# Receiving New Data

Sail never expects you to poll for the current status, every piece of new or changed data is signaled by a webhook instead. New data shows up in one of two ways, a periodic automatic refresh or a refresh you trigger yourself. This page covers both, plus what you need to handle on every delivery.

Every webhook delivery is a POST to your configured endpoint, carrying one JSON envelope. Setting up that endpoint is a manual process today, the same as getting an API key, you send Sail your endpoint URL, and Sail sends back your webhook secret.

```json
{
  "id": "evt_7f3k9m",
  "event": "expense.created",
  "created_at": "2026-08-02T14:31:07Z",
  "user_id": "usr_abc123",
  "data": { "expense_id": "exp_9f2c", "connection_id": "conn_4d81" }
}
```

The `data` field carries ids only, never PII. Treat every event as "something changed, go look," not as a state transfer, fetch the resource by id for its current state instead of trusting the payload as the full picture.

## How new data shows up

Sail syncs a connection's data in one of two ways:

* **Periodic automatic refresh** happens on a cadence configurable per customer.
* **On-demand refresh** happens when you trigger a sync yourself through [Force Refresh](/reference/connections/post-users-user-id-connections-connection-id-refresh), which returns `202` and a `job_id` while the sync runs asynchronously.

Either way, you find out it's done through a `connection.synced` webhook, which names which kinds of data moved (`balances_updated`, `activity_updated`, `expenses_updated`) so you know what to go pull.

{/* PENDING: the historical backfill window on a connection's first sync is unconfirmed. Jonah said "two years" on the kickoff call, then self-corrected to "15 months, I think." See [[01-historical-lookback-window]], still open. Don't state a specific number here until resolved. */}

## Events by resource

Full per-event payload shapes live in [Webhook Events](/docs/api-reference/webhook-events). The table below groups each event by the resource it applies to.

| Resource | Events |
| :--- | :--- |
| Connections | `connection.created`, `connection.status_changed`, `connection.synced`, `connection.deleted` |
| Accounts | `account.created` |
| Expenses | `expense.created`, `expense.updated`, `transactions.ingested` |
| Receipts | `receipt.uploaded`, `receipt.processed`, `receipt.failed` |
| Connect Account Widget | `hosted_session.expired` |
| Users | `user.deleted` |

## What every delivery requires of you

Verify the `Sail-Signature` header (`t=<unix_ts>,v1=<hex>`, an HMAC-SHA256 of the timestamp and raw body using your webhook secret) before processing a delivery, and reject anything outside a 5-minute timestamp tolerance. Delivery is at-least-once with no ordering guarantee, so deduplicate on the event's `id` rather than assuming each event arrives once or in order. A failed delivery retries with exponential backoff for up to 24 hours, after which Sail stops retrying.

## Next steps

* To register a webhook endpoint, see [Set Up Webhooks](/docs/get-started/get-started-overview/webhooks).
* To look up the full event catalog and payload shapes, see [Webhook Events](/docs/api-reference/webhook-events).