# Webhooks

## What are webhooks?

A webhook (also called a web callback or HTTP push API) is a method to provide external applications with real-time information about data changes in a platform.

A webhook delivers data to the application at the moment that there is a change, resulting in data being pushed.
Unlike REST APIs where the application polls the API at regular intervals in order to get the changed data.
This makes webhooks much more efficient for both providers and consumers.

This guide will give more context and webhooks and get you up and running with the configuration in Unify.
We bundled this in the following sections:

- [Pull versus Push](#pull-versus-push)
- [Virtual Webhooks](#virtual-webhooks)
- [How to subscribe to webhook events?](#how-to-subscribe-to-webhook-events)
- [How to activate webhook events for integrations?](#how-to-activate-webhook-events-for-integrations)
- [Vault connection events and their payloads](#vault-connection-events-and-their-payloads)

Learn more about [what's a webhook](https://blog.apideck.com/what-is-a-webhook) on our blog.

## Pull versus Push

Pull via polling and Push via webhooks are two different techniques that can be used to retrieve data from an API.
Polling involves periodically sending requests to the API to check for new data, while webhooks involve registering a callback URL with the API and receiving notifications when new data is available.

Typically when you integrate with an API, you need to pull data from it. This means that you make a request to the API to get the data you need. This is called a pull integration.
To act on changes, you need to monitor the API for changes and pull the data when it changes.

A webhook is a way to receive update events being pushed instead of polling continuously for updates.

You can use webhooks to subscribe to certain events when they occur.
When an event occurs that matches your webhook subscription, a POST HTTP request will be sent to your webhook URL.

### When to use webhooks and when to poll?

In general, polling is recommended when the data being retrieved is not time-sensitive and does not need to be received immediately. Polling is also useful when the frequency of data updates is not known in advance, as it allows you to control the rate at which you retrieve data from the API.

Webhooks, on the other hand, are recommended when the data being retrieved is time-sensitive and needs to be received as soon as possible. Webhooks are also useful when the frequency of data updates is known in advance, as they allow the API to send notifications to your callback URL as soon as new data is available.

_Use Webhooks when_:
If you need updated data in real-time or updates are not very frequent, webhooks are the perfect solution.
Webhooks are also more resource-efficient as you only get notified when an event has happened.

_Use Polling when_:
You don't need updates in real-time and the updates are very frequent
You need to get the latest data from the API, even if there are no updates
example: Every 1 hour, refresh the number of users.

The use cases for webhooks are endless.
We have listed some of the most common use cases in our blog post [Apideck: What is a webhook?](https://blog.apideck.com/what-is-a-webhook).

[//]: # 'Webhooks and APIs make a perfect team. Webhooks are great for real-time updates, while APIs are great for retrieving data.'

## Virtual Webhooks

![Missing native webhooks](/guides/webhooks/virtual-webhooks-connector.png)

Some APIs don’t natively support webhooks. To prevent you from building data polling infrastructure, we’re introducing Virtualized Webhooks to let our partners receive Webhook events about changes by polling API endpoints as part of the Unify platform.

![Virtual webhooks](/guides/webhooks/virtual-webhooks.png)

Our proprietary polling engine monitors for changes in records inside APIs and notifies you about changes via unified webhook events, enabling new use cases and powerful features like bi-directional sync.

The Unify platform will handle all the sync & polling complexity ( like pagination, automatic retries, rate limits, change tracking, ...) for our partner.

This all happens without storing data on our end. Keeping sustainability and computing resources in mind.

## How to subscribe to webhook events?

There are 2 ways to subscribe to Unify events:

- Via the Apideck Admin
- Via the Apideck Webhook subscription API

### Via the Apideck admin

1. Goto Configuration > Webhooks section or [https://platform.apideck.com/webhooks](https://platform.apideck.com/webhooks)

Here you can manage existing webhook subscriptions.

![Unify admin - manage webhooks](/guides/webhooks/webhook-admin.png)

To create a new Webhook subscription, click the “Add Webhook”

![Unify admin - Register webhook subscription](/guides/webhooks/webhook-subscription.png)

Enter the delivery URL of the webhook endpoint from your system, and select the Unify API to be able to select the desired events you want to receive webhook events for.

The delivery URL will be validated upon creation, and it is expected to respond with an HTTP 200 status code to the POST request initiated by Unify. You can find more information about [how the webhook delivery URL validation works here](https://help.apideck.com/en/articles/4232258).

The validation request or event will contain a header `x-apideck-event-type: apideck.subscription.created` and request body structured as follows:

`{"message":"Validating delivery URL"}`

After you pressed “Create”, you are subscribed to the Unify Webhook events.

### Via the Apideck Webhook subscription API

By using the Webhook API, you can manage Webhook subscriptions

Visit: [https://developers.apideck.com/apis/webhook/reference#tag/Webhooks](https://developers.apideck.com/apis/webhook/reference#tag/Webhooks) to find all the details on what data is needed or use our [API explorer](https://developers.apideck.com/apis/webhook/api-explorer)

![Developer Docs - Webhooks API](/guides/webhooks/webhook-docs.png)

## How to activate webhook events for integrations?

For Unify to forward any webhook events for your integrations, the integration needs to support webhook events and it is necessary to register a Unify endpoint to receive their webhook events.

For integrations that support subscription management via their API, Apideck will try to auto-register the subscription.

For integrations, that do not support auto-registration Webhooks, it is needed that you, or the customer, activating the integration, have to enter the Unify endpoint in the web portal of the integration.

For example Quickbooks:

![Example - QuickBooks webhooks activation](/guides/webhooks/webhook-activation-1.png)

At the bottom of the connector configuration, you can find the unique Unify endpoint that is needed to be copied and pasted into your webhooks settings in QuickBooks.

Once this is done, Unify can receive the Webhooks events from the integration (Quickbooks in this example) and converts them to Unify events and push them to the delivery endpoint that you configured when registering webhooks in Unify.

## Vault connection events and their payloads

Alongside events from the Unified APIs (new invoice, updated employee, ...), Vault emits its own events whenever something changes about a **connection** itself, rather than the data behind it. Subscribe to these the same way as any other event, [via the Apideck admin or the Webhook subscription API](#how-to-subscribe-to-webhook-events), by selecting the **Vault API** and picking the event you need.

Every Vault connection event delivers the same shape: the full [Connection resource](https://developers.apideck.com/apis/vault/reference#tag/Connections/operation/connectionsOne) as `entity`, plus an `entityType` of `Connection`:

```json
{
  "entity": {
    "id": "accounting+quickbooks",
    "application_id": "dSBdXd2H6Mqwfg0atXHXYcysLJE9qyn1VwBtXHX",
    "consumer_id": "test_consumer_id",
    "service_id": "quickbooks",
    "unified_api": "accounting",
    "auth_type": "oauth2",
    "state": "callable",
    "health": "ok",
    "enabled": true,
    "settings": {},
    "metadata": {},
    "created_at": "2021-09-10T10:39:49.628Z",
    "updated_at": "2021-09-10T10:39:52.715Z"
  },
  "entityType": "Connection"
}
```

Which event you get, and which field on that same payload is the signal to act on, depends on what changed:

- **`vault.connection.callable`** — fires the moment a connection transitions from any other state to `callable`: OAuth scopes were granted (or, for non-OAuth connectors, the entered credentials were validated). Good place to kick off an initial sync.
- **`vault.connection.updated`** — a general-purpose event that fires whenever any connection data changes as a result of a Vault-driven action (adding/updating credentials, an OAuth callback, importing a connection, updating settings). Its payload includes the connection's current `state`, so this is also how you find out a connection became `invalid`, not a dedicated `vault.connection.invalid` event. See the [multi-company accounting guide](/guides/multi-company-accounting#reading-metadatacompany_id) for using this event to detect an organization change via `metadata.company_id`.
- **`vault.connection.disabled`** — fires when a connection's `enabled` property changes from `true` to `false`.
- **`vault.connection.revoked`** — fires when OAuth access is explicitly revoked and that revocation is confirmed at the integration's side.
- **`vault.connection.token_refresh.pending`** — an *early warning*, not a failure signal: Vault refreshes OAuth tokens proactively and retries roughly every 15 minutes if an attempt fails. This fires on the first failed attempt, while the connection stays `callable` and `health` reads `pending_refresh` for up to 48 hours as Vault keeps retrying.
- **`vault.connection.token_refresh.failed`** — the *terminal* event: fires only once that 48-hour retry window elapses with no successful refresh, at which point credentials are cleared and the connection is no longer callable. Don't treat `token_refresh.pending` as a precursor you can ignore until this fires — by design it can be up to 48 hours later. See the [Migrating Integrations guide](/guides/migrating-integrations#webhooks) for how to enable this event.
- **`vault.connection.downstream.degraded`** / **`vault.connection.downstream.recovered`** — a connection can stay `callable` while the integration itself is temporarily unreachable; these two events cover that separately from `state`.

>
> One case isn't covered by any event above: a request to the integration comes back unauthorized even though the stored credentials didn't look expired or invalid locally, for example access was revoked earlier than its recorded expiry, or the connector uses static (non-OAuth) credentials with no refresh cycle at all. Vault still marks the connection `invalid`, but that specific path doesn't emit a webhook and, since it isn't part of the token-refresh retry cycle, won't self-correct either. Calling [`validateConnectionState`](https://developers.apideck.com/apis/vault/reference#operation/validateConnectionState) yourself forces a fresh check; otherwise, treat a 401/unauthorized response from your own Unified API or Proxy calls as the signal for this specific case.

For the full connection lifecycle these events move through, and what each `state` and `health` value means, see [Reacting to state changes without polling](/guides/connection-states#reacting-to-state-changes-without-polling) in the Vault Connection States guide.
