---
title: Monitor API
description: Documentation on how to create and configure monitor's with Cronitor's API.
---

The Monitor API allows you to configure monitor settings, including schedules, assertions, alert preferences and more.{% .lead %}

This guide includes a detailed reference of monitor attributes, as well as examples of creating, modifying, deleting and pausing monitors. Cronitor's open-source SDKs are the easiest way to use this API.

## Creating & Updating Monitors

Monitors are created or updated by making a `PUT` request to the `/monitors` endpoint.

The two required attributes are `type` ("job"|"check"|"heartbeat"|"site") and `key`, the unique identifier for the monitor. See the [Monitor Attributes](#monitor-attributes) below for a complete list of attributes.

```bash
PUT https://cronitor.io/api/monitors   |   status_codes: 200, 400, 403
```

```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request PUT \
--data '{
        "monitors": [
            {
                "type": "job",
                "key": "nightly-backup-job",
                "schedule": "0 0 * * *",
                "notify": ["default"],
                "assertions": ["metric.duration < 15min"]
            },
            {
                "type": "check",
                "key": "website-homepage",
                "schedule": "every 1 min",
                "notify": ["default"],
                "assertions": ["response.time < 2s"]
            }
        ]
    }' \
https://cronitor.io/api/monitors
```

Monitors can also be created individually by making a `POST` request.

```bash
POST https://cronitor.io/api/monitors   |   status_codes: 201, 400, 403
```

```bash
curl --user API_KEY: \
    --header "Content-Type: application/json" \
    --request POST \
    --data '{
        "type": "job",
        "key": "nightly-backup-job",
        "schedule": "0 0 * * *",
        "notify": ["default"]
    }' \
https://cronitor.io/api/monitors
```

### Monitor Type Examples

Here are comprehensive examples for creating different types of monitors:

### Job Monitor Examples

**Basic Cron Job:**
```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "job",
    "key": "daily-backup",
    "name": "Daily Database Backup",
    "schedule": "0 2 * * *",
    "timezone": "America/New_York",
    "assertions": [
        "metric.duration < 30min",
        "metric.error_count = 0"
    ],
    "notify": ["devops-team"],
    "note": "Backs up production database to S3",
    "platform": "linux cron",
    "grace_seconds": 300,
    "failure_tolerance": 1
}' \
https://cronitor.io/api/monitors
```

### Check Monitor Examples

**Website Uptime Check:**
```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "check",
    "key": "website-uptime",
    "name": "Main Website",
    "schedule": "every 1 min",
    "request": {
        "url": "https://example.com",
        "method": "GET",
        "timeout_seconds": 10
    },
    "assertions": [
        "response.time < 3s",
        "response.code = 200"
    ],
    "platform": "http",
    "failure_tolerance": 2,
    "notify": ["alerts"]
}' \
https://cronitor.io/api/monitors
```

**API Health Check with JSON Validation:**
```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "check",
    "key": "api-health",
    "name": "API Health Endpoint",
    "schedule": "every 30s",
    "request": {
        "url": "https://api.example.com/health",
        "method": "GET",
        "headers": {
            "Authorization": "Bearer token123",
            "User-Agent": "Cronitor/1.0"
        }
    },
    "assertions": [
        "response.code = 200",
        "response.json status = \"healthy\"",
        "response.json uptime > 0.99",
        "response.time < 500ms"
    ],
    "notify": ["api-team"]
}' \
https://cronitor.io/api/monitors
```

**SSL Certificate Monitoring:**
```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "check",
    "key": "ssl-cert-check",
    "name": "SSL Certificate Monitor",
    "schedule": "every 12 hours",
    "request": {
        "url": "https://secure.example.com",
        "method": "HEAD"
    },
    "assertions": [
        "ssl_certificate.expires_in > 30 days",
        "response.code < 400"
    ],
    "notify": ["security-team"]
}' \
https://cronitor.io/api/monitors
```

**Browser-based Check (JavaScript execution):**
```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "check",
    "key": "spa-functionality",
    "name": "Single Page App Check",
    "schedule": "every 5 min",
    "platform": "browser",
    "request": {
        "url": "https://app.example.com/dashboard",
        "method": "GET",
        "timeout_seconds": 15
    },
    "assertions": [
        "response.code = 200",
        "response.body contains \"Dashboard loaded\"",
        "response.time < 5s"
    ],
    "notify": ["frontend-team"]
}' \
https://cronitor.io/api/monitors
```

### Heartbeat Monitor Examples

**Service Health Heartbeat:**
```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "heartbeat",
    "key": "service-heartbeat",
    "name": "Microservice Health",
    "schedule": "every 2 min",
    "assertions": [
        "metric.duration < 1min",
        "metric.error_rate < 0.01"
    ],
    "grace_seconds": 120,
    "failure_tolerance": 1,
    "notify": ["ops-team"]
}' \
https://cronitor.io/api/monitors
```

**Queue Processing Heartbeat:**
```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "heartbeat",
    "key": "queue-processor",
    "name": "Background Queue Processor",
    "schedule": "every 30s",
    "assertions": [
        "metric.count > 0",
        "metric.error_count = 0"
    ],
    "platform": "sidekiq",
    "group": "background-jobs",
    "notify": ["backend-team"]
}' \
https://cronitor.io/api/monitors
```

### Site Monitor Examples

**Real User Monitoring:**
```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "site",
    "key": "webapp-rum",
    "name": "Web Application RUM",
    "schedule": "every 1 min",
    "assertions": [
        "metric.error_rate < 0.05",
        "metric.duration < 3s"
    ],
    "notify": ["frontend-team"],
    "note": "Monitors real user experience metrics"
}' \
https://cronitor.io/api/monitors
```

## Reading Monitors

Monitors can be retrieved in bulk by making a `GET` request to the top level monitors resource.

```bash
curl -X GET https://cronitor.io/api/monitors -u API_KEY:   |   status_codes: 200, 403
```

An individual monitor can be retrieved by making a `GET` request that includes a monitor key in the URL.
```bash
curl -X GET https://cronitor.io/api/monitors/:monitorKey -u API_KEY:   |   status_codes: 200, 403, 404
```

### Filtering and Searching Monitors

The monitors endpoint supports several query parameters for filtering and searching:

**Basic Filtering:**
```bash
# Filter by monitor type
curl -X GET "https://cronitor.io/api/monitors?type=job&type=check" -u API_KEY:

# Filter by group
curl -X GET "https://cronitor.io/api/monitors?group=production" -u API_KEY:

# Filter by tag
curl -X GET "https://cronitor.io/api/monitors?tag=critical&tag=database" -u API_KEY:

# Filter by state
curl -X GET "https://cronitor.io/api/monitors?state=failing&state=paused" -u API_KEY:

# Filter by environment
curl -X GET "https://cronitor.io/api/monitors?env=staging" -u API_KEY:
```

**Search Functionality:**
```bash
# Search across monitor names and keys
curl -X GET "https://cronitor.io/api/monitors?search=backup" -u API_KEY:

# Use the dedicated search endpoint for advanced search
curl -X GET "https://cronitor.io/api/search?query=backup" -u API_KEY:
```

**Advanced Search Syntax:**

The search endpoint supports scoped searches using the format `scope:phrase`:

```bash
# Search for monitors by type
curl -X GET "https://cronitor.io/api/search?query=job:backup" -u API_KEY:

# Search for monitors by group
curl -X GET "https://cronitor.io/api/search?query=group:production" -u API_KEY:

# Search for monitors by tag
curl -X GET "https://cronitor.io/api/search?query=tag:critical" -u API_KEY:

# Search for ungrouped monitors
curl -X GET "https://cronitor.io/api/search?query=ungrouped:" -u API_KEY:
```

**Supported Search Scopes:**
- `job:` - Search job monitors
- `check:` - Search check monitors
- `heartbeat:` - Search heartbeat monitors
- `group:` - Search by group name or key
- `tag:` - Search by tag name
- `ungrouped:` - Find monitors not assigned to any group

**Pagination and Sorting:**
```bash
# Paginate results
curl -X GET "https://cronitor.io/api/monitors?page=2&pageSize=25" -u API_KEY:

# Sort results (options: created, -created, name, -name)
curl -X GET "https://cronitor.io/api/monitors?sort=name" -u API_KEY:
```

## Deleting Monitors

### Individual Monitor Deletion

Monitors can be deleted individually by making a `DELETE` request that includes a monitor key in the URL.

```bash
curl -X DELETE https://cronitor.io/api/monitors/:monitorKey -u API_KEY:  |   status_codes: 204, 403, 404
```

### Bulk Monitor Deletion

Multiple monitors can be deleted in a single request by making a `DELETE` request to the monitors endpoint with a JSON body containing an array of monitor keys.

```bash
DELETE https://cronitor.io/api/monitors   |   status_codes: 200, 400, 403
```

**Request Body:**
```json
{
  "monitors": ["monitor-key-1", "monitor-key-2", "monitor-key-3"]
}
```

**Example:**
```bash
curl -X DELETE https://cronitor.io/api/monitors \
  -u API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "monitors": ["daily-backup", "weekly-cleanup", "monthly-report"]
  }'
```

**Response:**
```json
{
  "deleted_count": 2,
  "requested_count": 3,
  "errors": {
    "missing": ["monthly-report"]
  }
}
```

**Response Fields:**
- `deleted_count`: Number of monitors successfully deleted
- `requested_count`: Total number of monitors requested for deletion
- `errors`: Object containing categorized error arrays (optional)
  - `missing`: Array of monitor keys that could not be found

**Notes:**
- Each monitor deletion follows the same logic as individual deletions
- Audit logs are created for each deleted monitor
- Disabled monitors may be automatically enabled if capacity becomes available
- Non-existent monitor keys will be reported in the `errors.missing` array
- The request succeeds (200) if at least one monitor was deleted successfully

## Cloning Monitors

You can create a copy of an existing monitor by making a `POST` request to the `/monitors/clone` endpoint. This is useful when you want to create a new monitor based on an existing one's configuration.

```bash
POST https://cronitor.io/api/monitors/clone   |   status_codes: 201, 400, 403, 404
```

```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
        "key": "existing-monitor-key",
        "name": "Cloned Monitor Name"
    }' \
https://cronitor.io/api/monitors/clone
```

**Request Parameters:**

- `key` (required): The key of the monitor you want to clone
- `name` (optional): The name for the new monitor. If not provided, defaults to "Clone of [original monitor name]"

The cloned monitor will inherit all configuration from the original monitor except:
- A new unique `key` will be automatically generated
- The `name` will be set as specified or default to "Clone of [original name]"
- The monitor will start in an uninitialized state

**Example Response:**
```json
{
  "key": "auto-generated-key-123",
  "name": "Cloned Monitor Name",
  "type": "job",
  "schedule": "0 0 * * *",
  "assertions": ["metric.duration < 15min"],
  "notify": ["default"],
  "created": "2023-12-01T10:00:00Z",
  "passing": null,
  "initialized": false
}
```

## Pausing Monitors

You can programmatically pause and resume monitor evaluation using the pause endpoint. This is useful for maintenance windows, deployments, or temporarily disabling monitoring without deleting the monitor configuration.

### How Pausing Works by Monitor Type

**Job, Heartbeat & Site Monitors:**
- Cronitor continues to receive and record telemetry events
- No alerts are dispatched for schedule or assertion violations
- Monitor status remains visible in the dashboard
- Historical data is preserved

**Check Monitors:**
- Cronitor stops making outbound requests to the monitored endpoint
- No uptime checks are performed during the pause period
- Existing data and configuration are preserved

### Pause API Endpoints

```bash
GET https://cronitor.io/api/monitors/:monitorKey/pause/:hours   |   status_codes: 200, 403, 404
```

### Basic Pause Operations

```bash
# Pause monitoring indefinitely
curl -X GET "https://cronitor.io/api/monitors/my-monitor/pause" -u API_KEY:

# Pause monitoring for 24 hours
curl -X GET "https://cronitor.io/api/monitors/my-monitor/pause/24" -u API_KEY:

# Pause for 2 hours
curl -X GET "https://cronitor.io/api/monitors/my-monitor/pause/2" -u API_KEY:

# Resume monitoring (unpause)
curl -X GET "https://cronitor.io/api/monitors/my-monitor/pause/0" -u API_KEY:
```

### Bulk Pause Operations

**Pause All Monitors in a Group:**
```bash
# Pause all monitors in the "production" group for 4 hours
curl -X GET "https://cronitor.io/api/groups/production/pause/4" -u API_KEY:

# Resume all monitors in a group
curl -X GET "https://cronitor.io/api/groups/production/pause/0" -u API_KEY:
```

### Common Use Cases

**Scheduled Maintenance:**
```bash
# Pause before maintenance
curl -X GET "https://cronitor.io/api/monitors/database-backup/pause/6" -u API_KEY:

# Resume after maintenance
curl -X GET "https://cronitor.io/api/monitors/database-backup/pause/0" -u API_KEY:
```

**Deployment Windows:**
```bash
# Pause application monitors during deployment
curl -X GET "https://cronitor.io/api/groups/web-services/pause/1" -u API_KEY:
```

**Testing and Development:**
```bash
# Pause staging monitors during testing
for monitor in api-staging db-staging cache-staging; do
  curl -X GET "https://cronitor.io/api/monitors/$monitor/pause/12" -u API_KEY:
done
```

### Checking Pause Status

You can check if a monitor is paused by examining the `paused` field in the monitor details:

```bash
curl -X GET "https://cronitor.io/api/monitors/my-monitor" -u API_KEY:
```

**Response:**
```json
{
  "key": "my-monitor",
  "name": "My Monitor",
  "paused": true,
  "type": "job",
  "schedule": "0 0 * * *"
}
```

### Setting Pause State During Creation

You can also create monitors in a paused state:

```bash
curl --user API_KEY: \
--header "Content-Type: application/json" \
--request POST \
--data '{
    "type": "job",
    "key": "new-monitor",
    "schedule": "0 0 * * *",
    "paused": true
}' \
https://cronitor.io/api/monitors
```

### Best Practices

- **Use time-limited pauses** for maintenance windows to ensure monitoring resumes automatically
- **Document pause reasons** in your deployment scripts or runbooks
- **Set up alerts** for when critical monitors are paused for extended periods
- **Test resume functionality** as part of your maintenance procedures
- **Consider using groups** for bulk pause operations during system-wide maintenance

## Monitor Attributes

{% attribute name="assertions" context="[array of strings]" /%}

Monitors are evaluated multiple times per minute for both schedule and assertion violations.

The syntax for expressing most assertions is: `**"{assertion} {operator} {value}"**`
*   `"metric.duration < 5 min"`
*   `"response.code = 200"`

Assertions that use an access key to a hash data structure — `response.json` and `response.header` assertions — are expressed as: `**"{assertion} {key} {operator} {value}"**`

*   `"response.json new_user.count > 10"`
*   `"response.header X-App-Version = 1.2.3"`


Assertion | Monitor Type | Operators | Value Type |
|---------|--------------|-----------|-----------|
`metric.duration` |  `job`, `heartbeat` | <, <=, >=, > | interval e.g. '2 minutes'|
`metric.count` | `job`, `heartbeat`|  <, <=, >=, > |  int
`metric.error_count`| `job`, `heartbeat`| <, <=, >=, > | int
`metric.error_rate`| `job`, `heartbeat`| <, <=, >=, > | decimal
`response.time`| `check`| <, <=, >=, >| interval e.g. '1.2s'
`response.code`| `check`| <, <=, >=, >| int
`response.body`| `check`| contains, !contains, =, !=| string
`response.json`| `check`| contains, !contains, <, <=, =, !=, >=, >| *
`response.header`| `check`| contains, !contains, <, <=, =, !=, >=, >| *
`ssl_certificate.expires_in`| `check`| = | interval e.g. '30 days'

{% attribute name="consecutive_alert_threshold" context="[integer default:10 range:1-1000]" /%}

The maximum number of consecutive alerts to send without recovery before automatically pausing further alerts. Alerting resumes when the monitor recovers. Applies to free accounts, excluding `check` monitors.

For example, setting `consecutive_alert_threshold: 3` allows three consecutive alerts, then suppresses further alerts until recovery. Use `failure_tolerance` to tolerate failures before sending an alert.

{% attribute name="failure_tolerance" context="[integer default:0]" /%}
**job** & **heartbeat**: number of telemetry events with `state='fail'` to tolerate before sending an alert.

**check**: number of consecutive failed requests to tolerate before sending an alert.

{% attribute name="grace_seconds" context="[integer default:60 type=job, 0 otherwise]" /%}

**job** & **heartbeat**: additional time, in seconds, allowed for an expected run, completion, or heartbeat before sending a schedule alert. For jobs, this also adds time to maximum-duration assertions such as `metric.duration < 5 minutes`.

This is not a delay for explicit `state=fail` events. Use `failure_tolerance` to tolerate failed runs or requests before alerting.

**check** & **site**: `grace_seconds` has no effect on alerts, even if a value is stored on the monitor.

{% attribute name="group" context="[string]" /%}

Groups are user-defined collections of monitors, that are used to group monitors in the Cronitor application. provide the group `key` to add a monitor to a group.

{% attribute name="key" context="[string] **required**" /%}

A monitor's unique identifier. The key is used in making API requests to an individual monitor resource, e.g. `https://cronitor.io/api/monitors/:monitorKey`

It is also the required identifier for sending [telemetry events](https://cronitor.io/docs/telemetry-api "Telemetry Events API"). `https://cronitor.link/ping/API_KEY/:monitorKey`

{% attribute name="name" context="[string]" /%}

The display name of this monitor. Used to identify your monitor in alerts and within the Cronitor application. Defaults to the `key` attribute.

{% attribute name="note" context="[string]" /%}

A useful place to provide additional context/troubleshooting information about the job/system being monitored. The note is sent in alerts (excluding SMS), and are accessible from the monitor details view in the Cronitor application.

{% attribute name="notify" context="[mixed type: array, hash]" /%}

Configure where alerts are sent when Cronitor detects a problem.

All accounts have a default Notification List (_key="default"_). If notify is left empty or omitted, the default list will be used.

`Array:` An array of Notification List keys. [Notification Lists](https://cronitor.io/app/settings/alerts) are used for configuring how alerts are sent to your team.

`"notify": [‘devops-list’]`

You can also specify individual integrations prefixed with the integration type.

`"notify": [‘email:alerts@example.com, sms:+155512345555, slack:#devops-channel’]`

`Hash:` To enable occurrence based notification you can use a hash containing the keys "alerts" and "events".

The "alerts" key accepts an array of Notification List keys. The "events" key accepts a hash with keys corresponding to the lifecycle telemetry events - `run`, `complete`. If these keys are set to `true`, Cronitor will send a notification when the event occurs.

`{ "notify": { "alerts": [‘foo-bar’], "events": {"complete": true} }`

{% attribute name="paused" context="[boolean]" /%}

Is monitoring/alerting enabled or disabled.

{% attribute name="platform" context="[string]" /%}

The platform attribute is used in conjunction with the [type](#type) attribute to tell Cronitor about where and how a monitor is being run beyond.

The platform options for **job** monitors are:

`linux cron` (default), `windows`, `kubernetes`, `jvm`, `laravel`, `magento`, `sidekiq`, `celery`, `jenkins`, `quartz`, `spring`, `cloudwatch`, `node-cron`,

The platform options for **check** monitors are:

`http` (default), `browser`(executes javascript), `tcp`, `udp`

{% attribute name="realert_interval" context="[integer or string default: '8 hours']" /%}

Interval expression telling Cronitor how long to wait before sending follow up alerts after a monitor fails (and does not recover).

If an integer is provided it will be interpreted as \`X hours\`


{% attribute name="request" context="[hash  ** required by type=check **]" /%}

The details of the outgoing request:

*   `url` string - The URL of the resource to monitor.
*   `method` string - The HTTP request method: GET HEAD PATCH POST PUT
*   `body` string - The request body. Required for PUT, PATCH, and POST requests.
*   `headers` hash - The HTTP headers of the request (e.g. User-Agent). Limited to 5120 chars.
*   `cookies` hash - Cookies to set before each request. Limited to 5120 chars.
*   `timeout_seconds` integer 1 to 15 _default: 10_ - The timeout enforced when making the request. An alert will be triggered upon timeout.
*   `follow_redirects` boolean _default: true_ - HTTP checks only. If a request returns a redirect follow it and perform any assertions after the final redirect.
*   `verify_ssl` boolean _default: true_ - HTTP checks only. If a request is made to an https:// endpoint verify the SSL certificate.

{% attribute name="schedules" context="[array of strings]" /%}

_As of API version `2025-11-28`, the `schedule` field has been replaced by `schedules`, an array of schedule expressions. This allows monitors to have multiple schedule expressions (e.g., for Windows Task Scheduler RRULE triggers or multiple cron expressions). Requests using API version `2020-10-01` (the default) continue to use the `schedule` string field._

Schedule has different meanings depending on the [monitor type](#type).

**job** & **heartbeat**: the schedule tells Cronitor when to expect telemetry events from your system. If events are not received on schedule, an alert is sent.

An interval expression ('every 5 minutes'), cron expression ('0 0 \* \* \*') or time of day expression ('at 14:30') must be used.

`"schedules": ["0 0 * * *"]` or `"schedules": ["0 9 * * 1-5", "0 12 * * 6-7"]`

**check**: the schedule is used to tell Cronitor how frequently to make requests to the resource being monitored.

An interval expression must be used. The range of accepted values is 30 seconds to 1 hour. e.g. 'every 2 minutes'.

`"schedules": ["every 2 minutes"]`


{% attribute name="schedule_tolerance" context="[integer default:0]" /%}

Number of missed scheduled executions to allow before sending an alert.

{% attribute name="timezone" context="[string default: account.timezone or 'UTC']" /%}

The timezone this monitor should use when evaluating the schedule correctness.

{% attribute name="type" context="[string enum(job|heartbeat|check|site)]  **required**" /%}

The type attribute determines which of Cronitor's monitoring capabilities are used to assess the health of your system. Based on the type provided, other attributes may be required — e.g. the **checks** type requires the `request` attribute to be set.

**jobs** monitor the execution of a backend job (cron job, scheduled task, etc). This involves tracking the lifecycle of the job - the _start\_time_, _end\_time_ and _exit\_state_ of the job.

**checks** monitor websites, APIs, proxy servers, cloud storage providers (e.g. S3) or any other HTTP/TCP/UDP networked device.

**heartbeats** monitor the health of a system via telemetry events (heartbeats). There is no lifecycle to measure, the occurrence or absence of healthy/unhealthy events, as well as data passed as custom metrics are used to determine the health of an event monitor.

**sites** monitor your website based on the data collected using our [Web Analytics](/real-user-monitoring) script.

{% attribute name="environments" context="[array of objects]" /%}

Associate a monitor with specific environments. Each environment object contains:

*   `key` string - The unique identifier for the environment
*   `name` string - The display name of the environment

**Example:**
```json
{
  "environments": [
    {"key": "production", "name": "Production"},
    {"key": "staging", "name": "Staging"}
  ]
}
```

Environments allow you to track monitor status separately across different deployment environments. Configure environments from [Environment Settings](/app/settings/environments).

{% attribute name="statuspages" context="[array of strings]" /%}

An array of status page keys to associate this monitor with. When associated, the monitor's status will be reflected on the specified status pages.

**Example:**
```json
{
  "statuspages": ["main-status-page", "internal-status"]
}
```

When a monitor fails, it can automatically create an incident on the associated status pages if the status page component has autopublish enabled.

#### **Read Only Attributes**

{% attribute name="badges" context="[object]" /%}

_Available in API version `2025-11-28` and later. Replaces the `public_badge_url` and `public_detailed_badge_url` fields._

An object containing URLs for embeddable status badges:

*   `simple` - URL for a simple status badge showing pass/fail state
*   `detailed` - URL for a detailed badge with additional information

```json
{
  "badges": {
    "simple": "https://cronitor.io/badges/...",
    "detailed": "https://cronitor.io/badges/..."
  }
}
```

{% attribute name="created" context="[timestamp]" /%}

ISO 8601 formatted timestamp of when the monitor was created.

{% attribute name="disabled" context="[boolean]" /%}

Whether the monitor is currently disabled.

{% attribute name="passing" context="[boolean]" /%}

Whether the monitor is currently passing or failing.

{% attribute name="running" context="[boolean]" /%}

Whether a job is running (only applicable for type: job).

{% attribute name="initialized" context="[boolean]" /%}

Whether the monitor has received its first telemetry event. A monitor is considered initialized after Cronitor receives at least one ping.

{% attribute name="latest_event" context="[object]" /%}

The most recent telemetry event received by this monitor. Includes:

*   `stamp` - Unix timestamp of the event
*   `state` - Event state (run, complete, fail, ok)
*   `message` - Optional message included with the event
*   `duration` - Duration in milliseconds (for complete events)

{% attribute name="latest_events" context="[array of objects]" /%}

An array of the most recent telemetry events. Available when requesting monitor details with `withEvents=true`.

```bash
curl "https://cronitor.io/api/monitors/my-monitor?withEvents=true" -u API_KEY:
```

{% attribute name="latest_issue" context="[object]" /%}

The most recent issue associated with this monitor, if any. Includes the issue key, name, severity, and state.

{% attribute name="latest_invocations" context="[array of objects]" /%}

An array of recent job invocations showing run/complete pairs. Available when requesting monitor details with `withInvocations=true`.

```bash
curl "https://cronitor.io/api/monitors/my-monitor?withInvocations=true" -u API_KEY:
```

Each invocation includes:
*   `started_at` - When the job started
*   `ended_at` - When the job completed (if applicable)
*   `duration` - Total duration in milliseconds
*   `series` - The series identifier linking run and complete events

{% attribute name="next_expected_at" context="[timestamp]" /%}

ISO 8601 formatted timestamp of when the next telemetry event is expected, based on the monitor's schedule. This is useful for understanding when a monitor will be evaluated for schedule violations.

#### **Advanced Attributes**

{% attribute name="defaultName" context="[string]" /%}

When using Cronitor as part of a provisioning process it is useful to provide a name, but to allow users to be able to later edit that name from the Cronitor dashboard without the provisioning script later replacing the edit.

defaultName will be displayed as the name attribute if name is not set.

{% attribute name="defaultNote" context="[string]" /%}

Same as defaultNote above, but for the note field.

## YAML Configuration

Cronitor supports importing and exporting monitor configurations in YAML format, which is useful for version control, bulk operations, and infrastructure-as-code workflows.

### Exporting Monitors as YAML

You can export your monitors in YAML format by adding the `format=yaml` parameter or setting the `Content-Type` header to `application/yaml`:

```bash
# Export all monitors as YAML
curl -X GET "https://cronitor.io/api/monitors?format=yaml" -u API_KEY:

# Export monitors from a specific group
curl -X GET "https://cronitor.io/api/monitors?group=production&format=yaml" -u API_KEY:

# Using Content-Type header
curl -X GET https://cronitor.io/api/monitors \
  -u API_KEY: \
  -H "Accept: application/yaml"
```

**Example YAML Output:**
```yaml
jobs:
  nightly-backup:
    schedule: "0 0 * * *"
    assertions:
      - "metric.duration < 15min"
    notify:
      - default

checks:
  website-homepage:
    schedule: "every 1 min"
    request:
      url: "https://example.com"
      method: "GET"
    assertions:
      - "response.time < 2s"
      - "response.code = 200"
    notify:
      - default

heartbeats:
  service-health:
    schedule: "every 5 min"
    assertions:
      - "metric.duration < 30s"
    notify:
      - default
```

### Importing Monitors from YAML

You can create or update multiple monitors by sending YAML configuration. Cronitor's [language-specific SDKs](/docs/sdks) also provide built-in support for this.


```bash
# Import monitors from YAML file
curl --user API_KEY: \
--header "Content-Type: application/yaml" \
--request PUT \
--data-binary @monitors.yaml \
https://cronitor.io/api/monitors

# Import YAML directly
curl --user API_KEY: \
--header "Content-Type: application/yaml" \
--request PUT \
--data '
jobs:
  daily-report:
    schedule: "0 9 * * *"
    assertions:
      - "metric.duration < 10min"
    notify:
      - default
checks:
  api-health:
    schedule: "every 30s"
    request:
      url: "https://api.example.com/health"
    assertions:
      - "response.code = 200"
' \
https://cronitor.io/api/monitors
```

### Asynchronous YAML Processing

For large monitor configurations that may take time to process, Cronitor supports asynchronous YAML uploads. This prevents request timeouts and allows you to continue with other tasks while the monitors are being created or updated in the background.

#### Enabling Async Processing

To enable asynchronous processing, add `async: true` to your YAML configuration:

```bash
curl --user API_KEY: \
--header "Content-Type: application/yaml" \
--request PUT \
--data '
async: true
webhook_url: https://your-app.com/cronitor-callback
jobs:
  daily-report:
    schedule: "0 9 * * *"
    assertions:
      - "metric.duration < 10min"
    notify:
      - default
  nightly-backup:
    schedule: "0 2 * * *"
    assertions:
      - "metric.duration < 30min"
    notify:
      - default
' \
https://cronitor.io/api/monitors
```

#### Async Response

When async processing is enabled, you'll receive an immediate `202 Accepted` response with a unique batch identifier:

```json
{
  "batch_key": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing",
  "message": "Bulk update queued for async processing",
  "webhook_url": "https://your-app.com/cronitor-callback"
}
```

#### Webhook Notifications

When processing completes, Cronitor will POST the results to your webhook URL (if provided). The webhook payload includes the batch key and the complete response in YAML format:

**Successful Processing:**
```yaml
batch_key: "550e8400-e29b-41d4-a716-446655440000"
response:
  jobs:
    daily-report:
      schedule: "0 9 * * *"
      assertions:
        - "metric.duration < 10min"
      notify:
        - default
    nightly-backup:
      schedule: "0 2 * * *"
      assertions:
        - "metric.duration < 30min"
      notify:
        - default
```

**Processing with Errors:**
```yaml
batch_key: "550e8400-e29b-41d4-a716-446655440000"
response:
  invalid-monitor:
    schedule:
      - "Invalid schedule format"
    type:
      - "This field is required"
```

#### Webhook Requirements

- **HTTPS Only**: Webhook URLs must use HTTPS for security
- **Timeout**: Webhooks will timeout after 30 seconds
- **Retries**: Failed webhook calls are retried up to 5 times with exponential backoff
- **Headers**: Webhooks are sent with `Content-Type: application/yaml`
- **Format**: Webhook payloads are delivered in YAML format for consistency with monitor configurations

#### When to Use Async Processing

Async processing is recommended when:
- **Large Configurations**: Processing 50+ monitors at once
- **CI/CD Pipelines**: Avoiding timeouts in deployment scripts
- **Bulk Operations**: Mass monitor updates or migrations
- **Slow Networks**: Unreliable or slow internet connections

#### Example: Async Processing in CI/CD

```bash
#!/bin/bash
# Deploy monitors asynchronously in CI/CD pipeline

response=$(curl -s --user API_KEY: \
  --header "Content-Type: application/yaml" \
  --request PUT \
  --data-binary @monitors.yaml \
  https://cronitor.io/api/monitors)

if [ $? -eq 0 ]; then
  batch_key=$(echo $response | jq -r '.batch_key')
  echo "✅ Monitor deployment queued (batch: $batch_key)"
  echo "Results will be sent to webhook when processing completes"
else
  echo "❌ Failed to queue monitor deployment"
  exit 1
fi
```

### YAML Structure

The YAML format organizes monitors by type, with each monitor identified by its key:

```yaml
# Monitor types as top-level keys
jobs:
  nightly-background-job:
    # monitor configuration
checks:
  homepage-uptime:
    # monitor configuration
heartbeats:
  server-heartbeat:
    # monitor configuration
```

### Benefits of YAML Configuration

- **Version Control**: Store monitor configurations in Git
- **Bulk Operations**: Create/update many monitors at once
- **Infrastructure as Code**: Integrate with deployment pipelines
- **Backup & Restore**: Easy backup of monitor configurations
- **Environment Promotion**: Copy configurations between environments

## Troubleshooting

### Authentication Issues

**Problem: 401 Unauthorized**
```json
{
  "detail": "Authentication credentials were not provided."
}
```

**Solutions:**
- Verify your API key is correct: `curl -u API_KEY: https://cronitor.io/api/monitors`
- Check that your API key has `monitor:read` and `monitor:write` scopes
- See our [API Authentication documentation](/docs/api#authentication) for more details on API keys and permissions

### Monitor Creation Issues

**Problem: Duplicate Key Error**
```json
{
  "non_field_errors": ["Duplicate key error: my-monitor"]
}
```

**Solutions:**
- Use unique `key` values for each monitor
- Use PUT to update existing monitors instead of POST

**Problem: Invalid Schedule**
```json
{
  "schedule": ["Invalid schedule format"]
}
```

**Solutions:**
- Jobs/Heartbeats: Use cron (`0 0 * * *`), interval (`every 5 minutes`), or time (`at 14:30`)
- Checks: Use only intervals (`every 30s` to `every 1 hour`)

### Request Configuration Issues

**Problem: Missing Request for Check Monitors**
```json
{
  "request": ["This field is required for check monitors"]
}
```

**Solution:**
```bash
curl -u API_KEY: -H "Content-Type: application/json" -X POST \
-d '{
  "type": "check",
  "key": "my-check",
  "schedule": "every 1 min",
  "request": {"url": "https://example.com"}
}' https://cronitor.io/api/monitors
```

### Common Status Codes

| Code | Meaning | Solution |
|------|---------|----------|
| 400 | Bad Request | Check validation errors in response |
| 401 | Unauthorized | Verify API key |
| 403 | Forbidden | Check API key scopes |
| 404 | Not Found | Monitor doesn't exist |
| 429 | Rate Limited | Reduce request frequency |

---