Webhook endpoints

Where signed webhooks go. Up to 10 endpoints per account, each with its own signing secret, shown once (on create and on rotate) and never returned again.

Embed
Preview of the card
<a href="https://scrapelyserp.com/reference/webhook-endpoints"><img src="https://scrapelyserp.com/reference/_api/public/orgs/affc5b0f-d3c2-423a-8143-9d10db5736ae/spaces/e4cbe065-c1c2-4572-b134-0292dedd9c39/pages/962539f6-9b8b-4104-a176-500fb22bed53/social-card.svg?v=3e7ae33eec8b" alt="Webhook endpoints" width="600" height="315"></a>

Where signed webhooks go. Up to 10 endpoints per account, each with its own signing secret, shown once (on create and on rotate) and never returned again.

Endpoints

Method

Path

Does

GET

/v1/webhook_endpoints

List webhook endpoints

POST

/v1/webhook_endpoints

Create a webhook endpoint

GET

/v1/webhook_endpoints/{id}

Get a webhook endpoint

PATCH

/v1/webhook_endpoints/{id}

Update a webhook endpoint

DELETE

/v1/webhook_endpoints/{id}

Delete a webhook endpoint

POST

/v1/webhook_endpoints/{id}/rotate

Rotate the signing secret

POST

/v1/webhook_endpoints/{id}/test

Send a test event

How it works, when to use what, and what it costs: Webhooks. Base URL, authentication and errors: Overview.

GET /v1/webhook_endpoints

List webhook endpoints.

Every endpoint on the account, oldest first. Secrets are never returned: secret_hint shows the last four characters.

Request

curl "https://api.scrapelyserp.com/v1/webhook_endpoints" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY"

Response

{
  "object": "list",
  "data": [
    {
      "id": "we_7b1c2d3e4f5a6b7c8d9e",
      "object": "webhook_endpoint",
      "url": "https://example.com/hooks/scrapely",
      "description": "Production",
      "events": ["watchlist.product.changed", "watchlist.run.completed"],
      "enabled": true,
      "secret_hint": "whsec_…9c41",
      "previous_secret_expires_at": null,
      "created_at": "2026-10-06T08:00:00.000Z",
      "updated_at": "2026-10-06T08:00:00.000Z"
    }
  ],
  "has_more": false
}

Responses

Status

Meaning

200

Oldest first. No secrets.

401

UNAUTHORIZED: missing, unknown or revoked key.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

object

"list"

—

data

object[]

—

data[].id

string

—

data[].object

"webhook_endpoint"

—

data[].url

string

Normalised. A watchlist's webhook_url must equal it to be delivered here.

data[].description

string or null

—

data[].events

string[] or null

Account-wide events this endpoint receives. null (the default): every event. []: none — only deliveries that name this endpoint (a watchlist's webhook_url), which it always receives. One of: watchlist.product.changed, watchlist.product.matched, watchlist.product.delisted, watchlist.run.completed.

data[].enabled

boolean

A disabled endpoint receives nothing; deliveries naming it are recorded as failed.

data[].secret_hint

string

The last four characters of the current signing secret. The secret itself is never returned after create or rotate.

data[].previous_secret_expires_at

string (date-time) or null

During a rotation with overlap: when the previous secret stops signing (a second v1= until then, 24 hours after the rotation).

data[].created_at

string (date-time)

—

data[].updated_at

string (date-time)

—

has_more

boolean

—

POST /v1/webhook_endpoints

Create a webhook endpoint.

Registers a URL and generates its own signing secret, returned in secret this once. At most 10 per account (409 beyond). Not idempotent by design: a replayable response would be a stored secret.

Request body

Name

Type

Required

Description

url

string

yes

HTTPS, a public host, port 443 or 1024–65535. Unique per account.

description

string or null

—

Up to 120 characters.

events

string[] or null

—

Account-wide events this endpoint receives. null (the default): every event. []: none — only deliveries that name this endpoint (a watchlist's webhook_url), which it always receives. One of: watchlist.product.changed, watchlist.product.matched, watchlist.product.delisted, watchlist.run.completed.

enabled

boolean

—

Default true.

Request

curl -X POST "https://api.scrapelyserp.com/v1/webhook_endpoints" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/hooks/scrapely",
    "description": "Production",
    "events": ["watchlist.product.changed", "watchlist.run.completed"]
  }'

Response

{
  "id": "we_7b1c2d3e4f5a6b7c8d9e",
  "object": "webhook_endpoint",
  "url": "https://example.com/hooks/scrapely",
  "description": "Production",
  "events": ["watchlist.product.changed", "watchlist.run.completed"],
  "enabled": true,
  "secret_hint": "whsec_…9c41",
  "previous_secret_expires_at": null,
  "created_at": "2026-10-06T08:00:00.000Z",
  "updated_at": "2026-10-06T08:00:00.000Z",
  "secret": "whsec_example_shown_once_store_it_now"
}

Responses

Status

Meaning

201

Created. Save secret now.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

409

CONFLICT: idempotent request in flight, a run already in progress, or a per-account limit.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"webhook_endpoint"

—

url

string

Normalised. A watchlist's webhook_url must equal it to be delivered here.

description

string or null

—

events

string[] or null

Account-wide events this endpoint receives. null (the default): every event. []: none — only deliveries that name this endpoint (a watchlist's webhook_url), which it always receives. One of: watchlist.product.changed, watchlist.product.matched, watchlist.product.delisted, watchlist.run.completed.

enabled

boolean

A disabled endpoint receives nothing; deliveries naming it are recorded as failed.

secret_hint

string

The last four characters of the current signing secret. The secret itself is never returned after create or rotate.

previous_secret_expires_at

string (date-time) or null

During a rotation with overlap: when the previous secret stops signing (a second v1= until then, 24 hours after the rotation).

created_at

string (date-time)

—

updated_at

string (date-time)

—

secret

string

The signing secret. Shown this once: store it now (it is kept encrypted and cannot be read back).

GET /v1/webhook_endpoints/{id}

Get a webhook endpoint.

One endpoint, without its secret.

Path parameters

Name

Type

Required

Description

id

string

yes

The endpoint id (we_…).

Request

curl "https://api.scrapelyserp.com/v1/webhook_endpoints/we_7b1c2d3e4f5a6b7c8d9e" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY"

Response

{
  "id": "we_7b1c2d3e4f5a6b7c8d9e",
  "object": "webhook_endpoint",
  "url": "https://example.com/hooks/scrapely",
  "description": "Production",
  "events": ["watchlist.product.changed", "watchlist.run.completed"],
  "enabled": true,
  "secret_hint": "whsec_…9c41",
  "previous_secret_expires_at": null,
  "created_at": "2026-10-06T08:00:00.000Z",
  "updated_at": "2026-10-06T08:00:00.000Z"
}

Responses

Status

Meaning

200

The endpoint. No secret.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"webhook_endpoint"

—

url

string

Normalised. A watchlist's webhook_url must equal it to be delivered here.

description

string or null

—

events

string[] or null

Account-wide events this endpoint receives. null (the default): every event. []: none — only deliveries that name this endpoint (a watchlist's webhook_url), which it always receives. One of: watchlist.product.changed, watchlist.product.matched, watchlist.product.delisted, watchlist.run.completed.

enabled

boolean

A disabled endpoint receives nothing; deliveries naming it are recorded as failed.

secret_hint

string

The last four characters of the current signing secret. The secret itself is never returned after create or rotate.

previous_secret_expires_at

string (date-time) or null

During a rotation with overlap: when the previous secret stops signing (a second v1= until then, 24 hours after the rotation).

created_at

string (date-time)

—

updated_at

string (date-time)

—

PATCH /v1/webhook_endpoints/{id}

Update a webhook endpoint.

Change url, description, events or enabled. The secret is unchanged (rotate it separately).

Path parameters

Name

Type

Required

Description

id

string

yes

The endpoint id (we_…).

Request body

Name

Type

Required

Description

url

string

—

HTTPS, a public host, port 443 or 1024–65535. Unique per account.

description

string or null

—

Up to 120 characters.

events

string[] or null

—

Account-wide events this endpoint receives. null (the default): every event. []: none — only deliveries that name this endpoint (a watchlist's webhook_url), which it always receives. One of: watchlist.product.changed, watchlist.product.matched, watchlist.product.delisted, watchlist.run.completed.

enabled

boolean

—

Default true.

Request

curl -X PATCH "https://api.scrapelyserp.com/v1/webhook_endpoints/we_7b1c2d3e4f5a6b7c8d9e" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"enabled":false}'

Response

{
  "id": "we_7b1c2d3e4f5a6b7c8d9e",
  "object": "webhook_endpoint",
  "url": "https://example.com/hooks/scrapely",
  "description": "Production",
  "events": ["watchlist.product.changed", "watchlist.run.completed"],
  "enabled": false,
  "secret_hint": "whsec_…9c41",
  "previous_secret_expires_at": null,
  "created_at": "2026-10-06T08:00:00.000Z",
  "updated_at": "2026-10-16T09:15:04.120Z"
}

Responses

Status

Meaning

200

Updated.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

409

CONFLICT: idempotent request in flight, a run already in progress, or a per-account limit.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"webhook_endpoint"

—

url

string

Normalised. A watchlist's webhook_url must equal it to be delivered here.

description

string or null

—

events

string[] or null

Account-wide events this endpoint receives. null (the default): every event. []: none — only deliveries that name this endpoint (a watchlist's webhook_url), which it always receives. One of: watchlist.product.changed, watchlist.product.matched, watchlist.product.delisted, watchlist.run.completed.

enabled

boolean

A disabled endpoint receives nothing; deliveries naming it are recorded as failed.

secret_hint

string

The last four characters of the current signing secret. The secret itself is never returned after create or rotate.

previous_secret_expires_at

string (date-time) or null

During a rotation with overlap: when the previous secret stops signing (a second v1= until then, 24 hours after the rotation).

created_at

string (date-time)

—

updated_at

string (date-time)

—

DELETE /v1/webhook_endpoints/{id}

Delete a webhook endpoint.

Pending retries to it, and watchlists that name its URL, are recorded as failed deliveries from now on.

Path parameters

Name

Type

Required

Description

id

string

yes

The endpoint id (we_…).

Request

curl -X DELETE "https://api.scrapelyserp.com/v1/webhook_endpoints/we_7b1c2d3e4f5a6b7c8d9e" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY"

Response

{
  "id": "we_7b1c2d3e4f5a6b7c8d9e",
  "object": "webhook_endpoint",
  "deleted": true
}

Responses

Status

Meaning

200

Deleted.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"webhook_endpoint"

—

deleted

true

—

POST /v1/webhook_endpoints/{id}/rotate

Rotate the signing secret.

A new secret, effective at once, returned in secret this once. With overlap: true (the default) the old secret keeps signing too — a second v1= in Scrapely-Signature — for 24 hours, so you can deploy the new one without missing a delivery. overlap: false drops it immediately (use it if the secret leaked).

Path parameters

Name

Type

Required

Description

id

string

yes

The endpoint id (we_…).

Request body (optional)

Name

Type

Required

Description

overlap

boolean

—

Default true.

Request

curl -X POST "https://api.scrapelyserp.com/v1/webhook_endpoints/we_7b1c2d3e4f5a6b7c8d9e/rotate" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"overlap":true}'

Response

{
  "id": "we_7b1c2d3e4f5a6b7c8d9e",
  "object": "webhook_endpoint",
  "url": "https://example.com/hooks/scrapely",
  "description": "Production",
  "events": ["watchlist.product.changed", "watchlist.run.completed"],
  "enabled": true,
  "secret_hint": "whsec_…77ab",
  "previous_secret_expires_at": "2026-10-17T09:15:04.120Z",
  "created_at": "2026-10-06T08:00:00.000Z",
  "updated_at": "2026-10-16T09:15:04.120Z",
  "secret": "whsec_example_shown_once_store_it_now"
}

Responses

Status

Meaning

200

Rotated. Save secret now.

400

MISSING_PARAM or INVALID_PARAM; param names the culprit.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

id

string

—

object

"webhook_endpoint"

—

url

string

Normalised. A watchlist's webhook_url must equal it to be delivered here.

description

string or null

—

events

string[] or null

Account-wide events this endpoint receives. null (the default): every event. []: none — only deliveries that name this endpoint (a watchlist's webhook_url), which it always receives. One of: watchlist.product.changed, watchlist.product.matched, watchlist.product.delisted, watchlist.run.completed.

enabled

boolean

A disabled endpoint receives nothing; deliveries naming it are recorded as failed.

secret_hint

string

The last four characters of the current signing secret. The secret itself is never returned after create or rotate.

previous_secret_expires_at

string (date-time) or null

During a rotation with overlap: when the previous secret stops signing (a second v1= until then, 24 hours after the rotation).

created_at

string (date-time)

—

updated_at

string (date-time)

—

secret

string

The signing secret. Shown this once: store it now (it is kept encrypted and cannot be read back).

POST /v1/webhook_endpoints/{id}/test

Send a test event.

One signed webhook.test delivery to this endpoint, now, without retries. Recorded in the delivery log.

Path parameters

Name

Type

Required

Description

id

string

yes

The endpoint id (we_…).

Request

curl -X POST "https://api.scrapelyserp.com/v1/webhook_endpoints/we_7b1c2d3e4f5a6b7c8d9e/test" \
  -H "Authorization: Bearer $SCRAPELY_API_KEY"

Response

{
  "object": "webhook_test",
  "endpoint_id": "we_7b1c2d3e4f5a6b7c8d9e",
  "delivered": true,
  "status_code": 200,
  "duration_ms": 182,
  "error": null
}

Responses

Status

Meaning

200

What the endpoint answered.

401

UNAUTHORIZED: missing, unknown or revoked key.

404

NOT_FOUND.

429

RATE_LIMITED or CONCURRENCY_LIMIT. Honour Retry-After.

500

INTERNAL: our fault, not charged. Quote X-Request-Id.

Response fields

Field

Type

Description

object

"webhook_test"

—

endpoint_id

string

—

delivered

boolean

—

status_code

integer or null

—

duration_ms

integer

—

error

string or null

—

Updated