Create a webhook subscription
Registers a new webhook endpoint to receive events.
The signing_secret is returned ONLY in this response — store it securely. If not provided in the request, the server generates a cryptographically random secret.
TENANT SCOPING: - Provide tenant_id in query to scope the subscription to a specific tenant. - Omit tenant_id to create a system-wide subscription (receives events from all tenants). - System-wide subscriptions still respect scope_filter if provided.
TENANT-OWNED CATEGORY BOUNDARY (NORMATIVE): the admin-write-path half of the cross-plane WEBHOOK SUBSCRIPTION INVARIANT 2 (info.description; part of the conformance surface). When the target subscription's owning tenant is a CONCRETE tenant (tenant_id present and != "system"), event_types and event_categories MUST satisfy the same tenant-accessible boundary the tenant self-service path enforces — budget.* / reservation.* / tenant.* types, and only the budget / reservation / tenant categories; an admin-only event type or category (api_key, policy, webhook, system) MUST be rejected with 400 INVALID_REQUEST. See createTenantWebhook (TENANT-ACCESSIBLE BOUNDARY) for the exact type/category sets — the same boundary applies here, on the admin write path, for tenant-owned targets. This holds regardless of auth context (admin key or admin-on-behalf-of): the constraint is a property of the owning tenant, not of the caller. Rationale: event_categories is ADDITIVE in delivery matching, and the owning tenant controls the delivery URL and signing secret of any subscription under its tenant_id, so an admin-only category on such a row would leak admin governance/security telemetry (api_key / policy / webhook / system events) to a tenant-controlled endpoint. When tenant_id is omitted or == "system", the subscription is NOT tenant-owned and admin-only categories remain permitted (system-wide admin monitoring is legitimate). Closes issue #209 at the admin write path (the previously ungoverned carrier of admin-only categories onto tenant-owned rows). To monitor admin-only events, create a system-owned subscription (omit tenant_id, or set tenant_id="system") — operator-owned (operator controls its URL + signing secret), so admin selectors are permitted — with event_types listing the admin event types you want (e.g. ["api_key.created","api_key.revoked"]); that satisfies the create-time event_types minItems:1 requirement directly and needs no event_categories. (For category-level matching you must create with at least one event_type first, then PATCH event_types to [] with event_categories set — the create/ update selector asymmetry of document revision 0.1.25.39.) The system subscription is in the dispatch union for every tenant, so it receives ALL tenants' admin events, which the operator filters to a specific tenant CLIENT-SIDE on the envelope tenant_id. Note: scope_filter CANNOT select a single tenant's admin telemetry server-side, because most admin lifecycle events are emitted with a null scope (api_key.*, webhook.*, and the system.* webhook-test event carry no scope; only policy.* carries a real tenant-bounded scope and could be scope-filtered). A tenant-OWNED subscription MUST NOT be used for this.
EVENTS (document revision 0.1.25.33): - On success, server MUST emit one webhook.created Event.
Payload conforms to EventDataWebhookLifecycle with
new_status = ACTIVE and previous_status omitted.
correlation_id = webhook_create:<subscription_id>.
AUTHORIZATION: - Requires admin key (X-Admin-API-Key)
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Scope subscription to a specific tenant. Omit for system-wide.
Request Body
Responses
Subscription created