---
title: "Create monitor"
method: POST
path: "/monitors"
---

# Create monitor

`POST /monitors`

## Request

- Base URL: `https://app.yoping.me/api/v1`
- URL: `https://app.yoping.me/api/v1/monitors`
- Auth: API key in cookie `yp_session`

Creates a monitor. The plan's monitor cap and the per-account distinct-target-host cap (both from the plan) return 422 `plan_limit`; an alert channel id that does not belong to the account returns 404.

## Request body

- MonitorRequest: Create/update payload for a monitor. Target shape depends on type: http/keyword require an absolute http(s) URL; ssl takes a host, host:port, or https URL (normalized to host:port, default port 443); ping takes a bare hostname or IP; tcp requires host:port.
  - `type` 'http' | 'keyword' | 'ssl' | 'ping' | 'tcp', required
  - `name` string: Defaults to the target host when omitted.
  - `target` string, required
  - `http_method` 'GET' | 'HEAD' | 'POST'
  - `interval_seconds` integer: Minimum and default are the plan's min_interval_seconds (300 on free, 60 on pro).
  - `timeout_ms` integer
  - `accepted_statuses` string: Comma-separated tokens: a class (2xx-5xx), a 3-digit code (100-599), or an inclusive NNN-NNN range.
  - `keyword` string: Required for type "keyword".
  - `keyword_mode` 'present' | 'absent': Required for type "keyword".
  - `alert_channel_ids` string[]: Alert channels to attach. A channel id not owned by the account is a 404.
  - `regions` string[], nullable: Region codes to check from (see GET /regions). Omitted, null, or empty means automatic: the first max_regions active regions, tracked as the fleet changes. An explicit set is capped by the plan's max_regions and pinned — it does not adopt regions added later.
  - `notification_policy` object
    - `alert_after_seconds` integer: 0 = alert immediately once the outage is confirmed (default). Maximum is the plan's max_alert_after_seconds.
    - `region_alert_after_seconds` integer: 0 = alert immediately once a region is confirmed degraded (default). Maximum is the plan's max_region_alert_after_seconds. Only meaningful with at least 2 effective regions — a monitor checked from a single region can never see one region disagree with the others, so this can never fire there.

## Response `201`

Monitor created.

- object: Uniform success envelope: the payload is always under `data`.
  - `data` Monitor, required: The full monitor object (returned by create, update, pause, and resume).
    - `id` string, required
    - `type` 'http' | 'keyword' | 'ssl' | 'ping' | 'tcp', required
    - `name` string, required
    - `target` string, required
    - `http_method` 'GET' | 'HEAD' | 'POST', required
    - `interval_seconds` integer, required
    - `timeout_ms` integer, required
    - `accepted_statuses` string, required
    - `keyword` string, nullable, required
    - `keyword_mode` 'present' | 'absent' | 'null', nullable, required
    - `paused` boolean, required
    - `paused_reason` 'domain_conflict' | 'plugin_silent' | 'null', nullable, required: Why the system, not the user, paused this monitor; null while it is running or when the user paused it. domain_conflict: disabled because another account monitors this website's domain (free plan). plugin_silent: paused because the YoPingMe WordPress plugin on this site stopped reporting for 30 days; the plugin's next report resumes it automatically.
    - `current_status` 'up' | 'down' | 'confirming' | 'unknown', required
    - `next_due_at` string, date-time, nullable, required
    - `created_at` string, date-time, required
    - `alert_channel_ids` string[], required
    - `regions` string[], nullable, required: Explicit region codes, or null for automatic (the plan-capped prefix of the active fleet).
    - `notification_policy` object, required: v1 shipped this as a reserved empty object; it now carries the DOWN-alert delay and the region-degradation alert delay (seconds) and may grow more fields.
      - `alert_after_seconds` integer, required
      - `region_alert_after_seconds` integer, required: Region-degradation alert delay in seconds. Only meaningful with at least 2 effective regions — a monitor checked from a single region can never see one region disagree with the others, so this can never fire there.

## Other responses

- `400`: Invalid input (code `validation_failed`): malformed JSON, a missing or out-of-range field, bad pagination parameters, or a rejected token.
- `401`: Not authenticated (code `unauthorized`): missing, invalid, or expired session; invalid login credentials; or a Bearer token, which this surface rejects.
- `403`: Forbidden. Code `forbidden` for a cross-origin (CSRF) request blocked by origin validation or for API-key management attempted without a browser session; `account_suspended` when a suspended account attempts a mutation; `account_deleted` when an account in its deletion grace window calls a non-exempt route.
- `404`: Not found (code `not_found`). A resource id belonging to another account is indistinguishable from a missing one.
- `422`: A plan or account cap was hit (code `plan_limit`): monitor cap, distinct-target-host cap, or API-key cap.
- `429`: Too many requests (code `rate_limited`). A global per-IP budget of 300 requests/minute (burst 60) applies to every endpoint; login, signup, and test alerts have tighter dedicated limits.

---

[API](https://skmtc.dev/yoping/apis/yopingme-api.md) · [All operations](https://skmtc.dev/yoping/apis/yopingme-api/llms.txt) · [OpenAPI document](https://skmtc.dev/yoping/apis/yopingme-api/revisions/76d8deb40173?raw)
