---
title: "Webhooks · Scrape.ly Docs"
description: "HTTP notifications for run and build events, with payloads, retries, and delivery logs."
url: https://scrape.ly/docs/api-webhooks
markdown: https://scrape.ly/docs/api-webhooks.md
---

# Webhooks

> HTTP notifications for run and build events, with payloads, retries, and delivery logs.

Webhooks send an HTTP `POST` to your endpoint when an Actor run or build changes state. All endpoints are prefixed with `https://api.scrape.ly/v2`. Authenticate with `Authorization: Bearer $SCRAPELY_TOKEN`.

The `/v2/webhooks` routes need your personal API token, or an Actor run token with full permissions. Limited-permission run tokens receive `403 insufficient-permissions`. The `/v2/webhook-dispatches` routes accept any token for your account.

To attach a one-off webhook to a single run instead of creating a standing one, pass `webhooks` when you start the run; see [Actors API](https://scrape.ly/docs/api-actors.md).

Every webhook except ad-hoc ones is also listed as an automation: `GET /v2/automations?include=webhooks` and `GET /v2/automations/{webhookId}` return it with `"source": "webhook"`, and the dashboard shows it under **Automations**. Nothing on this page changes because of that. See [Webhooks as automations](https://scrape.ly/docs/api-automations.md#webhooks-as-automations).

## Endpoints

| Method | Path | Description |
| --- | --- | --- |
| `GET` | `/v2/webhooks` | List webhooks you own |
| `POST` | `/v2/webhooks` | Create a webhook |
| `GET` | `/v2/webhooks/{webhookId}` | Get a webhook |
| `PUT` | `/v2/webhooks/{webhookId}` | Update a webhook |
| `DELETE` | `/v2/webhooks/{webhookId}` | Delete a webhook |
| `GET` | `/v2/webhooks/{webhookId}/dispatches` | List dispatches for one webhook |
| `POST` | `/v2/webhooks/{webhookId}/test` | Send a `TEST` event |
| `POST` | `/v2/webhooks/{webhookId}/convert-to-automation` | Turn a Trigger Actor or Trigger task webhook into an [automation](https://scrape.ly/docs/api-automations.md#convert-a-webhook) |
| `GET` | `/v2/actor-tasks/{taskId}/webhooks` | Your webhooks whose condition names this task |
| `GET` | `/v2/webhook-dispatches` | List dispatches for your account |
| `GET` | `/v2/webhook-dispatches/{dispatchId}` | Get one dispatch |

## Errors and limits

| Status | `error.type` | When |
| --- | --- | --- |
| `400` | `invalid-input` | Missing `requestUrl`, empty or invalid `eventTypes`, a malformed URL, a URL that is not allowed (see [Allowed URLs](#allowed-urls)), or `ACTOR.BUILD.*` events with a `condition.actorId` you don't own. |
| `403` | `insufficient-permissions` | A limited-permission Actor run token called a `/v2/webhooks` route. |
| `403` | `limit-reached` | Creating a webhook when you already have your plan's maximum number of webhooks. |
| `403` | `permission-denied` | The webhook belongs to another account. |
| `404` | `record-not-found` | The webhook or dispatch does not exist, or the dispatch belongs to another account. |

## Event types

`eventTypes` is an array of these values:

| Event | Fires when |
| --- | --- |
| `ACTOR.RUN.CREATED` | A run is created, however it was started: `POST /v2/actors/{actorId}/runs`, the synchronous run endpoints, a task run, a schedule, or an automation. |
| `ACTOR.RUN.SUCCEEDED` | A run finishes successfully. |
| `ACTOR.RUN.FAILED` | A run fails. |
| `ACTOR.RUN.ABORTED` | A run is aborted. |
| `ACTOR.RUN.TIMED_OUT` | A run exceeds its timeout. |
| `ACTOR.RUN.RESURRECTED` | A finished run is resurrected. |
| `ACTOR.BUILD.CREATED` | A build starts. |
| `ACTOR.BUILD.SUCCEEDED` | A build finishes successfully. |
| `ACTOR.BUILD.FAILED` | A build fails. |
| `ACTOR.BUILD.ABORTED` | A build is aborted. |
| `ACTOR.BUILD.TIMED_OUT` | A build exceeds its timeout. |
| `TEST` | Sent by [Test webhook](#test-webhook). |

Build events are owner only: they fire only for your own Actors, and you can't set them on someone else's Actor.

### Conditions

`condition` narrows which events fire the webhook. Every field you set must match:

| Field | Matches |
| --- | --- |
| `actorId` | Runs and builds of this Actor. Builds only if you own it. |
| `actorTaskId` | Runs started from this task, including their `ACTOR.RUN.CREATED` event. `ACTOR.RUN.RESURRECTED` events do not carry a task ID, so a webhook with this condition does not receive them. |
| `actorRunId` | This run only. Build events never match. |

An empty `condition` (the default) matches every event of the selected types across your account.

## Get list of webhooks

```
GET /v2/webhooks
```

| Query param | Type | Description |
| --- | --- | --- |
| `limit` | number | Page size (default `1000`, max `1000`). |
| `offset` | number | Number of webhooks to skip (default `0`). |
| `desc` | boolean | **Default is `true`** (newest first). Pass `desc=0` for ascending. |
| `sortBy` | string | `createdAt` (default), `description`, `requestUrl`, or `isEnabled`. |

```bash [Request]
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  "https://api.scrape.ly/v2/webhooks?limit=20&sortBy=createdAt"
```

```json [Response]
{
  "data": {
    "total": 1,
    "count": 1,
    "offset": 0,
    "limit": 20,
    "items": [
      {
        "id": "5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c",
        "createdAt": "2026-08-14T15:00:00.000Z",
        "modifiedAt": "2026-08-14T15:00:00.000Z",
        "userId": "uSrIdExAmPlE123",
        "isAdHoc": null,
        "shouldInterpolateStrings": null,
        "eventTypes": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED"],
        "condition": { "actorId": "eLN5rTB8sYTBWdfzx" },
        "ignoreSslErrors": false,
        "doNotRetry": null,
        "requestUrl": "https://example.com/hooks/scrapely",
        "payloadTemplate": null,
        "headersTemplate": null,
        "description": "Notify the data pipeline",
        "lastDispatch": { "status": "SUCCEEDED", "finishedAt": "2026-08-14T15:02:31.000Z" },
        "stats": { "totalDispatches": 12 },
        "idempotencyKey": null,
        "isEnabled": true
      }
    ]
  }
}
```

`lastDispatch` and `stats` are `null` until the webhook has fired.

```api-test
{ "method": "GET", "path": "/v2/webhooks?limit=5" }
```

## Create webhook

```
POST /v2/webhooks
```

| Body field | Type | Required | Description |
| --- | --- | --- | --- |
| `eventTypes` | string[] | Yes | Non-empty array of [event types](#event-types). |
| `requestUrl` | string | Yes | HTTP or HTTPS URL that receives the event. See [Allowed URLs](#allowed-urls). |
| `condition` | object | No | `actorId`, `actorTaskId`, and/or `actorRunId`. See [Conditions](#conditions). Defaults to `{}`. |
| `payloadTemplate` | string | No | Template for the request body. See [Payload template](#payload-template). |
| `headersTemplate` | string | No | JSON object, as a string, of extra request headers. See [Headers template](#headers-template). |
| `description` | string | No | Human-readable description. |
| `isAdHoc` | boolean | No | Delete the webhook after its first dispatch. |
| `shouldInterpolateStrings` | boolean | No | `false` leaves placeholders inside JSON strings of `payloadTemplate`, and in `headersTemplate` values, as written. Placeholders outside strings are still replaced. |
| `ignoreSslErrors` | boolean | No | Stored and returned for compatibility. TLS certificates are always verified. |
| `notification` | object | No | Send a Slack, Discord, or email message, or write to Google Sheets, instead of a `POST`. See [Notifications](#notifications). |
| `doNotRetry` | boolean | No | Send each event once, without [retries](#retries). |
| `idempotencyKey` | string | No | If you already have a webhook with this key, that webhook is returned instead of creating another. |
| `isEnabled` | boolean | No | `false` creates the webhook turned off (default `true`). Any other non-boolean value returns `400 invalid-input`. |

```bash
curl -X POST https://api.scrape.ly/v2/webhooks \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "eventTypes": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED"],
    "requestUrl": "https://example.com/hooks/scrapely",
    "condition": { "actorId": "eLN5rTB8sYTBWdfzx" },
    "description": "Notify the data pipeline"
  }'
```

Returns `201` with `{ "data": { ...webhook } }`.

## Get webhook

```
GET /v2/webhooks/{webhookId}
```

```bash
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  https://api.scrape.ly/v2/webhooks/5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c
```

Returns `{ "data": { ...webhook } }` in the same shape as a list item.

```api-test
{ "method": "GET", "path": "/v2/webhooks/5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c" }
```

## Update webhook

```
PUT /v2/webhooks/{webhookId}
```

Send only the fields you want to change. Accepts the create fields except `idempotencyKey`, plus `isEnabled`. A new `requestUrl` is checked against [Allowed URLs](#allowed-urls), and `eventTypes` values must be valid.

| Body field | Type | Description |
| --- | --- | --- |
| `isEnabled` | boolean | Enable or disable the webhook. |

```bash
curl -X PUT https://api.scrape.ly/v2/webhooks/5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"isEnabled": false}'
```

Returns the updated webhook.

## Delete webhook

```
DELETE /v2/webhooks/{webhookId}
```

Returns `204 No Content`.

```bash
curl -X DELETE -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  https://api.scrape.ly/v2/webhooks/5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c
```

## Test webhook

```
POST /v2/webhooks/{webhookId}/test
```

Sends a `TEST` event with placeholder values (`test-actor-id`, `test-run-id`, and so on) to the webhook's `requestUrl`, using its templates and retry settings, and stores a dispatch record. The test is sent even if the webhook is disabled.

```bash [Request]
curl -X POST -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  https://api.scrape.ly/v2/webhooks/5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c/test
```

```json [Response]
{
  "data": {
    "webhookId": "5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c",
    "success": true,
    "statusCode": 200,
    "sentAt": "2026-08-14T15:03:00.000Z",
    "responseTimeMs": 91,
    "attemptCount": 1
  }
}
```

On failure, `success` is `false` and `error` describes the last attempt.

## Delivery

### Request

Each event is sent as `POST` to `requestUrl` with these headers:

| Header | Value |
| --- | --- |
| `Content-Type` | `application/json` |
| `User-Agent` | `Scrapely-Webhook/1.0` |
| `X-Scrapely-Webhook-Dispatch-Id` | ID of the [dispatch record](#list-webhook-dispatches). |
| `X-Scrapely-Webhook` | An HMAC-SHA256 of the body, signed with a platform key. |

> [!TIP]
> You cannot verify `X-Scrapely-Webhook`, because the signing key is not available to you. To authenticate deliveries, put a secret in `headersTemplate` (for example `{"X-Webhook-Secret": "..."}`) or in the `requestUrl` query string, and check it in your endpoint.

Without a `payloadTemplate`, the body is:

```json
{
  "userId": "uSrIdExAmPlE123",
  "createdAt": "2026-08-14T15:02:31.000Z",
  "eventType": "ACTOR.RUN.SUCCEEDED",
  "eventData": {
    "actorId": "eLN5rTB8sYTBWdfzx",
    "actorTaskId": null,
    "actorRunId": "a3f9c1e7b5d20486f",
    "userId": "uSrIdExAmPlE123",
    "status": "SUCCEEDED",
    "startedAt": "2026-08-14T15:00:00.000Z",
    "finishedAt": "2026-08-14T15:02:31.000Z",
    "durationMillis": 151000,
    "defaultDatasetId": "3f6c1a2e-8b4d-4c7a-9e21-5d0b7f3a9c10",
    "defaultKeyValueStoreId": "b2d7e4a1-5c3f-4e8a-9f60-1a2b3c4d5e6f",
    "defaultRequestQueueId": "7a9e2c4b-1d3f-4b6a-8c5e-0f1a2b3c4d5e",
    "buildId": "bUiLdIdExAmPlE123",
    "exitCode": 0,
    "computeUnits": 0.13
  },
  "resource": { "...": "same object as eventData" }
}
```

On runs of an Actor you don't own, `buildId` is left out (and `{{buildId}}` is an empty string). Dispatch lists leave `buildId` and `buildNumber` out of the stored payloads of those runs, also for dispatches sent before builds became owner only.

For build events, `eventData` has `actorId`, `buildId`, `userId`, `status`, `startedAt`, `finishedAt`, `durationMillis`, `versionNumber`, `buildTag`, and `exitCode`.

### Payload template

`payloadTemplate` replaces the default body. Placeholders in double braces are replaced with **JSON-encoded** values, so write them without surrounding quotes:

| Placeholder | Value |
| --- | --- |
| `{{userId}}`, `{{createdAt}}`, `{{eventType}}` | Event fields. |
| `{{eventData}}`, `{{resource}}` | The whole event data object. |
| `{{eventData.field}}`, `{{resource.field}}` | One field of the event data, for example `{{resource.defaultDatasetId}}`. Unknown fields become `null`. |
| `{{globals.dateISO}}`, `{{globals.dateUnix}}` | Event time as an ISO string or Unix seconds. |
| `{{actorId}}`, `{{actorRunId}}`, `{{status}}`, `{{startedAt}}`, `{{finishedAt}}`, `{{buildId}}`, `{{defaultDatasetId}}`, `{{defaultKeyValueStoreId}}`, `{{exitCode}}`, `{{durationMillis}}`, `{{computeUnits}}` | Shortcuts to event data fields, always encoded as strings (`{{exitCode}}` becomes `"0"`). Use `{{eventData.exitCode}}` for a number. |

```json
{ "text": {{status}}, "run": {{actorRunId}}, "dataset": {{resource.defaultDatasetId}}, "sentAt": {{globals.dateISO}} }
```

Inside a JSON string, a placeholder that is the whole string (`"{{resource.defaultDatasetId}}"`) is replaced by its JSON value, and one inside other text (`"Run {{actorRunId}}"`) by its plain text, unless `shouldInterpolateStrings` is `false`.

The template is sent as rendered and is not validated, so check that it produces valid JSON.

### Headers template

`headersTemplate` is a JSON object, as a string, whose entries are added to the request headers. These placeholders are replaced with plain text: `{{eventType}}`, `{{actorId}}`, `{{actorRunId}}`, `{{status}}`, `{{userId}}`, and `{{createdAt}}`. Set `shouldInterpolateStrings` to `false` to send the values unchanged. A template that is not valid JSON is ignored.

```json
"{\"X-Webhook-Secret\": \"s3cr3t\", \"X-Run-Status\": \"{{status}}\"}"
```

Header values are secrets, so only your Default key, OAuth tokens, and API keys that can write webhooks see them. Read-only and other scoped keys, run tokens, and CI tokens get every value as `********`. Sending `********` back in a `PUT` keeps the stored value. A caller that only sees masked values can't change the `requestUrl` or `condition` of a webhook that stores header values unless it also sends a new `headersTemplate`, and can't send that webhook a test delivery (`403 insufficient-permissions`).

### Retries

A delivery succeeds on any `2xx` response. Network errors, timeouts, `429`, and `5xx` responses are retried up to 5 times, after 1, 2, 4, 8, and 16 seconds. Other `4xx` responses fail immediately. Redirects are not followed, so a `3xx` response is a failure. Each attempt times out after 30 seconds. Set `doNotRetry` to send only once.

### Allowed URLs

`requestUrl` can be `http` or `https`. URLs that point at `localhost`, private or internal networks, or Scrape.ly infrastructure are rejected, both when you save the webhook and again when it is sent. The one exception is the Scrape.ly API's run endpoints, `/v2/actors/{actorId}/runs` and `/v2/actor-tasks/{taskId}/runs`, so one event can start another run. Those endpoints need a token, so send it from `headersTemplate`:

```json
{
  "eventTypes": ["ACTOR.RUN.SUCCEEDED"],
  "condition": { "actorId": "eLN5rTB8sYTBWdfzx" },
  "requestUrl": "https://api.scrape.ly/v2/actors/kT2pQ9mWx4LbN7sVc/runs",
  "headersTemplate": "{\"Authorization\": \"Bearer <your token>\"}",
  "payloadTemplate": "{\"datasetId\": {{resource.defaultDatasetId}}}"
}
```

The rendered payload becomes the second run's input.

## Notifications

A webhook with a `notification` object sends a ready-made message, or writes the run's results to a Google Sheet, instead of a `POST`. Leave out `requestUrl`, `payloadTemplate`, and `headersTemplate`. Only the run-finished events are allowed (`ACTOR.RUN.SUCCEEDED`, `FAILED`, `ABORTED`, `TIMED_OUT`); Google Sheets takes only `ACTOR.RUN.SUCCEEDED`. These webhooks need your personal API token and can't be ad hoc.

| `notification` field | Channels | Description |
| --- | --- | --- |
| `channel` | all | `slack`, `discord`, `email`, or `gsheets`. Can't be changed later. |
| `discordWebhookUrl` | `discord` | A `https://discord.com/api/webhooks/…` URL. Stored encrypted; responses show it masked. |
| `email` | `email` | Recipient (required). Your account email works right away; any other address gets a confirmation link first. |
| `onlyWithResults` | `slack`, `discord`, `email` | Skip succeeded runs that returned no items. Default `false`. |
| `previewItems` | `slack`, `discord`, `email` | First 0 to 5 items shown in the message. Default `3`. |
| `message` | `slack`, `discord`, `email` | Your own text above the run details, up to 1,000 characters. Variables: `{{actorName}}`, `{{taskName}}`, `{{status}}`, `{{runId}}`, `{{duration}}`, `{{itemCount}}`, `{{cost}}`, `{{runUrl}}`, `{{datasetUrl}}`. |
| `sheetUrl` | `gsheets` | Link to a sheet shared with the address from `GET /v2/integrations/gsheets`. |
| `sheetName` | `gsheets` | Tab to write to; `null` for the first tab. |
| `mode` | `gsheets` | `append` (add rows) or `replace` (clear the tab first). |
| `maxRows` | `gsheets` | Items written per run, 1 to 10,000. Default `1000`. |

Slack posts to the channel connected under **Settings → Connections**. Responses carry `notification` with `channel`, a masked `target`, and the options; for Slack also `connected`, for email `emailState`. `POST /v2/webhooks/{webhookId}/test` sends a test message. Limits, retries, and message contents are described in [Slack, Discord and Email](https://scrape.ly/docs/integrations.md#slack-discord-and-email) and [Google Sheets](https://scrape.ly/docs/integrations.md#google-sheets).

```bash
curl -X POST https://api.scrape.ly/v2/webhooks \
  -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "eventTypes": ["ACTOR.RUN.FAILED", "ACTOR.RUN.TIMED_OUT"],
    "condition": { "actorId": "eLN5rTB8sYTBWdfzx" },
    "description": "Slack when the crawl fails",
    "notification": { "channel": "slack", "previewItems": 0 }
  }'
```

## List webhooks of a task

```
GET /v2/actor-tasks/{taskId}/webhooks
```

Your webhooks whose `condition.actorTaskId` names this task, in the same shape as [Get list of webhooks](#get-list-of-webhooks). `{taskId}` can be the task ID or `username~task-name`. Paginated with `limit` (default and max `1000`), `offset`, and `desc` (default `false`). The task must be yours: another account's task returns `403 forbidden`, an unknown one `404 record-or-token-not-found`. On a scoped key it needs `webhooks:read`. For an Actor's webhooks, see [List Actor webhooks](https://scrape.ly/docs/api-actors.md#list-actor-webhooks).

```bash
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  "https://api.scrape.ly/v2/actor-tasks/kQ7mN2pXv9LsT4wRb/webhooks"
```

```api-test
{ "method": "GET", "path": "/v2/actor-tasks/{taskId}/webhooks" }
```

## List dispatches for a webhook

```
GET /v2/webhooks/{webhookId}/dispatches
```

Lists dispatch records for one webhook, newest first. There is one record per event, not per retry attempt. A webhook you don't own returns an empty list.

| Query param | Type | Description |
| --- | --- | --- |
| `limit` | number | Page size (default `1000`, max `1000`). |
| `offset` | number | Number of records to skip (default `0`). |

```bash [Request]
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  "https://api.scrape.ly/v2/webhooks/5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c/dispatches?limit=20"
```

```json [Response]
{
  "data": {
    "total": 1,
    "count": 1,
    "offset": 0,
    "limit": 20,
    "items": [
      {
        "id": "c8f2a6d4-3b1e-4f7a-a9c5-6e0d2b4f8a1c",
        "webhookId": "5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c",
        "userId": "uSrIdExAmPlE123",
        "actorId": "eLN5rTB8sYTBWdfzx",
        "actorRunId": "a3f9c1e7b5d20486f",
        "eventType": "ACTOR.RUN.SUCCEEDED",
        "status": "succeeded",
        "statusCode": 200,
        "error": null,
        "requestPayload": { "createdAt": "2026-08-14T15:02:31.000Z", "eventType": "ACTOR.RUN.SUCCEEDED", "eventData": { "...": "..." } },
        "responseTimeMs": 84,
        "createdAt": "2026-08-14T15:02:31.000Z"
      }
    ]
  }
}
```

- `status` is `succeeded` or `failed` (lower case), after all retries.
- `requestPayload` holds the event (`createdAt`, `eventType`, `eventData`), not the rendered `payloadTemplate`.
- Records are kept for 2 days on the free plan, 31, 60 or 90 days on the Starter, Scale or Business plan, and at most the newest 500 per webhook.

```api-test
{ "method": "GET", "path": "/v2/webhooks/5e1c7b9a-2f4d-4a8e-b3c6-9d0e1f2a3b4c/dispatches?limit=20" }
```

## List webhook dispatches

```
GET /v2/webhook-dispatches
```

Lists dispatch records across all your webhooks, newest first. [Automation webhook deliveries](https://scrape.ly/docs/api-automations.md#webhook-delivery) are listed too, with the automation's ID as `webhookId` and the event type `AUTOMATION.RUN.SUCCEEDED` or `AUTOMATION.RUN.FAILED`.

| Query param | Type | Description |
| --- | --- | --- |
| `limit` | number | Page size (default `1000`, max `1000`). |
| `offset` | number | Number of records to skip (default `0`). |
| `runId` | string | Only dispatches for this Actor run. |

```bash
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  "https://api.scrape.ly/v2/webhook-dispatches?limit=20"
```

The response matches [List dispatches for a webhook](#list-dispatches-for-a-webhook).

```api-test
{ "method": "GET", "path": "/v2/webhook-dispatches?limit=5" }
```

## Get webhook dispatch

```
GET /v2/webhook-dispatches/{dispatchId}
```

```bash
curl -H "Authorization: Bearer $SCRAPELY_TOKEN" \
  https://api.scrape.ly/v2/webhook-dispatches/c8f2a6d4-3b1e-4f7a-a9c5-6e0d2b4f8a1c
```

Returns `{ "data": { ...dispatch } }` with the same fields as a list item.

```api-test
{ "method": "GET", "path": "/v2/webhook-dispatches/c8f2a6d4-3b1e-4f7a-a9c5-6e0d2b4f8a1c" }
```

---

- Previous: [Automations](https://scrape.ly/docs/api-automations.md)
- Next: [Schedules](https://scrape.ly/docs/api-schedules.md)
- All docs: [Docs index](https://scrape.ly/docs.md), [llms.txt](https://scrape.ly/llms.txt)
