Skip to main content
Endpoint Reference

POST /public/v1/orgs/:orgId/entities/:entityId/webhooks

Subscribe to one or more event topics. Returns the subscription row and a one-time signing_secret.

Reference

Method: POST Path: /public/v1/orgs/:orgId/entities/:entityId/webhooks Auth: Bearer marketplace token Tenant guard: :orgId and :entityId MUST match the install scope Required scope: none beyond a valid install Rate limit: standard

Request body

{
  "topics": ["invoice.paid", "bill.created"],
  "target_url": "https://your-app.example.com/hellobooks/webhook"
}
FieldTypeRequiredValidation
topicsstring[]yesAt least one element. Each is lowercased server-side.
target_urlstringyesMust start with https://. HTTP is rejected with 400.

Response (201)

{
  "id": "65f1aa...",
  "topics": ["invoice.paid", "bill.created"],
  "target_url": "https://your-app.example.com/hellobooks/webhook",
  "signing_secret": "shhh-this-is-shown-once-base64",
  "created_at": "2026-05-04T10:14:32.123Z"
}

⚠️ signing_secret is the plaintext secret. It is bcrypt-hashed server-side and never returned again. Store it immediately and treat it like a password.

Errors

HTTPerrorWhen
400invalid_requesttopics[] empty/missing, or target_url not HTTPS
401invalid_tokenStandard auth failures
401invalid_installInstall Status is not active
403tenant_scope_violationURL params don't match install scope

Curl example

curl -s -X POST \
  -H "Authorization: Bearer $HB_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "topics": ["invoice.paid"],
    "target_url": "https://your-app.example.com/hellobooks/webhook"
  }' \
  https://api.hellobooks.com/public/v1/orgs/$HB_ORG/entities/$HB_ENT/webhooks | jq
    API Reference: Create Webhook Subscription