> This page is for version 2023-04-25.
> For other versions, use one of these documentation indexes:
> - 2025-09-18 (default): https://apidocs.polytomic.com/2025-09-18/llms.txt
> - 2024-02-08: https://apidocs.polytomic.com/2024-02-08/llms.txt
> - 2023-04-25: https://apidocs.polytomic.com/2023-04-25/llms.txt

> 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.

Events are a way of being notified of important actions happening within an organization. For example, Polytomic will create a sync.completed event any time a sync finishes. These events are accessible via the events API. We also offer the ability to set up outgoing webhooks which will send realtime events as they happen.

Polytomic is designed for at most once delivery, which means we may fail to send some events. Additionally, events cannot be re-sent once they have been delivered. Therefore, if your use case demands a high level of assurance that all changes to a resource are processed without any missing events, we advise building a fallback polling system that periodically fetches the desired events using the events endpoint.

#### Retention

\


> **Note**
>
> Events accessible via the events endpoint are persisted for 48 hours, after which they will not be available.

## Event Types

Each event type has its own page with the conditions that fire it, its
fields, and an example payload.

* Model Sync: [`sync.running`](/2023-04-25/events/types/sync-running), [`sync.failed`](/2023-04-25/events/types/sync-failed), [`sync.canceled`](/2023-04-25/events/types/sync-canceled), [`sync.completed`](/2023-04-25/events/types/sync-completed), [`sync.completed_with_errors`](/2023-04-25/events/types/sync-completed-with-errors)
* Bulk Sync: [`bulk_sync.running`](/2023-04-25/events/types/bulk-sync-running), [`bulk_sync.completed`](/2023-04-25/events/types/bulk-sync-completed), [`bulk_sync.canceled`](/2023-04-25/events/types/bulk-sync-canceled), [`bulk_sync.failed`](/2023-04-25/events/types/bulk-sync-failed), [`bulk_sync.completed_with_errors`](/2023-04-25/events/types/bulk-sync-completed-with-errors)
* Ingestion: [`ingestion.stalled`](/2023-04-25/events/types/ingestion-stalled), [`ingestion.recovered`](/2023-04-25/events/types/ingestion-recovered)

## Webhooks

Webooks can be set up using the webhook API endpoints. Each webhook will fire events for the organization in which it exists. Currently, only one webhook per organization is allowed.

## HMAC Validation

HMAC validation can be used to ensure the events you receive are legitimate. When creating or updating a webook, there's a required `secret` field. Polytomic will hash each message and include a `Polytomic-Signature` header in each POST using that secret. You can use the `secret` field to validate that the signature matches.

## Delivery

We require that the endpoint returns a `2xx` response code. If a `2xx` is not returned, the event will be retried 5 times with exponential backoff. There are no guarantees around ordering.

## Record logs

The [`sync.completed`](/2023-04-25/events/types/sync-completed) event includes `logs_url`, the
endpoint that returns an index of the record logs the execution produced.

## Consuming Events

Below is a brief example (written in Go) of consuming events from a webhook:

```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")
}
```