Create a webhook
Create a webhook endpoint. Requires webhooks:write in the space named by X-Space-Id or org-webhooks:write, checked before the body is read; the body's level then decides which of the two applies. The secret is returned once in the response. Max 20 webhooks per org.
/api/webhooksCookie session from Better Auth. Requires X-Org-Id header for org-scoped routes.
In: cookie
Header Parameters
Organization ID. Required for cookie auth. Not needed for API key auth (org resolved from key).
uuidSpace ID. Required for space-scoped routes (agents, runs, schedules, and space-scoped module routes). Not needed for API key auth (space resolved from key).
Unique key for idempotent requests (max 255 chars). Prevents duplicate resource creation on retries. Cached for 24 hours, scoped to the organization and space: a repeat with the same method, URL and body replays the original response with Idempotent-Replayed: true, the same key with a different method, URL or body is 422 idempotency_conflict, and a concurrent duplicate is 409 idempotency_in_progress. Current permissions are checked again; run responses are projected using current visibility. This operation honours the header because it declares this parameter — operations that do not declare it refuse the header with 400 idempotency_not_supported rather than silently ignoring it (see the “Idempotency” section of the API description).
length <= 255Request Body
application/json
curl -X POST "https://your-instance/api/webhooks" \ -H "Content-Type: application/json" \ -d '{ "level": "org", "url": "https://api.example.com/webhooks/appstrate", "events": [ "run.success", "run.failed" ], "payloadMode": "summary", "enabled": true }'{
"id": "wh_cm1abc123",
"object": "webhook",
"level": "space",
"spaceId": "spc_8a3b6d9f-1e42-4c07-b5d8-6f0a2c4e8b13",
"url": "https://example.com/webhooks/appstrate",
"events": [
"run.success",
"run.failed"
],
"packageId": null,
"payloadMode": "full",
"enabled": true,
"createdAt": "2026-01-15T10:30:00Z",
"updatedAt": "2026-01-15T10:30:00Z",
"secret": "whsec_k3x9m2pq7r4t1w6y0a5d8g"
}{
"type": "https://docs.appstrate.dev/errors/validation-failed",
"title": "Validation Failed",
"status": 400,
"detail": "name: Invalid input: expected string, received undefined (+2 more)",
"code": "validation_failed",
"request_id": "req_abc123",
"errors": [
{
"field": "name",
"code": "required",
"message": "Invalid input: expected string, received undefined"
},
{
"field": "email",
"code": "invalid_format",
"message": "Invalid email address"
},
{
"field": "age",
"code": "invalid_type",
"message": "Invalid input: expected number, received string"
}
]
}{
"type": "https://docs.appstrate.dev/errors/unauthorized",
"title": "Unauthorized",
"status": 401,
"detail": "Invalid or missing session",
"code": "unauthorized",
"request_id": "req_abc123"
}{
"type": "https://docs.appstrate.dev/errors/forbidden",
"title": "Forbidden",
"status": 403,
"detail": "Insufficient permissions",
"code": "forbidden",
"request_id": "req_abc123"
}{
"type": "https://docs.appstrate.dev/errors/not-found",
"title": "Not Found",
"status": 404,
"detail": "Resource not found",
"code": "not_found",
"request_id": "req_abc123"
}{
"type": "https://docs.appstrate.dev/errors/idempotency-in-progress",
"title": "Idempotency In Progress",
"status": 409,
"detail": "A request with the same Idempotency-Key is already being processed. Please wait and retry.",
"code": "idempotency_in_progress",
"request_id": "req_abc123"
}{
"type": "https://docs.appstrate.dev/errors/idempotency-conflict",
"title": "Idempotency Conflict",
"status": 422,
"detail": "This Idempotency-Key was already used with a different method, URL or body. Use a new key for different requests.",
"code": "idempotency_conflict",
"request_id": "req_abc123"
}{
"type": "https://docs.appstrate.dev/errors/rate-limited",
"title": "Rate Limited",
"status": 429,
"detail": "Too many requests. Please try again shortly.",
"code": "rate_limited",
"request_id": "req_abc123",
"retry_after": 30
}