Receiving New Data
Learn why Sail signals new data through webhooks instead of polling, and the two ways new data actually shows up.
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 either through a periodic automatic refresh or through 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.
{
"id": "evt_7f3k9m",
"event": "receipt.uploaded",
"created_at": "2026-08-02T14:31:07Z",
"user_id": "usr_abc123",
"data": { "expense_id": "exp_9f2c" }
}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, which returns
202and ajob_idwhile 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.
Events by resource
Full per-event payload shapes live in 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 | expenses.213d_verified, 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.
- To look up the full event catalog and payload shapes, see Webhook Events.
Updated 14 days ago