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

# Bank Linking Webhooks

This page lists every webhook event Meld sends over the lifetime of a bank linking connection. For each event you'll see when it fires and what your application should do on receipt. For the end-to-end flow and the order webhooks arrive in, see [When is your data available?](/docs/bank-linking/get-connection-data/when-is-your-data-available).

<Note>Make sure your webhook endpoint is configured before triggering connections in production. See [Setting Up Webhooks](/docs/bank-linking/onboarding/step-5-setting-up-webhooks) for setup, authentication, and retry behavior.</Note>

## Attributes

All webhook events have the same attributes.

| Key         | Type           | Description                                                                          |
| :---------- | :------------- | :----------------------------------------------------------------------------------- |
| `eventType` | String         | Type of event                                                                        |
| `eventId`   | String         | Meld's unique identifier for the event                                               |
| `timestamp` | OffsetDateTime | The date and time the event was created                                              |
| `accountId` | String         | Account id                                                                           |
| `profileId` | String         | Id of the webhook profile responsible for this event to be sent                      |
| `version`   | Date           | API version of the payload                                                           |
| `payload`   | Object         | An object containing additional information of the event depending on the event type |

# Connection Webhooks

<Note>See the [API Reference](/api-reference/bank-linking) for the full payload schema of each connection webhook.</Note>

### `BANK_LINKING_CONNECTION_COMPLETED`

**When it fires:** Sent when the customer completes the connection with their institution either in the initial connect flow or a reconnect flow. This does not imply that financial account data has completed aggregating or is ready to be fetched, just that the customer has completed the widget flow.

**What to do:** Record that the customer finished the widget so you can update your UI. Wait for `BANK_LINKING_ACCOUNTS_UPDATED` before attempting to fetch product data.

The `BANK_LINKING_CONNECTION_STATUS_CHANGE` webhook will be sent in tandem with this one (with the `newStatus` being `ACTIVE`). However, if a connection goes from a broken state to `ACTIVE` without the user needing to reconnect (i.e. sometimes connections may break due to temporary institution unavailability but are eventually resolved on their own), then only `BANK_LINKING_CONNECTION_STATUS_CHANGE` will be issued containing both the old status and the new `ACTIVE` status. This is because `BANK_LINKING_CONNECTION_COMPLETED` is reserved solely for when the customer completes the widget flow.

```json theme={null}
{
  "eventType": "BANK_LINKING_CONNECTION_COMPLETED",
  "eventId": "NGoTSGJYpd3cLv1iyHWSw9",
  "timestamp": "2021-12-09T21:58:29.329186Z",
  "accountId": "QfdzpX3te1cDaviihXA4D5dA6ghnT3",
  "profileId": "W9kBgKB7afMxYoYuy3rJuZ",
  "version": "2021-10-28",
  "payload": {
    "requestId": "91d7fb355e319532b178acc8a7ae1a69",
    "customerId": "Qg56BnxskKokRV8rVo21Af3T4k6QKY",
    "externalCustomerId": "testCustomer1",
    "connectionId": "WQ4mBt3BEX2cmhCvSPyfTu",
    "institutionId": "Ntj3AwgdridJc2rtfeheku",
    "institutionName": "Chase",
    "serviceProviderDetails": {
      "serviceProvider": "PLAID",
      "serviceProviderConnectionId": "NXrZpLwd1eUQQqymvl9nSkkV8DpeLLUWoXdZx"
    }
  }
}
```

### `BANK_LINKING_CONNECTION_STATUS_CHANGE`

**When it fires:** Sent whenever a connection changes status. This webhook essentially encompasses all of the other connection status related webhooks and will be sent alongside them. Any service provider errors that occur post-completion will trigger this webhook as well, either due to an attempted aggregation failing or if the service provider notifies Meld via their own webhooks that a connection is in a broken state. This can happen when fetching products following an initial connection, or during daily/forced refreshes of existing connections.

**What to do:** This is the webhook to subscribe to for all connection-health tracking. Inspect `newStatus` and `newStatusReason` and route the customer to the [repair flow](/docs/bank-linking/manage-connection-status/repairing-connections) if the connection is now `RECONNECT_REQUIRED` or `CUSTOMER_ACTION_REQUIRED`. The `serviceProviderDetails` will provide additional information on what caused the connection to end up in such state. A list of potential reasons and actions to take for each of them can be found on the [Connection Statuses and Errors](/docs/bank-linking/get-connection-data/connection-statuses-and-errors) page.

<Tip>If a connection requires a reconnect, you can still request information (such as balances, transactions, etc.) about the connection and you will receive the data from the last time the connection was still operational.</Tip>

```json theme={null}
{
    "eventType": "BANK_LINKING_CONNECTION_STATUS_CHANGE",
    "eventId": "UhK4iqKP57FeLPgqBi8EUk",
    "timestamp": "2023-08-22T20:54:02.960285Z",
    "accountId": "W9ju7atKP5Jaf5RPweGeis",
    "profileId": "W9kBgKB7afMxYoYuy3rJuZ",
    "version": "2023-07-31",
    "payload": {
      "customerId": "WQ4KqLo3SRSPeTVjxxwo2o",
      "externalCustomerId": "20230822-67a",
      "connectionId": "WQ4KqLuBYYTYHi2YATXYdB",
      "institutionId": "W4AAAFPgUVB85QnQDu5xhU",
      "oldStatus": "ACTIVE",
      "oldStatusReason": null,
      "newStatus": "RECONNECT_REQUIRED",
      "newStatusReason": "LOGIN_REQUIRED",
      "activeDuplicateConnectionId": null,
      "serviceProviderDetails": {
        "environment": "sandbox",
        "error": {
          "error_type": "ITEM_ERROR",
          "error_code": "ITEM_LOGIN_REQUIRED",
          "error_message": "the login details of this item have changed (credentials, MFA, or required user action) and a user login is required to update this information. use Link's update mode to restore the item to a good state",
          "display_message": null,
          "request_id": null,
          "causes": null,
          "status": 400,
          "documentation_url": null,
          "suggested_action": null
        },
        "item_id": "NXrZpLwd1eUQQqymvl9nSkkV8DpeLLUWoXdZx",
        "serviceProvider": "PLAID",
        "serviceProviderConnectionId": "NXrZpLwd1eUQQqymvl9nSkkV8DpeLLUWoXdZx",
        "webhook_code": "ERROR",
        "webhook_type": "ITEM"
      }
    }
  }
```

# Financial Account Webhooks

<Note>See the [API Reference](/api-reference/bank-linking) for the full payload schema of each account webhook.</Note>

### `BANK_LINKING_ACCOUNTS_UPDATING`

**When it fires:** Sent once the connect flow is completed and the accounts are in the process of aggregating. At this time, only basic account info is available. Also sent during subsequent daily/forced refreshes when the accounts are in the process of aggregating again.

**What to do:** Treat this as a signal that aggregation has started — you can show a loading state but should not yet fetch product data. Wait for `BANK_LINKING_ACCOUNTS_UPDATED` before calling product endpoints.

*Financial Account fields for this event type:*

| Key                          | Type             | Description                                                                                                |
| :--------------------------- | :--------------- | :--------------------------------------------------------------------------------------------------------- |
| `financialAccounts`          | Array of objects |                                                                                                            |
|     `id`                     | String           | Unique identifier for the financial account                                                                |
|     `name`                   | String           | If present, the name of the account as provided by the institution.                                        |
|     `truncatedAccountNumber` | String           | If present, the last 4 digits of the account number, sometimes referred to as the account mask.            |
|     `newAccount`             | Boolean          | Indicates if the account was newly added or is an existing account getting updated (i.e. during a refresh) |

```json theme={null}
{
  "eventType": "BANK_LINKING_ACCOUNTS_UPDATING",
  "eventId": "38oVQntsutXnfzn6fZ3mxW",
  "timestamp": "2022-09-06T17:42:49.703620Z",
  "accountId": "W9ju7atKP5Jaf5RPweGeis",
  "profileId": "W9kBgKB7afMxYoYuy3rJuZ",
  "version": "2022-08-29",
  "payload": {
    "customerId": "WGti3bpsethEWYJrm2icuo",
    "externalCustomerId": "20220906-206",
    "connectionId": "WGu7we7dVTCnVkjJrpzVNm",
    "institutionId": "29KL1L2iYUV3zUCoSHhwvr",
    "requestId": "1f97b51f3771328bc07187c8a2c1fe30",
    "financialAccounts": [
      {
        "id": "WGti3dJFc6A9r1pYcBmE6e",
        "name": "Plaid Checking",
        "truncatedAccountNumber": "0000",
        "newAccount": true
      },
      {
        "id": "WGti3cCpeiAtWxL6pFQPTg",
        "name": "Plaid Saving",
        "truncatedAccountNumber": "1111",
        "newAccount": true
      }
    ],
    "serviceProviderDetails": {
      "serviceProvider": "PLAID",
      "serviceProviderConnectionId": "NXrZpLwd1eUQQqymvl9nSkkV8DpeLLUWoXdZx"
    }
  }
}
```

### `BANK_LINKING_ACCOUNTS_UPDATED`

**When it fires:** Sent once aggregation has completed for the accounts belonging to the connection. Products are now available to be fetched for the accounts. This webhook should arrive shortly after the `BANK_LINKING_ACCOUNTS_UPDATING` webhook, but sometimes products may take a while to aggregate for certain institutions. Note that if no products have been updated, then the `financialAccounts` object in this webhook will be empty.

**What to do:** Fetch the listed products for each financial account. See [Retrieving Connection Data](/docs/bank-linking/get-connection-data/retrieving-connection-data) and the per-account [aggregation overview](/docs/bank-linking/get-connection-data/when-is-your-data-available).

*Financial Account fields for this event type:*

| Key                 | Type             | Description                                                                                                                                                                                                                                                                                                                              |
| :------------------ | :--------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `financialAccounts` | Array of objects |                                                                                                                                                                                                                                                                                                                                          |
|     `id`            | String           | Unique identifier for the financial account                                                                                                                                                                                                                                                                                              |
|     `products`      | Array of Strings | The products that were updated for the account. This list will never include `TRANSACTIONS` because their updates are handled separately within the transactions webhooks. Products are considered updated even if nothing changed, and it is solely meant to indicate that the updated products were fetched from the service provider. |

```json theme={null}
{
  "eventType": "BANK_LINKING_ACCOUNTS_UPDATED",
  "eventId": "Ja2HXauns8LHPYR1NhEbrh",
  "timestamp": "2022-09-06T17:42:51.853020Z",
  "accountId": "W9ju7atKP5Jaf5RPweGeis",
  "profileId": "W9kBgKB7afMxYoYuy3rJuZ",
  "version": "2022-08-29",
  "payload": {
    "customerId": "WGti3bpsethEWYJrm2icuo",
    "externalCustomerId": "20220906-206",
    "connectionId": "WGu7we7dVTCnVkjJrpzVNm",
    "institutionId": "29KL1L2iYUV3zUCoSHhwvr",
    "requestId": "1f97b51f3771328bc07187c8a2c1fe30",
    "successfullyAggregatedAt": "2023-08-22T19:48:55Z",
    "financialAccounts": [
      {
        "id": "WGti3cCpeiAtWxL6pFQPTg",
        "products": [
          "BALANCES",
          "IDENTIFIERS",
          "OWNERS"
        ]
      },
      {
        "id": "WGti3dJFc6A9r1pYcBmE6e",
        "products": [
          "BALANCES",
          "IDENTIFIERS",
          "OWNERS"
        ]
      }
    ],
    "serviceProviderDetails": {
      "serviceProvider": "PLAID",
      "serviceProviderConnectionId": "NXrZpLwd1eUQQqymvl9nSkkV8DpeLLUWoXdZx"
    }
  }
}
```

### `BANK_LINKING_ACCOUNTS_REMOVED`

**When it fires:** Sent when individual financial accounts belonging to a connection have been deleted. This can occur when the customer revokes access to individual accounts or they close a financial account with their bank altogether. This webhook will always be issued following the `BANK_LINKING_CONNECTION_DELETED` event, as a connection deletion implies all of its financial accounts are deleted as well.

**What to do:** Remove the listed financial account IDs from your local data store and stop displaying them to the customer.

```json theme={null}
{
  "eventType": "BANK_LINKING_ACCOUNTS_REMOVED",
  "eventId": "GUVQ5N9tQpLFALKpRevt6C",
  "timestamp": "2021-12-09T19:09:23.283931Z",
  "accountId": "QfdzpX3te1cDaviihXA4D5dA6ghnT3",
  "profileId": "W9kBgKB7afMxYoYuy3rJuZ",
  "version": "2021-10-28",
  "payload": {
    "customerId": "WGuEzKYdKukkUFxmzVDUvm",
    "externalCustomerId": "20221031-34",
    "connectionId": "WGuEzMHgUFDzumu6zVRyw5",
    "institutionId": "W9kgBBLULSJFSKTwCpb5Gf",
    "financialAccounts": [
      {
        "id": "WGuEzL3AC3sF155f2ASWpu"
      },
      {
        "id": "WGuEzHzJzEiDTBhCcniN4D"
      },
      {
        "id": "WGuEzHoQA6UgG1Nq1qQ1Qy"
      },
      {
        "id": "WGuEzHswGCZCn2bS1N9Mkh"
      }
    ],
    "serviceProviderDetails": {
      "serviceProvider": "FINICITY",
      "serviceProviderConnectionId": "6026862732"
    }
  }
}
```

# Transaction Webhooks

<Note>See the [API Reference](/api-reference/bank-linking) for the full payload schema of each transaction webhook.</Note>

### `BANK_LINKING_TRANSACTIONS_AGGREGATED`

**When it fires:** Captures net transactional effects for each financial account belonging to the connection. Sent after each aggregation in which transactions are added or modified.

**What to do:** If you cache transactions locally, re-fetch the affected financial accounts using the `oldestTransactionUpdatedSearchKey` so you pick up new and updated transactions. See the [webhook flow](/docs/bank-linking/get-connection-data/when-is-your-data-available) for more details.

```json theme={null}
{
  "eventType": "BANK_LINKING_TRANSACTIONS_AGGREGATED",
  "eventId": "FEfSjVLXjM81CkG9ejkWBvu3Kb6ND5",
  "timestamp": "2022-01-31T22:05:04.068964Z",
  "accountId": "QfdzpX3te1cDaviihXA4D5dA6ghnT3",
  "version": "2022-03-09",
  "payload": {
    "customerId": "WGv8FTrTroky93FYwAJNXc",
    "externalCustomerId": "testCustomer",
    "connectionId": "WGumJ72d21SDCyma5Ax51k",
    "requestId": "1f97b51f3771328bc07187c8a2c1fe30",
    "successfullyAggregatedAt": "2023-08-22T19:48:55Z",
    "isPartial": false,
    "financialAccounts": [
     	{
        "financialAccountId": "WGv8FSGqrwvgVtqY5CARE9",
        "oldestTransactionUpdatedSearchKey": "3ztRY2PPYjEyzuuAfttKi9omi7UbsLxTbPTDV8MDpPhg9trwrsLZkHCJtb7QPs7cq35DJWSGqnRPP8UxGDmy2o2DRZJnG826oCuePdcnkAaCFyUEqc2QLeteoqJ3xBKetdApYwoFtA39ZpMxyL77LPxZEyUsWa4NWpxAEMQUHV9pSqZcgG",
        "numTransactionsAdded": 3,
        "numInvestmentTransactionsAdded": 0,
        "numTransactionsUpdated": 1,
        "numInvestmentTransactionsUpdated": 0,
        "transactionIdsRemoved": [],
        "investmentTransactionIdsRemoved": []
     	},
     	{
        "financialAccountId": "WGv8FSsWTrgAXBtS2cVPWR",
        "oldestTransactionUpdatedSearchKey": "3ztRY2PPYjEyzuuAfttKi9omi7UbsLxTbPTDV8MDpPhg9trwrsLZkHCJtb7QPs7cq35DJWSGqnRPP8UxGDmy2o2DRZJnG826oCuePdcnkAaCFyUEqc2QLeteoqJ3xBKetdApYwoFtA39ZpMxyL77LPxZEyUsWa4NWpxAEMQUHV9pSqZcgG",
        "numTransactionsAdded": 0,
        "numInvestmentTransactionsAdded": 0,
        "numTransactionsUpdated": 17,
        "numInvestmentTransactionsUpdated": 0,
        "transactionIdsRemoved": [],
        "investmentTransactionIdsRemoved": []
     	}
    ],
    "serviceProviderDetails": {
      "environment": "sandbox",
      "item_id": "zqyK7Abwv7cXJnr5Xk9xS31lMgqdXDuo3ZDxb",
      "new_transactions": 8,
      "serviceProvider": "PLAID",
      "webhook_code": "INITIAL_UPDATE",
      "webhook_type": "TRANSACTIONS"
    }
  }
}
```

### `BANK_LINKING_HISTORICAL_TRANSACTIONS_AGGREGATED`

**When it fires:** Captures net historical transaction effects for each financial account belonging to the connection. Sent at most once per connection after historical transactions (transactions older than 30 days) have been aggregated. By default, historical transaction aggregation is initiated after the connection is made.

**What to do:** Fetch the older transactions if your application surfaces extended history. Check `historicalAggregationSucceeded` per account — some institutions do not support extended history and will report `false` with an explanatory `historicalAggregationError`. See the [webhook flow](/docs/bank-linking/get-connection-data/when-is-your-data-available) for more details.

```json theme={null}
{
  "eventType": "BANK_LINKING_HISTORICAL_TRANSACTIONS_AGGREGATED",
  "eventId": "FEfSjVLXjM81CkG9ejkWBvu3Kb6ND5",
  "timestamp": "2022-01-31T22:05:04.068964Z",
  "accountId": "QfdzpX3te1cDaviihXA4D5dA6ghnT3",
  "version": "2022-03-09",
  "payload": {
    "customerId": "WGv8FTrTroky93FYwAJNXc",
    "externalCustomerId": "testCustomer",
    "connectionId": "WGumJ72d21SDCyma5Ax51k",
    "requestId": "1f97b51f3771328bc07187c8a2c1fe30",
    "successfullyAggregatedAt": "2023-08-22T19:48:55Z",
    "isPartial": false,
    "financialAccounts": [
     	{
        "financialAccountId": "WGv8FSGqrwvgVtqY5CARE9",
        "oldestTransactionUpdatedSearchKey": "3ztRY2PPYjEyzuuAfttKi9omi7UbsLxTbPTDV8MDpPhg9trwrsLZkHCJtb7QPs7cq35DJWSGqnRPP8UxGDmy2o2DRZJnG826oCuePdcnkAaCFyUEqc2QLeteoqJ3xBKetdApYwoFtA39ZpMxyL77LPxZEyUsWa4NWpxAEMQUHV9pSqZcgG",
        "numTransactionsAdded": 84,
        "numInvestmentTransactionsAdded": 0,
        "numTransactionsUpdated": 1,
        "numInvestmentTransactionsUpdated": 0,
        "transactionIdsRemoved": [],
        "investmentTransactionIdsRemoved": [],
        "historicalAggregationSucceeded": false,
        "historicalAggregationError": {
           "error": {
              "message": "Member's institution does not support extended transaction history.",
              "status": "bad_request",
              "type": "bad_request_error"
            },
            "serviceProvider": "MX"
         }
     	},
     	{
        "financialAccountId": "WGv8FSsWTrgAXBtS2cVPWR",
        "oldestTransactionUpdatedSearchKey": "3ztRY2PPYjEyzuuAfttKi9omi7UbsLxTbPTDV8MDpPhg9trwrsLZkHCJtb7QPs7cq35DJWSGqnRPP8UxGDmy2o2DRZJnG826oCuePdcnkAaCFyUEqc2QLeteoqJ3xBKetdApYwoFtA39ZpMxyL77LPxZEyUsWa4NWpxAEMQUHV9pSqZcgG",
        "numTransactionsAdded": 150,
        "numInvestmentTransactionsAdded": 0,
        "numTransactionsUpdated": 1,
        "numInvestmentTransactionsUpdated": 0,
        "transactionIdsRemoved": [],
        "investmentTransactionIdsRemoved": [],
        "historicalAggregationSucceeded": false,
        "historicalAggregationError": {
           "error": {
              "message": "Member's institution does not support extended transaction history.",
              "status": "bad_request",
              "type": "bad_request_error"
            },
            "serviceProvider": "MX"
         }
     	}
    ],
    "serviceProviderDetails": {
      "serviceProvider": "FINICITY",
      "serviceProviderConnectionId": "6026862732"
    }
  }
}
```
