# Campaigns

Reusable crawl configurations and their schedule.

## List the campaigns of a project

`GET /v1/projects/{project}/campaigns`

Reusable crawl configurations and their schedule, newest first.


- Required scopes: `projects:read`
- Rate-limit cost: 1 unit(s)

### Parameters

- `project` (path, string (uuid), required)
- `cursor` (query, string, optional): Opaque cursor from `meta.next_cursor`. It is bound to the request that issued it; reusing it with other filters returns `400 pagination.invalid_cursor`.
- `limit` (query, integer, optional): Items per page, 1 to 100 (default 25).

### Responses

- `200`: OK.
- `400`: Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`).
- `422`: Invalid query or body values (`validation_failed`), with `errors` by field.
- `401`: Missing, invalid or expired token, or a member who left the team.
- `403`: The plan does not include the API (`api.not_in_plan`) or this verb
(`api.write_not_in_plan`), or the token lacks a scope
(`token.missing_scope`).

- `404`: No such resource for the token's team. Resources of another team answer 404 as well, never 403.
- `429`: The plan rate limit is exhausted for one window.

### Request example (cURL)

```bash
curl "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/campaigns" \
  -H "Authorization: Bearer $NESSFLOW_TOKEN"
```

### Response example

```json
{
    "data": [
        {
            "id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
            "name": "Exemple",
            "start_url": "https://exemple.fr/",
            "max_depth": 42,
            "max_urls": 42,
            "javascript_rendering": true,
            "pagespeed": true,
            "check_external_links": true,
            "check_ai_reachability": true,
            "check_accessibility": true,
            "protected_site": true,
            "schedule": {
                "frequency": "manual",
                "day": "string",
                "time": "string",
                "paused": true,
                "next_run_at": "string"
            },
            "created_at": "2026-10-01T09:30:00Z"
        }
    ],
    "meta": {
        "limit": 100,
        "has_more": true,
        "next_cursor": "string"
    }
}
```

## Create a campaign

`POST /v1/projects/{project}/campaigns`

Same validation and plan bounds as the product (URL budget, JavaScript
rendering, schedule frequencies). Unknown fields are refused, never ignored.


- Required scopes: `projects:write`
- Rate-limit cost: 1 unit(s)
- Idempotency-Key accepted

### Parameters

- `project` (path, string (uuid), required)

### Request body

- `name` (string, required)
- `start_url` (string, required)
- `max_depth` (integer, required)
- `max_urls` (integer, required)
- `javascript_rendering` (boolean, optional)
- `pagespeed` (boolean, optional)
- `check_external_links` (boolean, optional)
- `check_ai_reachability` (boolean, optional)
- `check_accessibility` (boolean, optional)
- `check_accessibility_rendered` (boolean, optional)
- `include_patterns` (string | null, optional)
- `exclude_patterns` (string | null, optional)
- `issue_exclusion_patterns` (string | null, optional)
- `timeout` (integer | null, optional)
- `retries` (integer | null, optional)
- `duplication_threshold` (number | null, optional)
- `regression_threshold` (string, optional) [off, warning, error]
- `protected_site` (boolean, optional)
- `http_user` (string | null, optional)
- `http_password` (string | null, optional)
- `notify` (boolean, optional)
- `schedule` (object, optional)

### Responses

- `201`: OK.
- `400`: Malformed request, such as an invalid pagination cursor (`pagination.invalid_cursor`).
- `401`: Missing, invalid or expired token, or a member who left the team.
- `403`: The plan does not include the API (`api.not_in_plan`) or this verb
(`api.write_not_in_plan`), or the token lacks a scope
(`token.missing_scope`).

- `404`: No such resource for the token's team. Resources of another team answer 404 as well, never 403.
- `409`: The request conflicts with the current state (a crawl already running, an idempotency key in use, a project not ready).
- `422`: Invalid query or body values (`validation_failed`), with `errors` by field.
- `429`: The plan rate limit is exhausted for one window.

### Request example (cURL)

```bash
curl -X POST "https://api.nessflow.com/v1/projects/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57/campaigns" \
  -H "Authorization: Bearer $NESSFLOW_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"name":"Exemple","start_url":"https://exemple.fr/","max_depth":42,"max_urls":42,"javascript_rendering":true,"pagespeed":true,"check_external_links":true,"check_ai_reachability":true,"check_accessibility":true,"check_accessibility_rendered":true,"include_patterns":"string","exclude_patterns":"string","issue_exclusion_patterns":"string","timeout":42,"retries":42,"duplication_threshold":0.5,"regression_threshold":"off","protected_site":true,"http_user":"string","http_password":"string","notify":true,"schedule":{"frequency":"manual","day":"string","time":"string"}}'
```

### Response example

```json
{
    "data": {
        "id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
        "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
        "name": "Exemple",
        "start_url": "https://exemple.fr/",
        "max_depth": 42,
        "max_urls": 42,
        "javascript_rendering": true,
        "pagespeed": true,
        "check_external_links": true,
        "check_ai_reachability": true,
        "check_accessibility": true,
        "protected_site": true,
        "schedule": {
            "frequency": "manual",
            "day": "string",
            "time": "string",
            "paused": true,
            "next_run_at": "string"
        },
        "created_at": "2026-10-01T09:30:00Z"
    }
}
```

## Get a campaign

`GET /v1/campaigns/{campaign}`

A crawl configuration and its schedule. HTTP credentials are never returned.


- Required scopes: `projects:read`
- Rate-limit cost: 1 unit(s)

### Parameters

- `campaign` (path, string (uuid), required)

### Responses

- `200`: OK.
- `401`: Missing, invalid or expired token, or a member who left the team.
- `403`: The plan does not include the API (`api.not_in_plan`) or this verb
(`api.write_not_in_plan`), or the token lacks a scope
(`token.missing_scope`).

- `404`: No such resource for the token's team. Resources of another team answer 404 as well, never 403.
- `429`: The plan rate limit is exhausted for one window.

### Request example (cURL)

```bash
curl "https://api.nessflow.com/v1/campaigns/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57" \
  -H "Authorization: Bearer $NESSFLOW_TOKEN"
```

### Response example

```json
{
    "data": {
        "id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
        "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
        "name": "Exemple",
        "start_url": "https://exemple.fr/",
        "max_depth": 42,
        "max_urls": 42,
        "javascript_rendering": true,
        "pagespeed": true,
        "check_external_links": true,
        "check_ai_reachability": true,
        "check_accessibility": true,
        "protected_site": true,
        "schedule": {
            "frequency": "manual",
            "day": "string",
            "time": "string",
            "paused": true,
            "next_run_at": "string"
        },
        "created_at": "2026-10-01T09:30:00Z"
    }
}
```

## Update a campaign

`PATCH /v1/campaigns/{campaign}`

Partial update: absent fields keep their value. The HTTP password stays unchanged when absent.


- Required scopes: `projects:write`
- Rate-limit cost: 1 unit(s)

### Parameters

- `campaign` (path, string (uuid), required)

### Request body

- `name` (string, optional)
- `start_url` (string, optional)
- `max_depth` (integer, optional)
- `max_urls` (integer, optional)
- `javascript_rendering` (boolean, optional)
- `pagespeed` (boolean, optional)
- `check_external_links` (boolean, optional)
- `check_ai_reachability` (boolean, optional)
- `check_accessibility` (boolean, optional)
- `check_accessibility_rendered` (boolean, optional)
- `include_patterns` (string | null, optional)
- `exclude_patterns` (string | null, optional)
- `issue_exclusion_patterns` (string | null, optional)
- `timeout` (integer | null, optional)
- `retries` (integer | null, optional)
- `duplication_threshold` (number | null, optional)
- `regression_threshold` (string, optional) [off, warning, error]
- `protected_site` (boolean, optional)
- `http_user` (string | null, optional)
- `http_password` (string | null, optional)
- `notify` (boolean, optional)
- `schedule` (object, optional)

### Responses

- `200`: OK.
- `401`: Missing, invalid or expired token, or a member who left the team.
- `403`: The plan does not include the API (`api.not_in_plan`) or this verb
(`api.write_not_in_plan`), or the token lacks a scope
(`token.missing_scope`).

- `404`: No such resource for the token's team. Resources of another team answer 404 as well, never 403.
- `422`: Invalid query or body values (`validation_failed`), with `errors` by field.
- `429`: The plan rate limit is exhausted for one window.

### Request example (cURL)

```bash
curl -X PATCH "https://api.nessflow.com/v1/campaigns/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57" \
  -H "Authorization: Bearer $NESSFLOW_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"name":"Exemple","start_url":"https://exemple.fr/","max_depth":42,"max_urls":42,"javascript_rendering":true,"pagespeed":true,"check_external_links":true,"check_ai_reachability":true,"check_accessibility":true,"check_accessibility_rendered":true,"include_patterns":"string","exclude_patterns":"string","issue_exclusion_patterns":"string","timeout":42,"retries":42,"duplication_threshold":0.5,"regression_threshold":"off","protected_site":true,"http_user":"string","http_password":"string","notify":true,"schedule":{"frequency":"manual","day":"string","time":"string"}}'
```

### Response example

```json
{
    "data": {
        "id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
        "project_id": "0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57",
        "name": "Exemple",
        "start_url": "https://exemple.fr/",
        "max_depth": 42,
        "max_urls": 42,
        "javascript_rendering": true,
        "pagespeed": true,
        "check_external_links": true,
        "check_ai_reachability": true,
        "check_accessibility": true,
        "protected_site": true,
        "schedule": {
            "frequency": "manual",
            "day": "string",
            "time": "string",
            "paused": true,
            "next_run_at": "string"
        },
        "created_at": "2026-10-01T09:30:00Z"
    }
}
```

## Delete a campaign

`DELETE /v1/campaigns/{campaign}`

Deletes the campaign and its crawls. A running crawl of the campaign is stopped first.


- Required scopes: `projects:write`
- Rate-limit cost: 1 unit(s)

### Parameters

- `campaign` (path, string (uuid), required)

### Responses

- `204`: Deleted.
- `401`: Missing, invalid or expired token, or a member who left the team.
- `403`: The plan does not include the API (`api.not_in_plan`) or this verb
(`api.write_not_in_plan`), or the token lacks a scope
(`token.missing_scope`).

- `404`: No such resource for the token's team. Resources of another team answer 404 as well, never 403.
- `429`: The plan rate limit is exhausted for one window.

### Request example (cURL)

```bash
curl -X DELETE "https://api.nessflow.com/v1/campaigns/0190f5a2-7c4e-7b1a-9d3e-2f6b8c1a4e57" \
  -H "Authorization: Bearer $NESSFLOW_TOKEN"
```
