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/ATS 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.

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
    },
  })

  // We take the date of the current sync to save it later for the next sync
  // We do this to make sure no changes can be missed that might happen during
  // the sync itself.
  const syncStartDate = new Date() // This time should be in UTC
  const lastSyncStartDate = 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 ? lastSyncStartDate : 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)

  // We save the date of the last sync to use it in the next sync
  await prisma.customer.update({
    where: {
      id: customerId,
    },
    data: {
      last_synced_from_kombo_at: syncStartDate,
    },
  })
}