- POST /api/v2/hooks — Subscribe a REST hook.
- DELETE /api/v2/hooks/{id} — Remove a REST hook.
POST /api/v2/hooks
Subscribe a REST hook.
The Zapier and Make apps’ subscription: a webhook endpoint of the Organisation that the calling credential owns, delivering the named events to target_url as every endpoint’s deliveries are signed and sent. Scope read and no run-as Administrator, but an Idempotency-Key as a write. The same source and target_url again answers 200 with that hook, its events replaced by the ones sent, when this credential holds it or the credential that did was deleted; held by another credential that still exists, it is 409 webhook_subscription_taken.
- Operation ID:
subscribeHook - Authentication: A Bearer token from a credential holding the
readscope.
curl -X POST "https://your-org.backed.giving/api/v2/hooks" \
-H "Authorization: Bearer $BACKED_TOKEN" \
-H "Idempotency-Key: 7d1f0c2e-5b8a-4f3e-9c61-2a4b8e9d0f13" \
-H "Content-Type: application/json" \
-d '{"events":["applications.funding_application.submitted"],"target_url":"https://hooks.example.com/zapier/4412/3f0c9d1e/","source":"zapier","label":"New submissions to the grants sheet"}'Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
Idempotency-Key | header | Yes | string | A key of 1 to 255 characters, unique per write. A retry with the same key, method, path and body within 24 hours answers the first response again (with Idempotent-Replayed: true) and writes nothing. Example: 7d1f0c2e-5b8a-4f3e-9c61-2a4b8e9d0f13. |
Request body
application/json, the HookCreate schema. A REST-hook subscription: events (catalogue event types) or event (one type), exactly one of the two; the public HTTPS target_url deliveries go to; the app subscribing; and an optional label for the endpoint’s description, cut to 200 characters (absent or blank, <Zapier|Make>: <first event>).
| Field | Type | Required | Notes |
|---|---|---|---|
events | array of string | No | |
event | string | No | |
target_url | string | Yes | |
source | string | Yes | One of zapier, make. |
label | string | No |
{
"events": [
"applications.funding_application.submitted"
],
"target_url": "https://hooks.example.com/zapier/4412/3f0c9d1e/",
"source": "zapier",
"label": "New submissions to the grants sheet"
}200 response
The existing hook for this source and target_url, its events replaced.
Headers: Idempotent-Replayed.
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | Yes | |
events | array of string | Yes | |
target_url | string | Yes | |
source | string | Yes | One of zapier, make. |
created_at | string | Yes |
{
"id": 4412,
"events": [
"applications.funding_application.submitted"
],
"target_url": "https://hooks.example.com/zapier/4412/3f0c9d1e/",
"source": "zapier",
"created_at": "2026-05-20T04:12:55.000Z"
}201 response
The new hook.
Headers: Idempotent-Replayed.
| Field | Type | Required | Notes |
|---|---|---|---|
id | integer | Yes | |
events | array of string | Yes | |
target_url | string | Yes | |
source | string | Yes | One of zapier, make. |
created_at | string | Yes |
{
"id": 4412,
"events": [
"applications.funding_application.submitted"
],
"target_url": "https://hooks.example.com/zapier/4412/3f0c9d1e/",
"source": "zapier",
"created_at": "2026-05-20T04:12:55.000Z"
}400 response
idempotency_key_required: The write has no Idempotency-Key header of 1 to 255 characters. invalid_request: A query parameter is invalid, or a write’s body is not a JSON object.
{
"error": "idempotency_key_required",
"error_description": "A write needs an Idempotency-Key header of 1 to 255 characters"
}{
"error": "invalid_request",
"error_description": "limit is invalid"
}401 response
The token is missing, invalid, expired or revoked, of another Organisation, or API access is not Full. Ask for a new token.
Headers: WWW-Authenticate.
{
"error": "invalid_token",
"error_description": "The access token is invalid or has expired"
}403 response
https_required: The request was sent over plain HTTP and was not processed. insufficient_scope: The credential does not hold the scope the route needs.
Headers: WWW-Authenticate.
{
"error": "https_required"
}{
"error": "insufficient_scope",
"error_description": "This credential lacks the write:applications scope"
}404 response
An unknown host or path, or an id that is unknown, deleted or of another Organisation.
{
"error": "not_found"
}409 response
idempotency_in_progress: The first request with this Idempotency-Key has not finished. Nothing was written; retry after the given seconds. webhook_subscription_taken: The target_url is subscribed under another API credential that still exists. Its hook is left as it is. webhook_subscription_busy: The target_url was being unsubscribed while this subscription ran, on every attempt. Nothing changed; send the request again.
Headers: Retry-After.
{
"error": "idempotency_in_progress",
"error_description": "The first request with this Idempotency-Key has not finished. If this persists it stopped part-way: check whether the record exists before writing again with a new key"
}{
"error": "webhook_subscription_taken",
"error_description": "This target_url is subscribed under another API Credential"
}{
"error": "webhook_subscription_busy",
"error_description": "This target_url is being unsubscribed; send the request again"
}413 response
The body, or the declared file, is larger than the limit that applies.
{
"error": "payload_too_large",
"error_description": "The request body is too large"
}415 response
The body is not application/json, or the target does not accept the file’s content type.
{
"error": "unsupported_media_type",
"error_description": "The request body must be application/json"
}422 response
idempotency_key_reused: The Idempotency-Key was used in the last 24 hours for a different method, path or body. unknown_field: The body has a property the route does not document; the first is named. validation_failed: Body values the product’s own form would refuse; fields names each. webhook_url_invalid: The hook’s target_url is not HTTPS, or resolves to a private, loopback or link-local address. webhook_event_unknown: An event type is not in the webhook event catalogue.
{
"error": "idempotency_key_reused",
"error_description": "This Idempotency-Key was used for a different request"
}{
"error": "unknown_field",
"error_description": "bank_account_number is not a writable field"
}{
"error": "validation_failed",
"error_description": "Invalid fields: due_date",
"fields": [
"due_date"
]
}{
"error": "webhook_url_invalid",
"error_description": "target_url must be a public HTTPS address: plain HTTP, private, loopback and link-local addresses are refused"
}{
"error": "webhook_event_unknown",
"error_description": "An event type is not in the webhook event catalogue"
}429 response
A rate limit was exceeded: 120 requests a minute per credential, 30 token requests a minute per client_id.
Headers: Retry-After.
{
"error": "rate_limited",
"error_description": "Too many requests"
}500 response
An unexpected server error.
{
"error": "server_error"
}503 response
The Organisation’s API access cannot be determined, or a dependency is unavailable. Retry after the given seconds.
Headers: Retry-After.
{
"error": "temporarily_unavailable"
}DELETE /api/v2/hooks/{id}
Remove a REST hook.
The calling credential’s own hook goes, with its deliveries. Another credential’s hook, an endpoint made on the Webhooks screen and an unknown id are 404. No body and no Idempotency-Key.
- Operation ID:
unsubscribeHook - Authentication: A Bearer token from a credential holding the
readscope.
curl -X DELETE "https://your-org.backed.giving/api/v2/hooks/42" \
-H "Authorization: Bearer $BACKED_TOKEN"Parameters
| Name | In | Required | Type | Description |
|---|---|---|---|---|
id | path | Yes | integer | The record id. Anything but a positive integer is 404. Example: 42. |
204 response
Removed.
401 response
The token is missing, invalid, expired or revoked, of another Organisation, or API access is not Full. Ask for a new token.
Headers: WWW-Authenticate.
{
"error": "invalid_token",
"error_description": "The access token is invalid or has expired"
}403 response
https_required: The request was sent over plain HTTP and was not processed. insufficient_scope: The credential does not hold the scope the route needs.
Headers: WWW-Authenticate.
{
"error": "https_required"
}{
"error": "insufficient_scope",
"error_description": "This credential lacks the write:applications scope"
}404 response
An unknown host or path, or an id that is unknown, deleted or of another Organisation.
{
"error": "not_found"
}429 response
A rate limit was exceeded: 120 requests a minute per credential, 30 token requests a minute per client_id.
Headers: Retry-After.
{
"error": "rate_limited",
"error_description": "Too many requests"
}500 response
An unexpected server error.
{
"error": "server_error"
}503 response
The Organisation’s API access cannot be determined, or a dependency is unavailable. Retry after the given seconds.
Headers: Retry-After.
{
"error": "temporarily_unavailable"
}