Skip to main content
Webhooks require a Business tier subscription.

Overview

Borough webhooks deliver real-time notifications when listings change. Webhooks use the Standard Webhooks specification for payload signing and verification.

Event types

EventDescription
listing.createdA new listing appeared in the search index
listing.price_decreasedListing price dropped by more than $25
listing.price_increasedListing price increased by more than $25
listing.status_changedListing status changed (e.g., ACTIVE to IN_CONTRACT)
listing.expiredListing went off-market

Payload format

{
  "type": "listing.price_decreased",
  "data": {
    "listingId": "4961849",
    "oldValue": "5222",
    "newValue": "4900"
  },
  "timestamp": "2026-02-15T14:30:00Z"
}

Signature verification

Every webhook request includes three headers:
HeaderDescription
webhook-idUnique delivery ID
webhook-timestampUnix timestamp of signing
webhook-signaturev1,<base64-hmac-sha256>
The signature is computed as:
HMAC-SHA256(secret, "${webhook-id}.${webhook-timestamp}.${body}")

Verify with the SDK

import { webhookMiddleware } from '@borough/sdk/webhooks/express';

app.post('/webhooks/borough',
express.raw({ type: 'application/json' }),
webhookMiddleware(process.env.BOROUGH_WEBHOOK_SECRET, async (event) => {
console.log('Received:', event.type, event.data);
})
);

Retry schedule

Failed deliveries (non-2xx responses) are retried up to 7 times with increasing delays. After all retries are exhausted, the delivery is moved to a dead letter queue.

Managing subscriptions

Use the Webhook CRUD endpoints to create, list, update, and delete subscriptions.