> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bindbee.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate from Webhooks Version 1

> Move a version 1 webhook to version 2 without missing an event.

Version 1 webhooks (`2025.01.01`) will be deprecated on December 31, 2026. A webhook's version is fixed when it is created, so migrating means creating a version 2 webhook, running it alongside the old one on the same URL, and then turning the old one off.

<Info>
  **Before you start**

  * You can deploy changes to the handler behind each version 1 webhook.
  * You have your signing secret - see [Verify webhook signatures](/guides/webhooks/verify-signatures).
</Info>

## Steps

<Steps>
  <Step title="Find your version 1 webhooks">
    Go to **[Webhooks](https://app.bindbee.dev/webhooks)**. Each webhook in the list carries a version chip, and version 1 webhooks show **v1**.

    From the API, [List Webhooks](/api-reference/webhooks/list-webhooks) returns a `version` for each one, `2025.01.01` for version 1.

    **Result:** A list of the webhooks to migrate, with the events each one subscribes to.
  </Step>

  <Step title="Choose the version 2 events">
    Replace each version 1 event with its version 2 equivalents - see [Map the events](#map-the-events). Where a version 1 webhook took `connector_data_modified`, pick the models your handler reads.

    Two version 1 webhooks on the same URL, one for Production and one for Development, become a single version 2 webhook covering both.

    **Result:** The event list for each new webhook.
  </Step>

  <Step title="Teach your handler to accept both versions">
    Route each request on the `X-BINDBEE-WEBHOOK-VERSION` header and verify it with the signature for its version: the [legacy signature](/guides/webhooks/verify-signatures#verify-the-legacy-signature) for version 1, `webhook-signature` for version 2. Keep processing version 1 as today, and parse version 2 but only log it for now.

    ```python theme={null}
    version = request.headers.get("X-Bindbee-Webhook-Version")

    if version == "2025.01.01":
        verify_legacy_signature(...)   # as today
        handle_v1(body)                # unchanged
    else:
        event = webhook.verify(raw_body, headers)   # webhook-signature
        log_v2(event)                  # parse and record, don't act yet
    return "", 200
    ```

    The header isn't signed, so verify on both branches. Map each version 1 field you read to its version 2 equivalent - see [Map the payload](#map-the-payload).

    **Result:** Your handler accepts version 2 requests without acting on them.
  </Step>

  <Step title="Create the version 2 webhook">
    Create a webhook on **Version 2** with the same URL, the environments and the events you chose - see [Create a webhook](/guides/webhooks/create-a-webhook). A URL can be registered once per version, so the two coexist.

    **Result:** Each event now reaches your URL twice, once in each version's shape.
  </Step>

  <Step title="Switch processing to version 2">
    Compare the logged version 2 events with what version 1 processed over a few syncs. When they agree, deploy the handler with the branches swapped: act on version 2, and answer version 1 with `200` without processing it.

    **Result:** Your application runs on version 2 events, and version 1 is acknowledged and ignored.
  </Step>

  <Step title="Turn off the version 1 webhook">
    Switch **Enable** off on the version 1 webhook. Once you're confident nothing depends on it, open its **Settings** and click **Delete webhook**.

    **Result:** Only the version 2 webhook delivers to your URL.
  </Step>
</Steps>

## Map the events

| Version 1 | Version 2 |
| - | - |
| `connector_sync_started` | `connector.sync.started` |
| `connector_synced` | `connector.sync.completed` |
| `connector_sync_error` | `connector.sync.failed`. Add `connector.relink_needed` to catch credential failures separately |
| `employee_data_changed` | `hris.employee.created` and `hris.employee.updated` |
| `connector_data_modified` | `<category>.<model>.created` and `<category>.<model>.updated` for each model you read. The version 1 key `hris_employment` becomes `hris.employment.created` and `hris.employment.updated` |
| - | `connector.linked` and `connector.relinked`, new in version 2 |

Every version 2 event is listed on [Webhook events](/guides/webhooks/events).

## Map the payload

Version 2 adds `id`, `event`, `version`, `sequence`, `occurred_at` and, on data events, `model` at the top level of the body. The `webhook` object is unchanged. The rest maps like this:

| Version 1 | Version 2 |
| - | - |
| `connector.id` | `connector.id` |
| `connector.display_name` | `connector.integration.name` |
| `connector.integration_slug` | `connector.integration.slug` |
| `connector.categories`, an array | `connector.category`, a string |
| `connector.origin_id` | `connector.origin_id` |
| `connector.connector_status` | `connector.connector_status` |
| `connector.end_user_name` | `connector.name` |
| `connector.org_name` | Removed. It was your own organization's name |
| `connector.end_user_email` | Removed |
| `connector.is_test_connector` | `connector.environment`, `production` or `development` |
| `data` on sync events | Unchanged |
| `data` on `employee_data_changed`, an array of employee IDs | `data` on `hris.employee.created` and `hris.employee.updated`, an array of IDs |
| `data` on `connector_data_modified`, an object keyed by table name | One event per model, each with `data` as an array of IDs |
| `sync` | Unchanged. Absent on `connector.linked` and `connector.relinked` |
| `error` | Unchanged |

Full version 2 bodies are on [Webhook payload](/guides/webhooks/payload#sample-payloads).

## What already changed for version 1

These changes shipped with version 2 and apply to version 1 webhooks too, whether or not you migrate:

* **Retries.** Deliveries are retried only on `408`, `429`, a `5xx` or a network failure, up to 4 attempts over about 7 seconds of waiting. Any other `4xx` is final - see [Delivery and retries](/guides/webhooks/delivery).
* **A version header.** Every delivery carries `X-BINDBEE-WEBHOOK-VERSION: 2025.01.01`. The body is unchanged.
* **Event order.** `connector_synced` now arrives after the sync's `employee_data_changed` and `connector_data_modified`, rather than before them.

## Frequently Asked Questions

<AccordionGroup>
  <Accordion title="Can I change an existing webhook's version instead?">
    No. A version 2 webhook is always a new webhook with a new `webhook_id`. Update anything that stores the old ID, such as a delivery-log filter.
  </Accordion>

  <Accordion title="Do I need a new signing secret?">
    No. One secret signs every webhook in your organization, on both versions.
  </Accordion>

  <Accordion title="My handler processes every event twice during the overlap">
    Both webhooks deliver each event, so a handler acting on both versions
    duplicates work. Act on one version at a time, as in the steps above. Version
    2's `id` can't collapse the two, since version 1 bodies don't carry it.
  </Accordion>

  <Accordion title="Creating the version 2 webhook fails with a duplicate name">
    Names are unique across your organization, on both versions. Give the new
    webhook a different name, for example with a `v2` suffix.
  </Accordion>

  <Accordion title="I relied on version 1 reporting employee changes as one event">
    `employee_data_changed` combined new and changed employees. Subscribe to both `hris.employee.created` and `hris.employee.updated` and send them to the same code path for the same behavior.
  </Accordion>
</AccordionGroup>

## Related

* [Webhooks](/guides/webhooks/overview) - what version 2 changes, and why
* [Webhook payload](/guides/webhooks/payload) - the version 2 body in full
* [Verify webhook signatures](/guides/webhooks/verify-signatures) - the version 2 signature and the legacy one
* [Delivery and retries](/guides/webhooks/delivery) - retry behavior for both versions


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.