# Webhooks
URL: https://www.quiltt.dev/webhooks
Description: Learn how to set up and manage Quiltt webhooks for real-time data updates. Subscribe to events like Profile creation and Connection syncs.
Content Length: 7k characters

Webhooks enable you to subscribe to changes to your data in Quiltt, without having to poll for updates.

For example, you can be notified when a Connection is synced or enters an error state, or when an Account is verified for money movement operations.

## How It Works

When a subscribed event occurs, Quiltt will send a **POST** request to your registered `targetUrl`, with a JSON payload containing the event types and events that triggered the webhook. This allows you to execute actions in your system based on changes in Quiltt.

## Event Types

Below are some of the events you can subscribe to:

| Type                                      | Description                                                                                                                                             |
| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `profile.created`                         | A Profile has been created.                                                                                                                             |
| `connection.synced.successful`            | A Connection has synced successfully. Automatically subscribes to any `connection.synced.successful.*` events.                                          |
| `connection.synced.successful.initial`    | A Connection has synced the initial data.                                                                                                               |
| `connection.synced.successful.historical` | Historical data has been synced after a successful Connector session. This event fires after both initial connections and Reconnect flows.              |
| `connection.synced.errored.repairable`    | A Connection has entered an error that must be resolved using the [**Reconnect** flow](/connector/reconnect).                                           |
| `account.verified`                        | An Account has been successfully verified and ACH numbers are now available via the [Account Numbers API](/api-reference/rest#tag/Account-Numbers). |

Each event payload will return information about the relevant data model and associated Profile. For example, the `connection.created` event will include information about the created Connection, along with the associated Profile.

See the [Webhooks Schema reference](/webhooks/schemas) for the full list of event types and object schemas.

## Webhook Payload

The webhook payload will include a list of `eventTypes` and a list of `events` that occured. Each event is structured as an object with an `id`, `at`, `type`, `profile` and `record` attributes. Certain event types also provide an optional `metadata` attribute.

Here's an example payload for a `connection.synced.successful` event:

```json
{
  "environment": ["id": "env_12uGLpOocVGvQYY9sFsOC6",
    "mode": "PRODUCTION",
    "metadata": null],
  "eventTypes": ["connection.synced.successful"],
  "events": [
    {
      "id": "evt_12sDfIGkY96vVvNvTqNfn9",
      "at": "2025-09-03T18:33:03Z",
      "type": "connection.synced.successful",
      "profile": {
        "id": "p_12uGLpPexyTkZCcJJntSjb",
        "uuid": "018a72f8-5434-7262-a029-a186fb0c5f33",
        "metadata": ["my_internal_user_id": "12345"]
      },
      "record": ["id": "conn_12uGLpQUjSjdQqpIYoEVdQ",
        "provider": "MX",
        "products": ["ACCOUNT_BALANCES_AND_TRANSACTIONS"],
        "status": "SYNCED",
        "metadata": null,
        "at": "2025-09-03T18:33:03Z"],
      "metadata": ["startDate": "2025-06-03",
        "endDate": "2025-09-03"]
    }
  ]
}
```

Warning:
A single webhook payload can contain more than one event. Quiltt batches events that occur
close together, so the `events` array often holds several events and can hold many at once.
Always iterate over `events` and branch on each event's `type`.

## Handling Events

Your endpoint must return a `2xx` HTTP response code within **20 seconds** to confirm successful receipt. Connection establishment must complete within **10 seconds**; otherwise, the webhook attempt will fail.

If your endpoint does not return a `2xx` response, Quiltt will automatically queue the delivery for retry. On `PRODUCTION` environments, Quiltt will make up to **20 delivery attempts** using exponential backoff.

### Event Handling Recommendations

To ensure robust webhook processing, we recommend implementing these patterns in your webhook handler:

#### 1. Event Deduplication

Since Quiltt may retry webhook deliveries, always check if you've already processed an event to prevent duplicate operations:

```javascript
if (processedEvents.has(event.id)) [return; // Skip processing - already handled]
processedEvents.add(event.id);
```

#### 2. Flexible Event Matching

Use prefix matching to handle related event types together, especially for `connection.synced.successful.*` events:

```js
// Match all successful sync events
if (event.type.startsWith("connection.synced.successful")) [processConnectionSync(event);]
```

#### 3. Date Range Handling

For events that include date metadata, use it to optimize your data synchronization:

```js
if (event.metadata.startDate && event.metadata.endDate) [// Re-scan transactions within the specified date range
  rescanTransactions(event.metadata.startDate, event.metadata.endDate);] else {
  // No specific date range - no transaction updates needed
  console.log(`Connection $[event.record.id] is up to date with Quiltt - no transaction updates needed!`);
}
```

## Webhook Verification

All Quiltt Webhooks are timestamped and signed with an HMAC256 signature, using a unique per-Subscription secret key. This allows you to verify that each message was issued by Quiltt, intended for your system, and has not been tampered with.

Info:
You can access your Subscription's secret key in the Quiltt Dashboard. This key should be stored securely and kept out of source control.

To verify the message is valid, check the headers of the incoming Webhook:

1. Ensure that the `Quiltt-Timestamp` header (Unix Epoch time) is within 5 minutes of current UTC time.
2. Validate that `Quiltt-Signature` header matches a Base64-encoded HMAC-SHA256 of `version+timestamp+payload`. The current version is `1`.

Warning:
Quiltt requires the raw body of the request to perform signature verification. If you’re using a framework like NestJs, make sure it doesn’t manipulate the raw body. Any manipulation to the raw body of the request causes the verification to fail.

Here's an example of how to construct and verify the signature in Ruby:

```rb
QUILTT_WEBHOOK_SECRET = '<QUILTT_WEBHOOK_SUBSCRIPTION_SECRET>'

timestamp = request.headers['Quiltt-Timestamp']
payload   = request.body.read
signature = OpenSSL::HMAC.base64digest(
  'SHA256', QUILTT_WEBHOOK_SECRET, "1#{timestamp}#{payload}"
)

raise "Verification failed" if request.headers['Quiltt-Signature'] != signature
```

See the [Setting up Webhook guide](/webhooks/setup#how-to-handle-incoming-events) for complete code examples.

## API Reference

See the Webhooks API Reference for full documentation of the subscription endpoints and the JSON payload we send to you.

Button Group:
[Webhooks API Reference]