# Cookie Trail API and MCP guide

Manage the same sites, checks, findings, and monitoring from Claude Code or your scripts.

Public documentation: no login or API key is needed to read this file. Send your key only to the Cookie Trail API/MCP endpoints in an Authorization header.

Browser guide: https://cookietrail.app/help/api-and-mcp

## Documentation for your agent

The copied Claude setup message starts with a link to the public Markdown guide. It includes this help, a first-audit walkthrough, fix verification, and operation input schemas generated from the API validators. Agents can fetch it without signing in or sending your API key. After connecting, discover the MCP tools for their current schemas.

- [Read the API and MCP Markdown reference](https://cookietrail.app/help/api-and-mcp.md)

## Create a workspace API key

1. Sign in, select the workspace you want your tools to use, and open API & MCP.
2. On a new workspace, select Create key & connect Claude. Or create a named Development or Read-only key with your preferred expiry in API & MCP. Select Copy setup for Claude while the new key is shown.
3. Optionally restrict audit targets to exact website origins. A blank list allows any supported public target in the connected workspace.

Each key stays bound to one workspace. It reads the same sites, results, and persistent findings as your dashboard, including records created before the key. A replacement key retains access to that workspace’s history. Switching workspaces in the app does not move an existing key.

- [Open API & MCP](https://cookietrail.app/dashboard/developer)

## Connect Claude Code

Paste the copied setup message into Claude Code. It includes your new API key, the hosted MCP address, a ready-to-run connection command, and instructions for the first audit. Claude can configure its connection and tell you if a restart is needed. The message is private and shown once; if you close it before copying, create a replacement key. You can also use the manual command or environment-based .mcp.json configuration in API & MCP. No local Cookie Trail server is needed.

Ask Claude to read your workspace and usage, list or add sites, run an audit, inspect findings, and propose fixes after reading your repository. After you deploy the change to the same public URL, ask it to rerun and compare the audit. The API-key connection is supported by clients that can send a bearer header; browser-based OAuth connection is not implemented.

For other MCP clients, use https://cookietrail.app/api/mcp with Streamable HTTP and the header Authorization: Bearer YOUR_API_KEY. The server exposes 21 tools with their request schemas. In Claude Code, the manual command is: claude mcp add --transport http --scope user cookie-trail https://cookietrail.app/api/mcp --header "Authorization: Bearer YOUR_API_KEY". Replace YOUR_API_KEY with the key you just created.

**Keep the audit identity**

Audits return an ID immediately. Waiting may return before capture finishes; ask Claude to wait again with the same ID. Reuse requestId when retrying a start, rerun, or finding verification. The queued job continues if your agent disconnects.

## Use the REST API

Requests use https://cookietrail.app/api/agent and Authorization: Bearer YOUR_API_KEY. Responses are not cached. Error responses include a code and message. Check the workspace and usage before starting work.

| Operation | Endpoint |
| --- | --- |
| Read or rename workspace | GET /workspace · PATCH /workspace |
| Read usage | GET /usage |
| List or register sites | GET /sites?limit=30 · POST /sites |
| Read or edit a site | GET /sites/:siteId · PATCH /sites/:siteId |
| Archive or restore | POST /sites/:siteId/archive |
| List or start audits | GET /audits · POST /audits |
| Read audit evidence and briefs | GET /audits/:auditId |
| Verify and compare | POST /audits/:auditId/rerun · GET /audits/:auditId/compare?baselineId=… |
| Read or review persistent findings | GET /findings · GET /findings/:issueId · PATCH /findings/:issueId |
| Verify a finding | POST /findings/:issueId/verify |
| Read, enable, or pause monitoring | GET /sites/:siteId/monitoring · PUT /sites/:siteId/monitoring · DELETE /sites/:siteId/monitoring |

Send JSON bodies with Content-Type: application/json and your Authorization header. The examples below use SITE_ID, AUDIT_ID and ISSUE_ID from earlier responses; replace those placeholders before sending. Requests never need a workspace ID: your key selects the workspace.

| Request | JSON body |
| --- | --- |
| PATCH /workspace | {"name":"My workspace"} |
| POST /sites | {"url":"https://example.com/","name":"My site"} |
| PATCH /sites/SITE_ID | {"name":"My renamed site","url":"https://example.com/new-page"} |
| POST /sites/SITE_ID/archive | {"archived":true} (use false to restore) |
| POST /audits | {"siteId":"SITE_ID","region":"de","requestId":"first-audit-001"} |
| POST /audits/AUDIT_ID/rerun | {"requestId":"verify-deployment-001"} |
| PATCH /findings/ISSUE_ID | {"expectedRevision":0,"status":"in_progress","note":"Investigating consent gating","ticketUrl":"https://example.com/issues/123"} |
| POST /findings/ISSUE_ID/verify | {"requestId":"verify-finding-001"} |
| PUT /sites/SITE_ID/monitoring | {"region":"de","cadence":"weekly","hour":12,"minute":0,"weekday":1} |
| DELETE /sites/SITE_ID/monitoring | No body; pauses the schedule. |

The name is optional when registering a site, but required when editing it; the edited URL is optional. Region values are de, uk, us-east, us-west, ca and sg; omitted audit region defaults to de. Monitoring accepts weekly or daily; time is UTC, hour is 0–23, minute 0–59, and weekday is 0 (Sunday) through 6 (Saturday). Review status is open, in_progress, resolved or dismissed; note, status, ticketUrl and assigneeId are optional. Copy expectedRevision from the issue’s current revision, and use a member userId for assignment or null to clear it.

Site registration returns {siteId,url,name,reused}; site detail returns {site,...}, with site._id as the ID. Starting or rerunning a check returns {auditId,siteId,status,url,region,reused}. Retrieve GET /audits/AUDIT_ID until status leaves queued/running; complete, inconclusive and failed are terminal states. Inspect result.coverage and result.findings before deciding whether a fix worked. Result findings belong to that audit; lasting review and verification use ISSUE_ID from the persistent finding list.

Site, audit and finding lists return {sites|audits|issues,...,nextCursor}. Follow every non-null nextCursor as the cursor query parameter, even if the page is empty; keep filters unchanged. Sites and audits accept limit from 1 to 100. Audit filters are siteId, region and status. Persistent finding entries expose issueId (also _id) and revision. Finding detail returns {issue,history,historyCursor,...}; follow historyCursor as cursor for its history. To compare terminal audits, use GET /audits/AUDIT_ID/compare?baselineId=OLDER_AUDIT_ID. It returns resolved, stillPresent, new, inconclusive and coverage for the same site URL/location.

**Retry and errors**

Reuse requestId only for the same audit target, region and baseline; conflicting reuse returns 409. Repeating an active or completed request recovers its saved ID without another slot. Errors have {error:{code,message}}: 400 invalid request or cursor, 401 missing/expired/revoked key, 403 denied permission or origin, 404 missing resource in this workspace, 409 conflict/stale revision, 429 workspace allowance exhausted, 503 backend unavailable. Restart pagination without cursor if it becomes invalid.

## Access follows your current workspace role

Development keys can add and edit sites, start checks, review findings, and configure monitoring where the current role and plan allow. Read-only keys can inspect the workspace, usage, sites, evidence, and finding history. Renaming the workspace and managing monitoring require its current owner. Teammate assignment requires that plan capability. Keys cannot manage payments, membership, or create other credentials.

Checks started through the API and scheduled monitoring use the same workspace allowance as the dashboard. Reopening an active check uses no extra slot. Missing consent coverage remains inconclusive; reviewing a finding as resolved does not establish that the measured behavior was fixed.

You can revoke your own keys or make them read only. The workspace owner can manage every key in the workspace. Expired and revoked keys stop working on the next request. Leaving or being removed from the workspace disables your keys. Saved evidence remains available to current members.

## First audit with REST

Use the private API key supplied in your setup message through a local environment variable, COOKIE_TRAIL_API_KEY. The following commands assume it is already set. They never require a workspace ID. Example response fragments are illustrative; IDs must come from your actual responses.

Read the connected workspace, capabilities and current allowance before creating work:

```sh
curl --fail-with-body -sS https://cookietrail.app/api/agent/workspace \
  -H "Authorization: Bearer $COOKIE_TRAIL_API_KEY"
curl --fail-with-body -sS https://cookietrail.app/api/agent/usage \
  -H "Authorization: Bearer $COOKIE_TRAIL_API_KEY"
curl --fail-with-body -sS 'https://cookietrail.app/api/agent/sites?limit=30' \
  -H "Authorization: Bearer $COOKIE_TRAIL_API_KEY"
```

Reuse an existing site with the intended URL, or register the public URL after asking the user which page and visitor location to check:

```sh
curl --fail-with-body -sS https://cookietrail.app/api/agent/sites \
  -H "Authorization: Bearer $COOKIE_TRAIL_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"url":"https://example.com/","name":"My site"}'
```

HTTP 201 body includes {"siteId":"SITE_ID","url":"https://example.com/","name":"My site","reused":false}. Save siteId. Repeated registration reuses the same normalized URL. Archived sites need restoring before an audit, subject to capacity.

Choose a new stable requestId for this logical audit, then retain it for retries:

```sh
curl --fail-with-body -sS https://cookietrail.app/api/agent/audits \
  -H "Authorization: Bearer $COOKIE_TRAIL_API_KEY" \
  -H 'Content-Type: application/json' \
  --data '{"siteId":"SITE_ID","region":"de","requestId":"first-audit-001"}'
```

HTTP 202 body includes {"auditId":"AUDIT_ID","siteId":"SITE_ID","status":"queued","url":"https://example.com/","region":"de","reused":false}. Save auditId immediately. Retry a lost response with the identical requestId and target; a new requestId can consume another slot after an earlier check finishes. Disconnecting does not cancel a queued job.

```sh
curl --fail-with-body -sS https://cookietrail.app/api/agent/audits/AUDIT_ID \
  -H "Authorization: Bearer $COOKIE_TRAIL_API_KEY"
```

Poll at a reasonable interval, such as every 5 seconds, while status is queued or running. Stop on complete, inconclusive or failed; on failure inspect the returned error rather than repeatedly starting jobs. Audit detail includes status, progress, paths, result, issues and reportUrl. Result may be absent while work is running. Read result.coverage, result.findings, path evidence and any fix briefs before drawing conclusions. Dashboard reportUrl values may be relative to https://cookietrail.app and require the user's browser login.

## Review and verify a fix

1. List persistent findings with GET /findings and retain an issueId. An audit result finding key is not an issueId.
2. Read GET /findings/ISSUE_ID. Use issue.revision as expectedRevision when saving workflow status or notes. PATCH returns {revision}; if it returns 409, reread the issue and reconcile your update.
3. Inspect the user's actual repository, observed evidence and proposed fix before changing code. A check measures one URL and location, not every page on the domain.
4. After the user deploys the change to the same URL, POST /findings/ISSUE_ID/verify with {"requestId":"verify-finding-001"}. Save its auditId and poll to a terminal state. Alternatively POST /audits/BASELINE_ID/rerun, retain the new auditId, then GET /audits/NEW_AUDIT_ID/compare?baselineId=BASELINE_ID.
5. Read the comparison and the original finding's history. Missing consent or request coverage remains inconclusive. Setting workflow status to resolved does not prove measured resolution. Each fresh verification/rerun uses normal check allowance.

## Handle errors and pagination

- Authentication failure (401): reconnect with a current key; do not keep retrying an expired or revoked key.
- Permission or plan denial (403): inspect get_workspace capabilities and scopes. Read-only keys cannot write. Owner actions and paid capabilities still apply to Development keys.
- Not found (404): confirm the resource belongs to this key's workspace and use an ID from a current response.
- Conflict (409): reread current state. For a stale finding revision, reconcile changes. For an audit retry, preserve its original target and requestId. Changed URLs require a new baseline.
- Capacity exhausted (429): read usage and wait for the returned allowance window or free an active site slot. Changing keys or deleting history does not reset check allowance.
- Backend unavailable (503): retry reads with bounded backoff; retry audit starts with the original requestId.
- For list pages, continue with the returned nextCursor until it is null, even when a page is empty. URL-encode opaque cursor query values; retain filters and never construct cursors. Finding detail history uses historyCursor, separately from list nextCursor. An invalid cursor (400) requires restarting that pagination without a cursor.

Errors are JSON: {"error":{"code":"CONFLICT","message":"..."}}. API responses use Cache-Control: no-store. GET and POST /operations success responses generally return 200; site registration uses 201 and audit start/rerun use 202 on their resource routes. HTTP acceptance is not audit completion.

## Operation input reference

The following schemas are generated from the same validators used by the workspace API. They describe full operation inputs. For REST routes, place resource IDs in the path, list filters in query parameters, and the remaining write fields in the JSON body. For the uniform alternative, send the entire input object as JSON to POST /api/agent/operations/OPERATION_NAME. All 22 operations below support that alternative. Unknown fields are rejected. API operations select the workspace from the key; never supply a workspaceId.

MCP exposes these 22 operations plus wait_audit. Discover tools/list after connection for the exact MCP schemas. wait_audit accepts {auditId,timeoutSeconds}; timeoutSeconds defaults to 20 and is between 0 and 25. It returns the same audit detail as get_audit, including queued/running when the wait expires. REST has no wait endpoint or wait_audit operation; poll GET /audits/AUDIT_ID instead.

### get_workspace

REST: `GET /workspace` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
```

### rename_workspace

REST: `PATCH /workspace` under `https://cookietrail.app/api/agent`.

Scope: `workspace:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 80
    }
  },
  "required": [
    "name"
  ],
  "additionalProperties": false
}
```

### get_usage

REST: `GET /usage` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {},
  "additionalProperties": false
}
```

### list_sites

REST: `GET /sites?limit=30` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "cursor": {
      "type": "string",
      "maxLength": 10000
    },
    "limit": {
      "default": 30,
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "additionalProperties": false
}
```

### register_site

REST: `POST /sites` under `https://cookietrail.app/api/agent`.

Scope: `sites:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "url": {
      "type": "string",
      "maxLength": 2048
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    }
  },
  "required": [
    "url"
  ],
  "additionalProperties": false
}
```

### register_sites

REST: `POST /operations/register_sites` under `https://cookietrail.app/api/agent`.

Scope: `sites:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "sites": {
      "minItems": 1,
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "maxLength": 2048
          },
          "name": {
            "type": "string",
            "minLength": 1,
            "maxLength": 100
          }
        },
        "required": [
          "url"
        ],
        "additionalProperties": false
      }
    }
  },
  "required": [
    "sites"
  ],
  "additionalProperties": false
}
```

### get_site

REST: `GET /sites/:siteId` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "siteId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    }
  },
  "required": [
    "siteId"
  ],
  "additionalProperties": false
}
```

### update_site

REST: `PATCH /sites/:siteId` under `https://cookietrail.app/api/agent`.

Scope: `sites:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "siteId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "name": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "url": {
      "type": "string",
      "maxLength": 2048
    }
  },
  "required": [
    "siteId",
    "name"
  ],
  "additionalProperties": false
}
```

### archive_site

REST: `POST /sites/:siteId/archive` under `https://cookietrail.app/api/agent`.

Scope: `sites:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "siteId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "archived": {
      "type": "boolean"
    }
  },
  "required": [
    "siteId",
    "archived"
  ],
  "additionalProperties": false
}
```

### list_audits

REST: `GET /audits` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "cursor": {
      "type": "string",
      "maxLength": 10000
    },
    "limit": {
      "default": 30,
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    },
    "siteId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "region": {
      "type": "string",
      "enum": [
        "de",
        "uk",
        "us-east",
        "us-west",
        "ca",
        "sg"
      ]
    },
    "status": {
      "type": "string",
      "enum": [
        "queued",
        "running",
        "complete",
        "inconclusive",
        "failed"
      ]
    }
  },
  "additionalProperties": false
}
```

### start_audit

REST: `POST /audits` under `https://cookietrail.app/api/agent`.

Scope: `audits:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "siteId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "region": {
      "default": "de",
      "type": "string",
      "enum": [
        "de",
        "uk",
        "us-east",
        "us-west",
        "ca",
        "sg"
      ]
    },
    "requestId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128
    },
    "previewUrl": {
      "type": "string",
      "maxLength": 2048
    }
  },
  "required": [
    "siteId",
    "requestId"
  ],
  "additionalProperties": false
}
```

### get_audit

REST: `GET /audits/:auditId` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "auditId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    }
  },
  "required": [
    "auditId"
  ],
  "additionalProperties": false
}
```

### rerun_audit

REST: `POST /audits/:auditId/rerun` under `https://cookietrail.app/api/agent`.

Scope: `audits:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "auditId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "requestId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128
    },
    "previewUrl": {
      "type": "string",
      "maxLength": 2048
    }
  },
  "required": [
    "auditId",
    "requestId"
  ],
  "additionalProperties": false
}
```

### compare_audits

REST: `GET /audits/:auditId/compare?baselineId=BASELINE_ID` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "auditId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "baselineId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    }
  },
  "required": [
    "auditId",
    "baselineId"
  ],
  "additionalProperties": false
}
```

### list_findings

REST: `GET /findings` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "cursor": {
      "type": "string",
      "maxLength": 10000
    }
  },
  "additionalProperties": false
}
```

### get_finding

REST: `GET /findings/:issueId` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "issueId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "cursor": {
      "type": "string",
      "maxLength": 10000
    }
  },
  "required": [
    "issueId"
  ],
  "additionalProperties": false
}
```

### update_finding

REST: `PATCH /findings/:issueId` under `https://cookietrail.app/api/agent`.

Scope: `findings:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "issueId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "expectedRevision": {
      "type": "integer",
      "minimum": 0,
      "maximum": 9007199254740991
    },
    "status": {
      "type": "string",
      "enum": [
        "open",
        "in_progress",
        "resolved",
        "dismissed"
      ]
    },
    "note": {
      "type": "string",
      "maxLength": 4000
    },
    "assigneeId": {
      "type": [
        "string",
        "null"
      ]
    },
    "ticketUrl": {
      "type": "string",
      "maxLength": 2048
    }
  },
  "required": [
    "issueId",
    "expectedRevision"
  ],
  "additionalProperties": false
}
```

### verify_finding

REST: `POST /findings/:issueId/verify` under `https://cookietrail.app/api/agent`.

Scope: `audits:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "issueId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "requestId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 128
    }
  },
  "required": [
    "issueId",
    "requestId"
  ],
  "additionalProperties": false
}
```

### get_monitoring

REST: `GET /sites/:siteId/monitoring` under `https://cookietrail.app/api/agent`.

Scope: `audits:read`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "siteId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    }
  },
  "required": [
    "siteId"
  ],
  "additionalProperties": false
}
```

### configure_monitoring

REST: `PUT /sites/:siteId/monitoring` under `https://cookietrail.app/api/agent`.

Scope: `monitoring:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "siteId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    },
    "region": {
      "type": "string",
      "enum": [
        "de",
        "uk",
        "us-east",
        "us-west",
        "ca",
        "sg"
      ]
    },
    "cadence": {
      "type": "string",
      "enum": [
        "daily",
        "weekly",
        "monthly",
        "fortnightly"
      ]
    },
    "hour": {
      "type": "integer",
      "minimum": 0,
      "maximum": 23
    },
    "minute": {
      "type": "integer",
      "minimum": 0,
      "maximum": 59
    },
    "weekday": {
      "type": "integer",
      "minimum": 0,
      "maximum": 6
    },
    "dayOfMonth": {
      "type": "integer",
      "minimum": 1,
      "maximum": 31
    },
    "regions": {
      "minItems": 1,
      "maxItems": 6,
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "de",
          "uk",
          "us-east",
          "us-west",
          "ca",
          "sg"
        ]
      }
    }
  },
  "required": [
    "siteId",
    "region",
    "cadence",
    "hour",
    "minute",
    "weekday"
  ],
  "additionalProperties": false
}
```

### configure_monitoring_bulk

REST: `POST /operations/configure_monitoring_bulk` under `https://cookietrail.app/api/agent`.

Scope: `monitoring:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "siteIds": {
      "minItems": 1,
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 100
      }
    },
    "region": {
      "type": "string",
      "enum": [
        "de",
        "uk",
        "us-east",
        "us-west",
        "ca",
        "sg"
      ]
    },
    "regions": {
      "minItems": 1,
      "maxItems": 6,
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "de",
          "uk",
          "us-east",
          "us-west",
          "ca",
          "sg"
        ]
      }
    },
    "cadence": {
      "type": "string",
      "enum": [
        "monthly",
        "fortnightly"
      ]
    },
    "hour": {
      "type": "integer",
      "minimum": 0,
      "maximum": 23
    },
    "minute": {
      "type": "integer",
      "minimum": 0,
      "maximum": 59
    },
    "weekday": {
      "type": "integer",
      "minimum": 0,
      "maximum": 6
    },
    "dayOfMonth": {
      "type": "integer",
      "minimum": 1,
      "maximum": 31
    }
  },
  "required": [
    "siteIds",
    "region",
    "regions",
    "cadence",
    "hour",
    "minute",
    "weekday"
  ],
  "additionalProperties": false
}
```

### pause_monitoring

REST: `DELETE /sites/:siteId/monitoring` under `https://cookietrail.app/api/agent`.

Scope: `monitoring:write`; current role and plan also apply.

Input JSON Schema:

```json
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "siteId": {
      "type": "string",
      "minLength": 1,
      "maxLength": 100
    }
  },
  "required": [
    "siteId"
  ],
  "additionalProperties": false
}
```
