---
title: "Webhooks and event delivery"
section: "Developer Platform"
canonical_url: "https://support.buildwithhq.com/api/webhooks.html"
reviewed_at: "2026-09-14"
authority: Official
---

# Webhooks and event delivery

Push signed application events to external systems with retries, idempotency, and observable delivery history.

## In brief

- **Scopes:** account | app
- **Default:** account
- **Transport:** Signed HTTPS POST

Webhooks are the outbound event surface of the developer platform. Instead of repeatedly polling the REST API, an integration registers an HTTPS destination and receives events when relevant application activity occurs.

## Choose a reachable destination

Set `destinationUrl` to a public HTTPS endpoint, at most 2048 characters, without a username, password, or fragment. Create and update requests reject private, loopback, link-local, multicast and reserved IP addresses, including IPv4 addresses written as IPv6. For example, `0.1.2.3`, `100.64.0.1`, `198.18.0.1` and `fd00::1` are not valid destinations. Use your public receiver URL instead.

An invalid destination returns HTTP 400 with correction guidance and a correlation ID. Hostname acceptance does not prove reachability: before each delivery the worker checks every resolved address and refuses the destination if any address is disallowed. Redirects are not followed. Correct an existing invalid subscription before retrying its deliveries.

[Open the Webhook Lab](https://webhooks.buildwithhq.com/) [Receiver and polling walkthrough](webhook-receiver-and-background-jobs.html) [Download Developer Kit 1.20.70](../downloads/BuildWithHQ-API43-Developer-Kit-1.20.70.zip)

## Choose the subscription scope

Set `scope` to `account` for records and activity belonging only to the credential's organization. Set it to `app` when the SaaS builder's trusted backend must synchronize customer organizations and users across the whole SaaS app. Existing subscriptions default to `account`; changing scope is explicit.

| Scope | Receives | Use it for |
| --- | --- | --- |
| `account` | Matching events for the credential's own customer organization. | Ordinary record and account-local integrations. This is the backward-compatible default. |
| `app` | The nine organization, user, membership, and invitation lifecycle events for every customer organization in the SaaS app. | A SaaS builder's controlled billing, CRM, identity, or onboarding backend. |

An app-scoped delivery still includes the customer `organizationId`. It does not give the receiver database access or permission to call APIs as that organization. App scope accepts only the nine lifecycle keys below; it cannot be paired with record events to bypass ordinary record scopes.

```
// Account-local record subscription (scope may be omitted)
{
  "displayName": "Account record sync",
  "destinationUrl": "https://hooks.example.com/records",
  "scope": "account",
  "events": [{ "eventKey": "record.updated", "eventVersion": "2026-08-01" }]
}

// App-wide customer lifecycle subscription
{
  "displayName": "Customer lifecycle sync",
  "destinationUrl": "https://hooks.example.com/lifecycle",
  "scope": "app",
  "events": [{ "eventKey": "organization.created", "eventVersion": "2026-09-14" }]
}
```

## Organization and user lifecycle events

| Event | Emitted when |
| --- | --- |
| `organization.created` | A customer organization is provisioned. |
| `organization.updated` | Name, billing email, status, or other published organization state changes, including reactivation. |
| `organization.deactivated` | The organization transitions to inactive. |
| `user.created` | A tenant user identity is created inside an organization. |
| `user.updated` | Published profile, type, owner, or active state changes, including reactivation. |
| `user.deactivated` | The user transitions to inactive. |
| `membership.created` | The user becomes a member of the organization. |
| `membership.role_changed` | User type, owner status, or DataRole assignments change. |
| `invitation.accepted` | A delivered invitation is consumed and linked to its accepted user. |

These events use version `2026-09-14` and are classified as sensitive because they can contain names or email addresses. Subscribe only a controlled backend and retain only the fields your billing, CRM, identity, or onboarding workflow needs.

## Event contract

Each delivery should have a stable event identifier, event type, schema version, occurrence time, application context, subject identifiers, and a data object. The event ID is the consumer's idempotency key.

```
{
  "id": "2a96f714-3653-4db4-bb63-7464bb5e4339",
  "type": "membership.role_changed",
  "version": "2026-09-14",
  "occurredAt": "2026-09-14T23:15:00Z",
  "appId": "7aa2...",
  "subject": {
    "type": "membership",
    "id": "e913..."
  },
  "actor": { "kind": "system" },
  "data": {
    "organizationId": "871c...",
    "userId": "e913...",
    "userTypeKey": "manager",
    "dataRoles": [{ "dataRoleId": 14 }]
  }
}
```

## Current management routes

```
GET  /v1/apps/{saasAppId}/webhook-event-types
GET  /v1/apps/{saasAppId}/webhooks
POST /v1/apps/{saasAppId}/webhooks
PUT  /v1/apps/{saasAppId}/webhooks/{subscriptionId}
POST /v1/apps/{saasAppId}/webhooks/{subscriptionId}/rotate-secret
GET  /v1/apps/{saasAppId}/webhook-deliveries
POST /v1/apps/{saasAppId}/webhook-deliveries/{deliveryId}/retry
```

## Receiving safely

1. Read the raw request body.
2. Verify the delivery signature and timestamp before trusting the JSON.
3. Reject payloads outside the replay window.
4. Use the event ID to make processing idempotent.
5. Return `2xx` quickly and do heavy work asynchronously.

Verify `X-BuildWithHQ-Timestamp` and `X-BuildWithHQ-Signature` over the exact bytes received. The signed value is `<timestamp>.<raw-body>`; the signature uses HMAC-SHA256 and is formatted as `v1=<lowercase-hex>`. Reject timestamps more than five minutes from your server clock. Delivery and event identifiers are also supplied in `X-BuildWithHQ-Delivery` and `X-BuildWithHQ-Event`.

## Delivery behavior

Lifecycle changes enter a transactional outbox with the database mutation, then the ordinary signed delivery worker promotes and delivers them. Multiple role writes inside one database transaction collapse to the final membership payload. Network failures still make delivery at-least-once rather than exactly-once: deduplicate by event ID and compare `occurredAt` or fetch current API state before applying an older event.

## Developer operations

The API exposes event discovery, subscription create/update, signing-secret rotation, bounded delivery evidence, and manual retry of eligible failed deliveries. Failed attempts retain safe status, duration, category, and bounded response evidence rather than unbounded remote bodies.

Note

Event keys and versions come from the event-type endpoint. Do not hard-code an event catalog copied from prose, and do not retry a delivery unless its current state is eligible for the explicit retry operation.

---

Capability review: 2026-09-14. [View the canonical guide](https://support.buildwithhq.com/api/webhooks.html).
