Skip to main content

Developers · Reference

Hooks

REST-hook subscriptions for the Zapier and Make apps. 2 operations: parameters, request body and answers, with examples.

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 read scope.
Example request
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

Parameters of POST /api/v2/hooks
NameInRequiredTypeDescription
Idempotency-KeyheaderYesstringA 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>).

Fields of the HookCreate body
FieldTypeRequiredNotes
eventsarray of stringNo
eventstringNo
target_urlstringYes
sourcestringYesOne of zapier, make.
labelstringNo
Example request body
{
  "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.

Fields of Hook
FieldTypeRequiredNotes
idintegerYes
eventsarray of stringYes
target_urlstringYes
sourcestringYesOne of zapier, make.
created_atstringYes
Example 200 response
{
  "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.

Fields of Hook
FieldTypeRequiredNotes
idintegerYes
eventsarray of stringYes
target_urlstringYes
sourcestringYesOne of zapier, make.
created_atstringYes
Example 201 response
{
  "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.

Example 400 response: idempotency_key_required
{
  "error": "idempotency_key_required",
  "error_description": "A write needs an Idempotency-Key header of 1 to 255 characters"
}
Example 400 response: invalid_request
{
  "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.

Example 401 response
{
  "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.

Example 403 response: https_required
{
  "error": "https_required"
}
Example 403 response: insufficient_scope
{
  "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.

Example 404 response
{
  "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.

Example 409 response: idempotency_in_progress
{
  "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"
}
Example 409 response: webhook_subscription_taken
{
  "error": "webhook_subscription_taken",
  "error_description": "This target_url is subscribed under another API Credential"
}
Example 409 response: webhook_subscription_busy
{
  "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.

Example 413 response
{
  "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.

Example 415 response
{
  "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.

Example 422 response: idempotency_key_reused
{
  "error": "idempotency_key_reused",
  "error_description": "This Idempotency-Key was used for a different request"
}
Example 422 response: unknown_field
{
  "error": "unknown_field",
  "error_description": "bank_account_number is not a writable field"
}
Example 422 response: validation_failed
{
  "error": "validation_failed",
  "error_description": "Invalid fields: due_date",
  "fields": [
    "due_date"
  ]
}
Example 422 response: webhook_url_invalid
{
  "error": "webhook_url_invalid",
  "error_description": "target_url must be a public HTTPS address: plain HTTP, private, loopback and link-local addresses are refused"
}
Example 422 response: webhook_event_unknown
{
  "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.

Example 429 response
{
  "error": "rate_limited",
  "error_description": "Too many requests"
}

500 response

An unexpected server error.

Example 500 response
{
  "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.

Example 503 response
{
  "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 read scope.
Example request
curl -X DELETE "https://your-org.backed.giving/api/v2/hooks/42" \
  -H "Authorization: Bearer $BACKED_TOKEN"

Parameters

Parameters of DELETE /api/v2/hooks/{id}
NameInRequiredTypeDescription
idpathYesintegerThe 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.

Example 401 response
{
  "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.

Example 403 response: https_required
{
  "error": "https_required"
}
Example 403 response: insufficient_scope
{
  "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.

Example 404 response
{
  "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.

Example 429 response
{
  "error": "rate_limited",
  "error_description": "Too many requests"
}

500 response

An unexpected server error.

Example 500 response
{
  "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.

Example 503 response
{
  "error": "temporarily_unavailable"
}