Real-time syncs with webhooks
Combine webhooks from external APIs with periodic polling for a reliable, real-time stream of changes.
Tenklo supports real-time syncs using webhook functions. You can rely entirely on webhooks or combine them with polling to ensure you never miss data.
What is a real-time sync
Real-time sync involves receiving webhooks from external APIs and processing them inside a sync function. By default, sync functions poll data at a set frequency, but they can also be configured to handle webhooks for real-time updates.
When processed in a sync:
- The webhook triggers the execution of a Tenklo sync script
- The script extracts data from the webhook and optionally fetches additional data from the external API
- The modified data is stored in the Tenklo cache
Whenever the cache is updated, Tenklo sends a sync completion webhook to notify your application of new data. This entire process happens in real-time.
Webhooks & periodic polling
Webhooks can fail due to external API outages or unordered events. Periodic polling ensures data consistency by reconciling any missed updates.
If you use webhooks for real-time syncs, we recommend always combining them with a polling sync function.
Near real-time syncing
As an alternative to real-time syncing, consider near-real-time syncing by polling at a higher frequency, which is simpler. Sync functions can run as frequently as every 30 seconds.
This is more resource intensive, but can be a good compromise if you are only syncing data for a handful of Connections.
Implement a real-time sync
Step 1 — Setup prerequisites
To create a real-time sync, you need:
- Webhooks from the external API enabled. Follow Webhook functions.
- A sync function for the object you want to sync. See Sync functions.
Step 2 — Enable webhooks processing
To enable the real-time sync, define webhookSubscriptions and onWebhook in your sync function:
export default createSync({
exec: async (nango) => {
// Use for periodic polling.
},
webhookSubscriptions: ['contact.propertyChange'], // Webhook event type to listen to
// Webhook handler
onWebhook: async (nango, payload) => {
if (payload.subscriptionType === 'contact.propertyChange') {
const updatedObject = {
id: payload.objectId,
[payload.propertyName]: payload.propertyValue
};
// Use nango.batchSave() or nango.batchUpdate() to save/update records.
}
}
});To check if a sync supports webhooks, navigate to the Integrations tab > select an integration > Endpoints sub-tab > check the function settings for webhook subscriptions.
Sync concurrency considerations
When a polling run and a webhook race to update the same record, the later write wins by default — which can clobber a fresher webhook update with stale polled data. To prevent that, set a merging strategy at the start of your function:
export default createSync({
exec: async (nango) => {
// Don't overwrite records that were modified after this batch was fetched
await nango.setMergingStrategy({ strategy: 'ignore_if_modified_after' }, 'Contact');
const contacts: Contact[] = [];
await nango.batchSave(contacts, 'Contact');
}
});Two strategies are available:
override(default) — applies updates regardless of last modification time. May overwrite real-time webhook updates with older polled data.ignore_if_modified_after— preserves records that were modified after the current batch was fetched. Recommended when you combine polling with webhooks.
Run batchSave / batchUpdate / batchDelete calls sequentially (not in parallel), and persist data promptly after fetching — concurrent batch operations can race against each other.
Related guides
- Webhook functions - process external API webhooks in Tenklo.
- Webhook forwarding - forward provider webhooks to your app.
- Sync functions - keep a polling sync as reconciliation.
- Webhooks from Tenklo - consume sync completion notifications.