This approach of syncing with Kombo is deprecated and will be removed in the future. For the modern approach, see Syncing Data. Also see Migrate to Data Changed for how to migrate to the new approach.

Syncing Data

To sync data from Kombo into your database, just call the endpoints you are interested in and handle the data on your side. To allow for faster syncs, we strongly recommend only fetching the changes that happened since the last sync. You don’t have to worry about missing changes on your side when following the approach outlined below.

Listen to Webhooks

Kombo provides webhooks to notify you when we finish a sync or receive a webhook about changes from the HRIS system. We are tracking any changes diligently on our side so you don’t have to worry about what kind of change happened. You can leverage those webhooks from Kombo to fetch any changes that happened since your last sync with Kombo. To implement this, create a webhook subscription for the sync-finished and remote-event-received webhooks on the webhook page. Learn how to use webhooks in development and how to authenticate them here.

React to webhooks

After receiving a webhook, you can use the integration_id in the body to fetch updated data from Kombo into your database. Do that by calling the endpoints you are interested in while providing the updated_after query parameter. This parameter is available for all Kombo GET endpoints. The endpoints are still paginated when using the updated after filter.
We recommend that you persist the timestamp of your last fetching process in your database and use that as the updated_after filter.
Important: Do NOT use the sync_started_at field from the webhook payload as your updated_after parameter. The sync_started_at represents when Kombo started syncing from the HRIS, not when you started fetching from Kombo. Using sync_started_at will cause you to miss data that was created/updated via webhooks before the sync started. Always track your own fetch timestamp as shown in the example below.
Here is an example of how this could be implemented in Node.js:
/**
 * @param {Object} options
 * @param {number} options.customerId Id of the customer in your database
 * @param {boolean} options.syncOnlyUpdates Specify if you want to sync deltas or full sync.
 * > It's recommended to run a full sync from time to time and updates if you want to receive changes.
 */
async function syncCustomer({
  customerId,
  syncOnlyUpdates,
}: {
  customerId: number
  syncOnlyUpdates: boolean
}) {
  // Assuming we are using prisma as our ORM
  const customer = await prisma.customer.findUniqueOrThrow({
    where: {
      id: customerId,
    },
    select: {
      last_synced_from_kombo_at: true,
      kombo_integration_id: true, // Also select the integration ID
    },
  })

  // IMPORTANT: We track when WE start fetching from Kombo (not when Kombo synced from the HRIS)
  // This ensures we don't miss any changes that happen between fetches
  const ourFetchStartTime = new Date() // This time should be in UTC
  const lastFetchStartTime = customer?.last_synced_from_kombo_at?.toISOString()

  let cursor
  do {
    const resp = await axios.get('https://api.kombo.dev/v1/hris/employees', {
      headers: {
        Authorization: `Bearer ${KOMBO_API_KEY}`,
        'X-Integration-Id': customer.kombo_integration_id ?? '', // Use the stored integration ID
      },
      params: {
        cursor: cursor,
        updated_after: syncOnlyUpdates ? lastFetchStartTime : undefined,
      },
    })

    cursor = resp.data.data.next

    // Implement your handling logic here
    // Usually, you will upsert the data into your database and build specific
    // domain logic here.
    await handleEmployeeData(resp.data.data.results)
  } while (cursor)

  // Save our fetch start time to use as updated_after in the next fetch
  await prisma.customer.update({
    where: {
      id: customerId,
    },
    data: {
      last_synced_from_kombo_at: ourFetchStartTime,
    },
  })
}