Skip to content
KnockDevelopers

Manage webhooks

Create, list, change, pause and delete webhooks with the API, set each webhook's secret token, test a URL, read event types and delivery stats, and handle every webhook error.

Chat with a Developer

You manage webhooks with the same API key you use for the rest of the Knock API. Create a webhook for each URL that should receive events, choose its event types, give it the secret token your receiver checks on each delivery, and send it a test ping. The overview lists every endpoint; this page covers each one in full.

Authenticate every call with your API key in the x-api-key header. To list and read webhooks, list event types and read delivery stats, use a key with the Admin, Editor, Viewer, CRM Admin or AI Manager role; an Enrichment API key can't. Everything else (creating, changing, pausing, pinging and deleting webhooks, testing a URL, and reading a secret token) needs a key with the Admin role. Admin keys carry full admin access, so keep them on your backend and out of the system that receives webhooks. See Authentication.

Every route is under https://app.knock-ai.com/v1/webhooks, the same host as the rest of the Knock API. Request bodies are JSON. Fields Knock doesn't know are ignored, so a typo in a field name is silently dropped: check the response.

Create a webhook

A webhook is one URL, the event types it receives and, optionally, a name and a secret token. While the webhook is active, Knock sends every event of those types to that URL.

Endpoint
POST https://app.knock-ai.com/v1/webhooks

Prop

Type

You can subscribe a webhook to meeting.booked, meeting.rescheduled and enrichment_request.completed (see the webhook events reference, or list them with the API). Any other value, webhook.ping included, gets 400 validation: Knock sends a ping only when you ask for one.

Terminal
curl -X POST https://app.knock-ai.com/v1/webhooks \
  -H "x-api-key: $KNOCK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "CRM sync",
    "url": "https://hooks.yourcompany.com/webhooks/knock",
    "events": ["meeting.booked", "meeting.rescheduled"]
  }'
201 Created
{
  "id": "1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35",
  "name": "CRM sync",
  "url": "https://hooks.yourcompany.com/webhooks/knock",
  "events": ["meeting.booked", "meeting.rescheduled"],
  "status": "active",
  "hasSecretToken": false,
  "createdAt": "2026-11-02T09:30:00.000Z"
}
FieldTypeDescription
idstring (UUID)ID of the webhook. Every delivery for it carries this value in the knock-webhook-id header.
namestring or nullThe label you gave the webhook. null when it has none.
urlstringThe URL Knock sends events to.
eventsstring[]The event types this webhook receives.
statusstringactive, or paused: Knock sends a paused webhook nothing until you set it back to active.
hasSecretTokenbooleanWhether the webhook has a secret token. The token itself is never returned with the webhook: read it separately.
createdAtstring (date-time)When the webhook was created, in UTC.

To have every delivery carry a secret token from the first one, add secretToken to the body (see Set the secret token). To check your endpoint before any event reaches it, test the URL before you create the webhook, or create it with "status": "paused", ping it, then resume it.

URL requirements

Knock checks the url when you create a webhook, change its URL or test a URL, and again before every delivery. When you send one that breaks a rule, Knock answers 422 webhooks.invalid-url and names the rule in metadata.reason:

Rulemetadata.reason when it's broken
A valid absolute URL, at most 2048 characters.notAUrl (an over-long URL gets 400 validation)
HTTPS.notHttps
On port 443. Any other port is rejected.explicitPort
Without credentials. A URL with a user name or password in it, such as https://user:pass@hooks.yourcompany.com/webhooks/knock, is rejected. Verify each delivery with the secret token instead.credentials
Public. localhost and similar host names are rejected.blockedHost
Every address the host resolves to is a public one, not a private, loopback or link-local address.nonPublicAddress
The host name resolves.unresolvable

To test an endpoint on your own machine, expose it through a public HTTPS tunnel.

Knock doesn't follow redirects, so use the final URL of your endpoint.

One URL per webhook

Your account can have only one webhook for each url. A second create with the same url gets 409 webhooks.already-exists, with the existing webhook's ID in metadata.webhookId: to add event types to that URL, change that webhook instead. A paused webhook keeps its url. Once you delete a webhook, its url is free again.

Knock compares URLs exactly as written, without normalizing them: https://hooks.yourcompany.com/webhooks/knock and https://hooks.yourcompany.com/webhooks/knock/ are two different URLs, so they can belong to two webhooks, and each one gets its own delivery of every event. Use the same spelling everywhere so you don't subscribe one endpoint twice.

The same event type can go to several URLs. Create one webhook per URL, each with that type in its events, and every one of them gets its own delivery of each event, with the same webhook-id. The knock-webhook-id header says which of your webhooks a delivery is for.

List your webhooks

Terminal
curl https://app.knock-ai.com/v1/webhooks \
  -H "x-api-key: $KNOCK_API_KEY"
200 OK
{
  "items": [
    {
      "id": "1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35",
      "name": "CRM sync",
      "url": "https://hooks.yourcompany.com/webhooks/knock",
      "events": ["meeting.booked", "meeting.rescheduled"],
      "status": "active",
      "hasSecretToken": true,
      "createdAt": "2026-11-02T09:30:00.000Z"
    },
    {
      "id": "6a2d8f4c-9e1b-4c7a-a3f5-0b8e2d6c1f47",
      "name": null,
      "url": "https://crm-sync.yourcompany.com/knock",
      "events": ["meeting.booked"],
      "status": "paused",
      "hasSecretToken": false,
      "createdAt": "2026-11-02T09:30:01.000Z"
    }
  ],
  "total": 2,
  "limit": 50,
  "offset": 0,
  "maxWebhooks": 50
}

Webhooks come oldest first, paused ones included, a page at a time. Each item has the same fields as the create response.

Query parameterDescription
eventOnly the webhooks that receive this event type.
limitWebhooks per page, 1 to 100. Default 50.
offsetNumber of webhooks to skip. Default 0.
FieldDescription
itemsThe webhooks of this page.
totalHow many webhooks match the query, across all pages.
limit, offsetThe page you got.
maxWebhooksThe most webhooks your account can have, paused ones included. It's the account limit, not the page size.

With the default limit of 50, one page holds every webhook your account can have. To list only the webhooks that receive one event type, add event:

Terminal
curl -G https://app.knock-ai.com/v1/webhooks \
  --data-urlencode "event=meeting.booked" \
  -H "x-api-key: $KNOCK_API_KEY"

An event value that isn't a subscribable event type, or a limit or offset out of range, gets 400 validation.

Get a webhook

Terminal
curl https://app.knock-ai.com/v1/webhooks/1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35 \
  -H "x-api-key: $KNOCK_API_KEY"
200 OK
{
  "id": "1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35",
  "name": "CRM sync",
  "url": "https://hooks.yourcompany.com/webhooks/knock",
  "events": ["meeting.booked", "meeting.rescheduled"],
  "status": "active",
  "hasSecretToken": true,
  "createdAt": "2026-11-02T09:30:00.000Z"
}

A webhook that doesn't exist, or that you deleted, gets 404 webhooks.not-found.

Change a webhook

PATCH /v1/webhooks/{webhookId} changes the webhook's name, url, events, status or secretToken, in one write. Send only the fields you change: a field you leave out keeps its value, and an empty body changes nothing and returns the webhook as it is. null is rejected with 400 validation, except for name and secretToken, where it removes the value.

Prop

Type

Terminal
curl -X PATCH https://app.knock-ai.com/v1/webhooks/1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35 \
  -H "x-api-key: $KNOCK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"events": ["meeting.booked", "meeting.rescheduled", "enrichment_request.completed"]}'
200 OK
{
  "id": "1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35",
  "name": "CRM sync",
  "url": "https://hooks.yourcompany.com/webhooks/knock",
  "events": ["meeting.booked", "meeting.rescheduled", "enrichment_request.completed"],
  "status": "active",
  "hasSecretToken": true,
  "createdAt": "2026-11-02T09:30:00.000Z"
}

The change applies from the next delivery attempt. Retries of earlier events go to the new url with the new secret token, and an event type you remove stops being sent, retries included. A url another of your webhooks already uses gets 409 webhooks.already-exists, and a url that breaks a rule gets 422 webhooks.invalid-url. A request Knock rejects changes nothing.

Pause and resume a webhook

To stop deliveries to a webhook without deleting it, set its status to paused:

Terminal
curl -X PATCH https://app.knock-ai.com/v1/webhooks/1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35 \
  -H "x-api-key: $KNOCK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status": "paused"}'

Knock answers 200 with the webhook, "status": "paused". Send {"status": "active"} to resume it.

  • Pausing stops deliveries to the webhook and drops every delivery not sent yet, retries included. Those deliveries are never sent, even after you resume the webhook, and they count as cancelled in delivery stats. A request already in flight when you pause still completes.
  • Resuming restarts deliveries for the events Knock records from then on. It doesn't replay the events of the pause, but an event from the pause that reaches Knock late can still be sent: its occurredAt shows when it happened.
  • A paused webhook keeps its URL and its secret token, and still counts toward the limit of 50. You can still ping it.
  • Pausing a paused webhook, or resuming an active one, changes nothing.

To create a webhook paused, send "status": "paused" in the create body.

Delete a webhook

Terminal
curl -X DELETE https://app.knock-ai.com/v1/webhooks/1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35 \
  -H "x-api-key: $KNOCK_API_KEY"
204 No Content
HTTP/1.1 204 No Content

Knock stops sending to the webhook at once, and retries already scheduled for it are cancelled. A webhook that doesn't exist, or that you already deleted, gets 404 webhooks.not-found. Deleting one webhook doesn't affect your other webhooks, even those for the same event types. Once a webhook is deleted, you can create a new one with its url. To stop deliveries but keep the webhook, pause it instead.

Test a webhook with a ping

POST /v1/webhooks/{webhookId}/ping sends a webhook.ping event to the webhook's URL right away, waits for your endpoint and tells you what happened. Use it after you create a webhook, after you deploy your receiver, and after you change the webhook's secret token.

Terminal
curl -X POST https://app.knock-ai.com/v1/webhooks/1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35/ping \
  -H "x-api-key: $KNOCK_API_KEY"
200 OK
{
  "eventId": "5e2b9c4a-7d1f-4a3e-8b6c-0f9d2e1a3c7b",
  "delivered": true,
  "statusCode": 200,
  "errorCode": null,
  "durationMs": 184,
  "retryAfterSeconds": 10
}
FieldTypeDescription
eventIdstring (UUID)ID of the ping event. Your endpoint received it as the webhook-id header and as id in the body. Search your logs for it.
deliveredbooleantrue when your endpoint answered with a 2xx status within 5 seconds.
statusCodeinteger or nullThe HTTP status your endpoint answered with. null when there was no HTTP response, for example a timeout or a connection error.
errorCodestring or nullWhy the ping wasn't delivered. null when delivered is true. The values are listed below.
durationMsintegerHow long the attempt took, in milliseconds.
retryAfterSecondsintegerSeconds before Knock accepts another ping of this webhook. 0 when you can send one now.
errorCodeMeaning
http_statusYour endpoint answered with a status other than 2xx or 3xx. statusCode has it.
redirectYour endpoint answered with a 3xx. Knock doesn't follow redirects.
timeoutNo response within 5 seconds.
connectionThe connection failed or was closed.
dnsThe host name didn't resolve.
tlsThe TLS handshake or the certificate check failed.
blocked_destinationThe host now resolves to an address that isn't public, so Knock didn't send the request.

The call answers 200 whether or not your endpoint accepted the ping: check delivered, and see What the result tells you when it's false. A ping waits 5 seconds for your endpoint, is never retried, doesn't affect deliveries of real events and isn't counted in delivery stats. You can ping each webhook once every 10 seconds, paused ones included; a second ping within 10 seconds gets 429 webhooks.ping-rate-limited, with the seconds to wait in the Retry-After header and in metadata.retryAfterSeconds. Each ping also counts toward the per-IP rate limit.

Your endpoint receives the ping like any other event, with the knock-webhook-token header when the webhook has a secret token. Answer it with any 2xx status; you don't need to act on it.

Test a URL

POST /v1/webhooks/test sends a webhook.ping event to a URL that has no webhook yet and tells you what your endpoint answered. Use it to check your receiver, and its token check, before you create the webhook.

Prop

Type

Terminal
curl -X POST https://app.knock-ai.com/v1/webhooks/test \
  -H "x-api-key: $KNOCK_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"url\": \"https://hooks.yourcompany.com/webhooks/knock\", \"secretToken\": \"$KNOCK_WEBHOOK_TOKEN\"}"
200 OK
{
  "eventId": "8d3f1a6c-2b4e-4f7a-9c5d-1e0b7a3f6c28",
  "delivered": true,
  "statusCode": 200,
  "errorCode": null,
  "durationMs": 201,
  "retryAfterSeconds": 10
}

The result has the same fields as a ping, except that retryAfterSeconds counts down to your account's next URL test.

  • The url and secretToken follow the same rules as on create: a URL that breaks one gets 422 webhooks.invalid-url, and a bad token gets 400 webhooks.invalid-secret-token.
  • No webhook exists yet, so the ping carries 00000000-0000-0000-0000-000000000000 as the webhook ID, in the knock-webhook-id header and in data.webhookId.
  • A test waits 5 seconds for your endpoint and is never retried. Knock doesn't record it, so it isn't counted in delivery stats and its eventId only helps you find the request in your own logs.
  • Your account can test a URL once every 10 seconds, whatever the URL. A second test within 10 seconds gets 429 webhooks.url-test-rate-limited, with the seconds to wait in the Retry-After header and in metadata.retryAfterSeconds. A test rejected for its URL or token doesn't use up the 10 seconds. Each test also counts toward the per-IP rate limit.

Secret token

Each webhook has one optional secret token: a value you choose, which Knock sends as is in the knock-webhook-token header of every delivery to that webhook. Your receiver compares the header with the value it expects. It's the only way to check that a delivery came from Knock: Knock adds no other proof to a delivery. Verify webhooks explains the check, rotation and what the token doesn't protect.

Knock never returns the token with the webhook: hasSecretToken says whether one is set, and reading it takes its own call. Setting, reading and removing it need an Admin key.

Treat it like a password

Anyone who holds your secret token can send requests your endpoint will accept. Keep it in a secrets manager, never in source code or logs.

Set the secret token

Send secretToken in the body of POST /v1/webhooks to set it on a new webhook, or with PATCH /v1/webhooks/{webhookId} to set or replace it on an existing one. From the next delivery attempt, every delivery to that webhook carries it in the knock-webhook-token header, exactly as you set it, retries of earlier events included.

The token is 1 to 256 characters, using only A-Z, a-z, 0-9, underscore (_) and hyphen (-). Pick a long random value, not a word or a phrase. All three examples below generate one that follows the rules and set it on a webhook:

Terminal
# 64 characters from 0-9 and a-f. Store this value in your secrets manager.
KNOCK_WEBHOOK_TOKEN=$(openssl rand -hex 32)

curl -X PATCH https://app.knock-ai.com/v1/webhooks/1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35 \
  -H "x-api-key: $KNOCK_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"secretToken\": \"$KNOCK_WEBHOOK_TOKEN\"}"
200 OK
{
  "id": "1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35",
  "name": "CRM sync",
  "url": "https://hooks.yourcompany.com/webhooks/knock",
  "events": ["meeting.booked", "meeting.rescheduled"],
  "status": "active",
  "hasSecretToken": true,
  "createdAt": "2026-11-02T09:30:00.000Z"
}

A token that is empty, longer than 256 characters, or contains any other character, such as a space, ., + or /, gets 400 webhooks.invalid-secret-token, and the webhook stays as it was. A secretToken that isn't a string gets 400 validation, and so does null on create.

A new token replaces the old one from the next delivery attempt, so follow Rotate the token to change it without rejecting any delivery.

Read the secret token

GET /v1/webhooks/{webhookId}/secret-token returns the webhook's token. It's a credential, so reading it needs an Admin key, like changing it.

Terminal
curl https://app.knock-ai.com/v1/webhooks/1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35/secret-token \
  -H "x-api-key: $KNOCK_API_KEY"
200 OK
{
  "secretToken": "fa0cb006958a09fd6a8b901706a54d39304e65914346d651bb860a09b5218c74"
}

secretToken is null when the webhook has none. Deliveries to it then have no knock-webhook-token header. A webhook that doesn't exist, or that you deleted, gets 404 webhooks.not-found.

Remove the secret token

Send null to stop sending the knock-webhook-token header to this webhook:

Terminal
curl -X PATCH https://app.knock-ai.com/v1/webhooks/1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35 \
  -H "x-api-key: $KNOCK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"secretToken": null}'

Knock answers 200 with the webhook, "hasSecretToken": false. Before you remove the token, make sure your receiver no longer requires the header, or it will reject every delivery to this webhook.

List event types

GET /v1/webhooks/event-types lists the event types a webhook can subscribe to, with what the webhook events reference publishes for each: a title, a description, the JSON Schema of the body Knock sends and an example.

Terminal
curl https://app.knock-ai.com/v1/webhooks/event-types \
  -H "x-api-key: $KNOCK_API_KEY"
200 OK
{
  "items": [
    {
      "type": "meeting.booked",
      "group": "Meetings",
      "title": "Meeting booked",
      "description": "A contact booked a meeting with your team through Knock.",
      "delivery": "retry",
      "schema": {
        "type": "object",
        "description": "The body of each `meeting.booked` delivery.",
        "required": ["id", "type", "apiVersion", "occurredAt", "data"],
        "properties": { "…": "…" },
        "$defs": { "MeetingData": { "…": "…" } }
      },
      "example": {
        "id": "0b4c7f9e-1d2a-4e3b-8c5d-6f7a8b9c0d1e",
        "type": "meeting.booked",
        "apiVersion": "2026-11-01",
        "occurredAt": "2026-11-02T12:00:05.000Z",
        "data": { "meetingId": "2e4f6a8c-0b1d-4c3e-9f5a-7b8c9d0e1f2a", "…": "…" }
      }
    },
    { "type": "meeting.rescheduled", "…": "…" },
    { "type": "enrichment_request.completed", "…": "…" }
  ]
}
FieldDescription
typeThe value to put in a webhook's events.
groupMeetings or Enrichment: a label to show related types together. Items come in display order, the types of each group together.
titleShort name of the type.
descriptionWhen Knock sends it, in one plain-text sentence.
deliveryretry: Knock retries a failed delivery for up to 72 hours.
schemaThe JSON Schema (2020-12) of the body Knock sends for this type, data included. The schemas it refers to are under $defs.
exampleAn example body of this type, valid against schema.

webhook.ping isn't listed, because no webhook can subscribe to it. Use the list to offer event types in your own product, or to validate the bodies your receiver gets.

Get delivery stats

GET /v1/webhooks/stats counts the delivery attempts of the last 24 hours or 3 days by UTC hour, for one webhook or every webhook of your account, with the success rate and how fast your endpoint answered.

Query parameterDescription
webhookIdOnly the deliveries to this webhook. Leave it out for every webhook of your account, including webhooks deleted within the window.
window24h (the default) or 3d.
Terminal
curl -G https://app.knock-ai.com/v1/webhooks/stats \
  --data-urlencode "webhookId=1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35" \
  --data-urlencode "window=24h" \
  -H "x-api-key: $KNOCK_API_KEY"
200 OK
{
  "window": "24h",
  "delivered": 980,
  "failed": 4,
  "retrying": 16,
  "cancelled": 0,
  "successRate": 0.9959,
  "latencyMs": { "p50": 250, "p95": 1000 },
  "series": [
    { "start": "2026-11-01T13:00:00.000Z", "delivered": 38, "failed": 0, "retrying": 1 },
    "…",
    { "start": "2026-11-02T12:00:00.000Z", "delivered": 41, "failed": 1, "retrying": 3 }
  ]
}
FieldDescription
windowThe window the numbers cover.
deliveredAttempts your endpoint accepted with a 2xx.
failedAttempts after which Knock gave up on the event: your endpoint rejected it for good (such as a 3xx, a 410 or another 4xx Knock doesn't retry), or it ran out of retries.
retryingFailed attempts Knock retries later, such as a 5xx, a timeout or a connection error.
cancelledDeliveries Knock dropped unsent because the webhook was paused, deleted or no longer subscribed to the event type.
successRatedelivered / (delivered + failed), from 0 to 1. null when both are 0.
latencyMsHow long your endpoint took to answer, in milliseconds: p50 and p95. null when Knock sent no request in the window.
seriesOne point per UTC hour, oldest first: 24 for 24h, 72 for 3d. Each point has start (the start of the hour), delivered, failed and retrying. Hours without attempts are zeros, and the last point is the current hour so far.
  • The numbers count attempts, not events: a retry counts in the hour it ran. Pings and URL tests aren't counted.
  • The numbers are up to about 60 seconds behind.
  • Each latency value is one of 50, 100, 250, 500, 1000, 2000 or 5000: Knock counts each request under the first of these bounds it fits. Anything slower, timeouts included, reports 5000.
  • A webhookId that doesn't exist, or that you deleted, gets 404 webhooks.not-found: a deleted webhook's attempts appear only in your account's totals. An invalid webhookId or window gets 400 validation.

Knock doesn't pause a webhook whose deliveries keep failing, and doesn't notify you, so watch failed and retrying here. See When deliveries keep failing.

Limits

LimitValue
Webhooks per account50, paused ones included. One more gets 422 webhooks.limit-reached, with the limit in metadata.limit.
Webhooks per url1. Put several event types on one webhook instead.
Event types per webhookAt least 1, any of the subscribable types, no duplicates.
Webhooks per event typeUp to 50: the same event type can go to several URLs.
urlHTTPS on port 443, a public host, no user name or password, at most 2048 characters.
nameOptional. 1 to 150 characters once trimmed. Two webhooks can have the same name.
Secret tokenOne per webhook, optional. 1 to 256 characters from A-Z, a-z, 0-9, _ and -.
List pagelimit 1 to 100, default 50.
PingsOne per webhook every 10 seconds, paused ones included. A ping waits 5 seconds and is never retried.
URL testsOne per account every 10 seconds. A test waits 5 seconds, is never retried and isn't recorded.
Delivery statsThe last 24 hours or 3 days, by UTC hour.
RequestsNo per-account limit. 3,000 per minute per IP address and endpoint by default. See Rate limits.

New fields may be added over time, so ignore fields you don't recognize (see Versioning).

Rate limits

The /v1/webhooks routes have no per-account rate limit, and they don't count toward the budget of the rest of the API. Only the per-IP limit applies: 3,000 requests per minute per IP address and endpoint by default, counted before the API key is checked, so every client behind the same outbound IP shares it. Responses that pass it carry X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset. The deliveries Knock sends to your endpoints never count toward it.

Over the limit, a call gets 429 and nothing is changed, so it's safe to retry after the number of seconds in the Retry-After header. The body is plain, with no code:

429 Too Many Requests
HTTP/1.1 429 Too Many Requests
Retry-After: 42
Content-Type: application/json; charset=utf-8

{
  "statusCode": 429,
  "message": "ThrottlerException: Too Many Requests"
}

Pings and URL tests have their own limits on top: one ping per webhook and one URL test per account every 10 seconds (see Test a webhook with a ping and Test a URL). Over either, a call gets 429 with a code and a Retry-After header. Rate limits has a ready-made retry helper.

Errors

Errors have a JSON body with errors (human-readable messages), code (stable: branch on it, not on the messages) and metadata (extra context, often empty):

409 Conflict
{
  "errors": ["A webhook for this url already exists."],
  "code": "webhooks.already-exists",
  "metadata": {
    "vendorId": "3f2c8a71-5d4e-4b9a-8c1f-2e6d7a9b0c35",
    "webhookId": "1c9e5b7a-3f2d-4e8a-b6c1-7d0f2a4e9b35"
  }
}
StatuscodeWhenRetry?
400validationThe body, path or query is invalid, for example url or events is missing, events is empty or repeats a type, an event type isn't subscribable, a field is null (except name and secretToken on PATCH), name is blank or longer than 150 characters, url is longer than 2048 characters, limit, offset or window is out of range, or webhookId isn't a UUID. errors has one message per problem.No. Fix the request.
400noneThe body isn't valid JSON. The body is {statusCode, message}, with no code.No. Fix the request.
400webhooks.invalid-secret-tokenThe secretToken is empty, longer than 256 characters, or contains a character other than A-Z, a-z, 0-9, _ and -.No. Choose a token that follows the rules.
401authentication.invalidThe x-api-key header is missing, or the key is unknown, expired or revoked. Also returned when Knock can't verify a key for a moment.A few times with backoff, then check the key.
401authentication.forbiddenThe request comes from a country Knock doesn't serve.No. Call from servers in a supported location.
403permissions.deniedThe key's role can't make this call.No. Use an Admin key, or for reads an Admin, Editor, Viewer, CRM Admin or AI Manager key.
403ip-restriction.deniedYour account only allows specific IP addresses, and this call came from another one.No. Call from an allowed IP.
404webhooks.not-foundYour account has no webhook with this webhookId, or it was deleted.No. List your webhooks to find the right ID.
409webhooks.already-existsAnother of your webhooks already uses this url. Its ID is in metadata.webhookId.No. Change that webhook's events instead.
422webhooks.invalid-urlThe url breaks one of the URL requirements. The rule is in metadata.reason.No. Fix the URL.
422webhooks.limit-reachedYou created a webhook while your account already has 50, paused ones included. The limit is in metadata.limit.No. Delete a webhook, or add event types to an existing one.
429webhooks.ping-rate-limitedYou pinged this webhook less than 10 seconds ago.Yes, after the Retry-After header's seconds (also in metadata.retryAfterSeconds).
429webhooks.url-test-rate-limitedYour account tested a URL less than 10 seconds ago.Yes, after the Retry-After header's seconds (also in metadata.retryAfterSeconds).
429noneToo many requests from one IP address. The body is {statusCode, message}, with no code.Yes, after the Retry-After header's seconds.
500webhooks.secret-decryption-failedKnock couldn't read the webhook's secret token.Yes, with exponential backoff. Contact Knock with the X-Request-Id header if it persists.
500webhooks.ping-not-runKnock couldn't send the ping.Yes, with exponential backoff.
500noneAn unexpected error. The body is {statusCode, message}, with no code.Yes, with exponential backoff.

See Errors for how the rest of the API reports errors.

Next steps

Chat with a Developer

On this page