Update a webhook endpoint
enabled: false switches it off (deliveries not yet made then fail); enabled: true switches it back on, also after the platform switched it off, and forgets its earlier failures. rotateSecret: true makes a new signing secret, answered once as secret; the old one keeps signing for 24 hours.
PATCH
/v1/webhooks/{id}Request
| Method and path | PATCH/v1/webhooks/{id} |
|---|---|
| Base URL | https://api.boxline.dev |
| Authentication | Your API key in the x-api-key header (or Authorization: Bearer). The examples read it from BOXLINE_API_KEY. |
| Rate limit | Yes. See Rate limits for the numbers and headers. |
Path parameters
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
idrequired | string | – | – |
Body
JSON with content-type: application/json. Required.
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
url | string | – | – | Up to 2048 characters. Format: uri. |
events | string[] | – | – | 1 to 100 items. |
enabled | boolean | – | – | |
description | string | null | – | – | Up to 200 characters. |
rotateSecret | boolean | – | – | Make a new signing secret, shown once in this answer; the old one keeps signing for 24 hours. |
curl -X PATCH "https://api.boxline.dev/v1/webhooks/$WEBHOOK_ID" \ -H "x-api-key: $BOXLINE_API_KEY" \ -H "content-type: application/json" \ -d '{ "events": ["session.stopped", "agent_run.finished", "crawl.finished"], "enabled": true }'import { Boxline } from "@boxline/sdk";const bx = new Boxline(); // reads BOXLINE_API_KEY and BOXLINE_API_URLconst w = await bx.webhooks.update("WEBHOOK_ID", { events: ["session.stopped", "agent_run.finished", "crawl.finished"], enabled: true,});console.log(w.enabled, w.events);// A new signing secret: store the new secret now; the old one signs for 24 more hours.const rotated = await bx.webhooks.update("WEBHOOK_ID", { rotateSecret: true });console.log(rotated.previousSecretExpiresAt); // verifyWebhook(body, header, [rotated.secret, oldSecret])from boxline import Boxlinebx = Boxline() # reads BOXLINE_API_KEY and BOXLINE_API_URLw = bx.webhooks.update("WEBHOOK_ID", events=["session.stopped", "agent_run.finished", "crawl.finished"], enabled=True,)print(w["enabled"], w["events"])# A new signing secret: store the new secret now; the old one signs for 24 more hours.rotated = bx.webhooks.update("WEBHOOK_ID", rotate_secret=True)print(rotated["previousSecretExpiresAt"]) # verify_webhook(body, header, [rotated["secret"], old_secret])Responses
200 OK
The endpoint now.
Fields
| Name | Type | Default | Allowed values | Description |
|---|---|---|---|---|
id | string | – | – | |
url | string | – | – | Format: uri. |
events | string[] | – | – | The types it gets, or ["*"] for all of them. |
description | string | null | – | – | |
enabled | boolean | – | – | |
disabledReason | string | null | – | user, gone, failing, account_recovered, null | user: switched off with PATCH; gone: it answered 410; failing: 3 days of failed deliveries; account_recovered: a password reset recovered an account whose email was not confirmed. null while enabled. |
disabledAt | string | null | – | – | Format: date-time. |
failingSince | string | null | – | – | The first failed delivery since the last success. Format: date-time. |
lastSuccessAt | string | null | – | – | Format: date-time. |
lastFailureAt | string | null | – | – | Format: date-time. |
secretRotatedAt | string | null | – | – | Format: date-time. |
previousSecretExpiresAt | string | null | – | – | Until then deliveries are signed with the secret before the last rotation too. Format: date-time. |
pausedUntil | string | null | – | – | Deliveries wait until then because the endpoint timed out 3 times in a row (test events still go). Format: date-time. |
createdAt | string | – | – | Format: date-time. |
updatedAt | string | – | – | Format: date-time. |
{ "id": "wh_Hk2Lq8Zx0Vb5Nm1C", "url": "https://example.com/", "events": [ "session.started" ], "description": "…", "enabled": false, "disabledReason": "user", "disabledAt": "2026-09-29T10:00:00.000Z", "failingSince": "2026-09-29T10:00:00.000Z", "lastSuccessAt": "2026-09-29T10:00:00.000Z", "lastFailureAt": "2026-09-29T10:00:00.000Z", "secretRotatedAt": "2026-09-29T10:00:00.000Z", "previousSecretExpiresAt": "2026-09-29T10:00:00.000Z", "pausedUntil": "2026-09-29T10:00:00.000Z", "createdAt": "2026-09-29T10:00:00.000Z", "updatedAt": "2026-09-29T10:00:00.000Z"}Errors
Errors have a matching HTTP status and the same body. code is stable, so check it in your code; message is for people. See Errors and request ids.
| Status | Codes | When |
|---|---|---|
| 400 Bad Request | invalid_request, invalid_json, invalid_cursor, invalid_idempotency_key, invalid_extension, variables_with_extensions, terms_not_accepted, invalid_reset_token, invalid_confirmation_code, wrong_password, no_password, invalid_next, invalid_oauth_token | The request is not valid. |
| 401 Unauthorized | unauthorized | Missing or invalid API key. |
| 404 Not Found | not_found, invite_not_found, provider_unavailable | No such thing in this project (or organization), or no such route. |
| 429 Too Many Requests | rate_limited, concurrency_limit | Too many requests, or the organization's concurrent sessions (its plan's) or the project's concurrencyCap are in use. |
{ "error": { "code": "not_found", "message": "session not found", "requestId": "req_4fJx0aQm2Lk9Pz7N" }}Learn more
These docs describe a beta API. Endpoints, fields and SDK methods may change before general availability; breaking changes will be listed in the changelog.