| Location | Name | Required | Meaning |
|---|---|---|---|
| header | X-Admin-CSRF | Yes | Session-bound token from the staff page; not a developer credential. |
{
"type": "object",
"properties": {
"url": {
"type": "string",
"minLength": 1,
"maxLength": 2000,
"description": "HTTPS endpoint passing the staff-hook URL safety checks."
},
"categories": {
"type": "array",
"items": {
"type": "string",
"enum": [
"security",
"access",
"user",
"retention",
"data_access"
]
},
"minItems": 1
}
},
"required": [
"url",
"categories"
],
"additionalProperties": false
}{error:{code,message}} for CloudError failures, attaches Request-Id, and disables caching. Handle 401 by signing in; show role refusal for 403 forbidden, reauthenticate only for step_up_required, and collect a reason for 400 reason_required. A CSRF failure needs a current page/session token, not blind retries. Operation-specific 404/409/413/422/502/503 errors retain their status. Honor Retry-After on 429./** POST /api/admin/hooks {url, categories} (hooks.manage, step-up): the secret is in the response once. Audited hooks.create. */
export const POST = adminRoute("hooks.manage", async (request, ctx) => adminJson(await createHook(ctx, await readBody(request, HOOK_BODY)), { status: 201 }));