> This page is for version 2024-02-08.
> 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 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](/2024-02-08/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

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

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

## 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`](/2024-02-08/guides/events/types/sync-completed) event includes `logs_url`, the
endpoint that returns an index of the record logs the execution produced.

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