# Guide to Bridge API Webhooks: Features and Best Practices

Bridge API webhooks notify your systems about open-banking activity: an item (bank connection) is refreshed, an account is created or updated, a payment transaction changes. If you're building on Bridge API's aggregation platform, webhooks are how you react to banking data changes without polling.

This guide covers how Bridge API webhooks work, the events you'll handle, how to verify the `BridgeApi-Signature`, secret rotation, and the best practices for production.

> This is Bridge API (bridgeapi.io), the open-banking aggregator by Bankin'/Bridge. It is a different company and API from bridge.xyz (the stablecoin platform), which has its own guide and a completely different (RSA) signature scheme. Make sure you're on the right one.

## What are Bridge API webhooks?

Bridge API webhooks are HTTP POSTs delivered to a callback URL you configure in the dashboard, each signed with an HMAC-SHA256. The `BridgeApi-Signature` header carries one or more scheme-prefixed values, for example `v1=E5637CDB...` (hex, uppercase). You verify the `v1=` value over the raw body with the webhook's signing secret.

## Bridge API webhook features

| Feature | Details |
| --- | --- |
| Configuration | Bridge dashboard (admins only): callback URL, name, events; max 10 webhooks per app |
| Signature header | `BridgeApi-Signature`, one or more `scheme=value` entries (e.g. `v1=<hex>`) |
| Signature scheme | HMAC-SHA256 over the raw body, hex uppercase; extract the `v1=` value |
| Secret | Auto-generated per webhook, shown once; 24h dual-secret window on rotation |
| Source IPs | `63.32.31.5`, `52.215.247.62`, `34.249.92.209` (use `X-Forwarded-For` behind a proxy) |
| Response | Keep response bodies under 10 KB |
| Retries | 1-2 days with exponential backoff on non-200/slow |
| SDK | None |

## Common events

Bridge API event names are lowercase `resource.action` (some three-segment):

| Event | Fires when |
| --- | --- |
| `item.refreshed` | An item (bank connection) is refreshed |
| `item.created` | An item is created |
| `item.account.created` | An account under an item is created |
| `item.account.updated` | An account under an item is updated |
| `payment.transaction.created` | A payment transaction is created |
| `user.deleted` | A user is deleted |

Note the three-segment `item.account.*` form. A "Send a test" button in the dashboard emits `TEST_EVENT`. Consult Bridge API's reference for the full list.

## Setting up Bridge API webhooks

Configure webhooks in the Bridge dashboard (admins only): callback URL, name, and selected events (max 10 webhooks per app). The signing secret is auto-generated and shown once at creation or rotation, capture it. Optionally allowlist the fixed source IPs (using `X-Forwarded-For` if you're behind a proxy), and keep your response bodies under 10 KB.

## Securing Bridge API webhooks

The `BridgeApi-Signature` header can hold multiple scheme-prefixed values. Extract the `v1=` value specifically (ignore other schemes, this guards against downgrade attacks), compute an HMAC-SHA256 with the webhook's signing secret over the raw body, hex-encode it (uppercase), and constant-time-compare. During rotation, up to two signatures may be present; accept a match against either.

```javascript
const crypto = require("crypto");

// One or two current secrets (24h overlap on rotation)
const SECRETS = (process.env.BRIDGEAPI_WEBHOOK_SECRETS || "").split(",");

function verify(rawBody, signatureHeader) {
  // Extract only the v1= signatures (ignore other schemes)
  const v1Sigs = (signatureHeader || "")
    .split(",")
    .map((s) => s.trim())
    .filter((s) => s.startsWith("v1="))
    .map((s) => s.slice("v1=".length));

  return SECRETS.some((secret) => {
    const expected = crypto
      .createHmac("sha256", secret)
      .update(rawBody)
      .digest("hex")
      .toUpperCase();
    return v1Sigs.some((sig) => {
      const a = Buffer.from(expected);
      const b = Buffer.from(sig.toUpperCase());
      return a.length === b.length && crypto.timingSafeEqual(a, b);
    });
  });
}

app.post("/webhook", express.raw({ type: "application/json" }), (req, res) => {
  if (!verify(req.body, req.headers["bridgeapi-signature"])) {
    return res.sendStatus(401);
  }

  res.sendStatus(200); // acknowledge fast
  processQueue.add(JSON.parse(req.body)); // process asynchronously
});

```

The same check in Python:

```python
import hashlib
import hmac
import os

SECRETS = os.environ.get("BRIDGEAPI_WEBHOOK_SECRETS", "").split(",")

def verify(raw_body: bytes, signature_header: str) -> bool:
    v1_sigs = [s.strip()[3:] for s in (signature_header or "").split(",") if s.strip().startswith("v1=")]
    for secret in SECRETS:
        expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest().upper()
        if any(hmac.compare_digest(expected, s.upper()) for s in v1_sigs):
            return True
    return False

```

## Bridge API webhook limitations and pain points

### Extract `v1=` to avoid downgrade

The Problem: The `BridgeApi-Signature` header can carry multiple scheme-prefixed values. Verifying whatever's first (or a weaker scheme) opens a downgrade attack.

Why It Happens: The header is designed to carry multiple schemes.

Workarounds:

* Extract the `v1=` value specifically and verify that; ignore other schemes.

How Hookdeck Can Help: Hookdeck verifies the correct scheme at the edge, so your app isn't exposed to downgrade.

### Uppercase hex and secret rotation

The Problem: The hex is uppercase, and rotation puts up to two active secrets/signatures in play for 24 hours. Lowercase comparison or checking only one secret fails valid deliveries.

Why It Happens: Bridge API uses uppercase hex and overlaps secrets on rotation.

Workarounds:

* Compare uppercase, and accept a match against either secret/signature during the 24h window.

How Hookdeck Can Help: Hookdeck handles rotation and encoding at the edge. See our [guide to webhook idempotency](/webhooks/guides/implement-webhook-idempotency).

### Events for already-deleted users/items

The Problem: You can receive webhooks for users or items that are already deleted. A handler that assumes the referenced resource still exists errors out.

Why It Happens: Delivery and deletion race; Bridge API delivers defensively.

Workarounds:

* Handle missing resources gracefully (treat a 404 on follow-up as expected).

How Hookdeck Can Help: Hookdeck durably queues events so you can process (or skip) them at your own pace.

### Source IPs and response size

The Problem: Deliveries come from fixed IPs (which you may need `X-Forwarded-For` to see behind a proxy), and responses must stay under 10 KB.

Why It Happens: Bridge API uses a fixed egress and caps response size.

Workarounds:

* Allowlist the IPs (via `X-Forwarded-For` behind a proxy) and keep responses small.

How Hookdeck Can Help: Hookdeck provides a stable ingestion URL and a compact acknowledgement, so IP and response-size handling are managed for you.

## Best practices

### Verify the `v1=` uppercase-hex signature over the raw body

Extract `v1=`, HMAC-SHA256 with the webhook secret over the raw body, uppercase hex, and compare in constant time. Accept either secret during rotation.

### Confirm you're on Bridge API, not bridge.xyz

They're different companies with different schemes (HMAC here, RSA there).

### Handle deleted resources and acknowledge fast

Treat missing users/items as expected, return 200 quickly, and process off a queue. See [why to process webhooks asynchronously](/webhooks/guides/why-implement-asynchronous-processing-webhooks).

### Allowlist IPs and keep responses small

Restrict to the fixed source IPs and keep response bodies under 10 KB.

## Conclusion

Bridge API (bridgeapi.io) webhooks are verified with a `BridgeApi-Signature` HMAC-SHA256 over the raw body, extracting the `v1=` uppercase-hex value (to prevent downgrade), with a 24-hour dual-secret rotation window and fixed source IPs. Verify the `v1=` value, handle rotation and already-deleted resources, and don't confuse this with bridge.xyz.

[Hookdeck](https://hookdeck.com) verifies the signature, handles rotation, deduplicates, and durably queues every event at the edge, so your app only ever processes verified, unique events.

[Get started with Hookdeck](https://dashboard.hookdeck.com/signup) for free and handle Bridge API webhooks reliably in minutes.