# Create a change-detection monitor

Creates a recurring change-detection monitor for a URL, delivering results via webhook.

**Limits:** request bodies are capped at 512 KB. An oversized body
returns a `400` with error code `request_too_large`.

**POST** `/v1/monitors`

## Request Body

- `url` (required)
- `type`
- `interval_type` (required)
- `cron_expression`
- `change_threshold`
- `notify_on`
- `webhook_url` (required)
- `webhook_secret`
- `webhook_headers`
- `options`
- `scrape_options`
- `metadata`

## Responses

### 201 — Monitor created.
- `id`
- `type`
- `url`
- `status`
- `interval_type`
- `cron_expression`
- `next_capture_at`
- `notify_on`
- `webhook_url`
- `webhook_headers`
- `change_threshold`
- `scrape_options`
- `last_content_hash`
- `captures_count`
- `changes_count`
- `skipped_captures`
- `last_captured_at`
- `last_changed_at`
- `consecutive_failures`
- `last_error_code`
- `suspension_reason`
- `metadata`
- `created_at`
- `updated_at`
- `cancelled_at`
- `webhook_secret`

### 400 — Bad request. When the `url` (or `webhook_url`) field fails strict
validation the error code is `invalid_url` and the `details` object
contains:
- `field` — the request field that failed (e.g. `"url"`)
- `url` — the rejected value
- `reason` — one of: `scheme_missing`, `scheme_unsupported`,
  `scheme_separator_typo`, `host_empty`, `host_invalid`,
  `host_blocked_private`, `host_blocked_loopback`, `host_too_long`,
  `host_unicode_not_punycode`, `userinfo_present`, `url_too_long`,
  `control_chars`, `not_a_url`
- `status`
- `error`
- `error.code`
- `error.message`
- `error.http_status`
- `error.failed_at`
- `error.details`

### 401 — Unauthorized. The request carried no valid credential, and no work was
performed. The unified `Error` envelope carries one of the codes below
in `error.code`; match on the code, never on the prose.

- `invalid_api_key` — a bearer API key was presented and rejected:
  unknown, revoked, expired or malformed. The bearer-only operations
  (`/v1/webhook-deliveries*` among them) also return it when no
  `Authorization` header is sent. `GET /v1/account` is the exception
  to "malformed": it returns `invalid_api_key` only for a key that
  starts `sk_test_` or `sk_live_` and is unknown, revoked or expired.
- `unauthorized` — the `Authorization` header is absent or malformed on
  an operation that also accepts a dashboard session (the dual-auth and
  billing operations). `GET /v1/account` also returns it, for no
  `Authorization` header and for any bearer value that does not start
  `sk_test_` or `sk_live_` (that value is checked as a dashboard
  session token).

Not retryable as-is: supply a valid API key first.
- `status`
- `error`
- `error.code`
- `error.message`
- `error.http_status`
- `error.failed_at`
- `error.details`

### 409 — Duplicate monitor for this URL.
- `status`
- `error`
- `error.code`
- `error.message`
- `error.http_status`
- `error.failed_at`
- `error.details`

### 422 — Validation error.
- `status`
- `error`
- `error.code`
- `error.message`
- `error.http_status`
- `error.failed_at`
- `error.details`