Checks
Checks are the core resource in WatchCron. Each check represents a cron job or scheduled task you want to monitor. The API lets you create, list, update, and delete checks programmatically.
List checks
/api/v1/checks
Returns a paginated list of all checks in the project associated with your API key.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
tag | string | — | Filter checks by tag (exact match) |
per_page | integer | 25 | Results per page |
page | integer | 1 | Page number |
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://watchcron.com/api/v1/checks?tag=production&per_page=10"
$response = Http::withToken('YOUR_API_KEY') ->get('https://watchcron.com/api/v1/checks', [ 'tag' => 'production', 'per_page' => 10, ]); $checks = $response->json('data');
import requests response = requests.get( "https://watchcron.com/api/v1/checks", headers={"Authorization": "Bearer YOUR_API_KEY"}, params={"tag": "production", "per_page": 10}, ) checks = response.json()["data"]
const response = await fetch( "https://watchcron.com/api/v1/checks?tag=production&per_page=10", { headers: { "Authorization": "Bearer YOUR_API_KEY" } } ); const { data: checks } = await response.json();
req, _ := http.NewRequest("GET", "https://watchcron.com/api/v1/checks?tag=production&per_page=10", nil) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close()
Response 200 OK
{
"data": [
{
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Nightly Backup",
"description": "Backs up production database",
"status": "up",
"schedule_type": "cron",
"period_seconds": null,
"cron_expression": "0 2 * * *",
"timezone": "UTC",
"grace_seconds": 600,
"tags": ["production", "database"],
"is_paused": false,
"ping_url": "https://watchcron.com/ping/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"last_ping_at": "2026-09-14T02:00:12Z",
"next_expected_at": "2026-09-15T02:00:00Z",
"created_at": "2026-03-22T10:00:00Z",
"updated_at": "2026-09-14T02:00:12Z"
}
],
"meta": {
"pagination": {
"total": 42,
"per_page": 10,
"current_page": 1,
"last_page": 5
}
}
}
Check object
Every check response includes these fields:
| Field | Type | Description |
|---|---|---|
uuid | string | Unique identifier (UUID v4). Used in all API and ping URLs. |
name | string | Display name of the check |
description | string|null | Optional description |
status | string | Current status: new, up, grace, down, or paused |
schedule_type | string | simple (fixed interval) or cron (cron expression) |
period_seconds | integer|null | Interval in seconds (only for simple schedule) |
cron_expression | string|null | Cron expression (only for cron schedule). Supports standard 5-field format. |
timezone | string | IANA timezone for cron schedule evaluation (e.g. America/New_York) |
grace_seconds | integer | Seconds to wait after expected ping before alerting |
tags | array|null | List of tag strings for organizing checks |
is_paused | boolean | Whether monitoring is paused |
ping_url | string | The URL your cron job should ping on completion |
last_ping_at | string|null | ISO 8601 timestamp of most recent ping |
next_expected_at | string|null | ISO 8601 timestamp of next expected ping |
created_at | string | ISO 8601 timestamp |
updated_at | string | ISO 8601 timestamp |
Status values
| Status | Meaning |
|---|---|
new | Check created, waiting for the first ping |
up | Receiving pings on schedule — everything is healthy |
grace | Ping is late, but still within the grace period |
down | Ping missed — grace period expired, alert triggered |
paused | Monitoring is paused — no alerts will fire |
Create a check
/api/v1/checks
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Check name (max 255 characters) |
description | string | No | Optional description (max 1000 characters) |
schedule_type | string | Yes | simple or cron |
period_seconds | integer | If simple | Interval in seconds (minimum 60) |
cron_expression | string | If cron | Standard 5-field cron expression (max 100 characters) |
timezone | string | No | IANA timezone (defaults to UTC) |
grace_seconds | integer | No | Grace period in seconds (defaults to system default) |
tags | array | No | List of tag strings (each max 50 characters) |
simple for fixed-interval jobs (e.g. “every 5 minutes”). Use cron when your job runs on a specific cron schedule (e.g. 0 2 * * * for 2 AM daily). The cron type supports standard 5-field expressions including ranges, lists, and steps.Example: create with cron schedule
curl -X POST https://watchcron.com/api/v1/checks \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Nightly Backup", "schedule_type": "cron", "cron_expression": "0 2 * * *", "timezone": "America/New_York", "grace_seconds": 600, "tags": ["production", "database"] }'
$response = Http::withToken('YOUR_API_KEY') ->post('https://watchcron.com/api/v1/checks', [ 'name' => 'Nightly Backup', 'schedule_type' => 'cron', 'cron_expression' => '0 2 * * *', 'timezone' => 'America/New_York', 'grace_seconds' => 600, 'tags' => ['production', 'database'], ]); $check = $response->json('data'); echo "Ping URL: " . $check['ping_url'];
import requests response = requests.post( "https://watchcron.com/api/v1/checks", headers={"Authorization": "Bearer YOUR_API_KEY"}, json={ "name": "Nightly Backup", "schedule_type": "cron", "cron_expression": "0 2 * * *", "timezone": "America/New_York", "grace_seconds": 600, "tags": ["production", "database"], }, ) check = response.json()["data"] print(f"Ping URL: {check['ping_url']}")
const response = await fetch("https://watchcron.com/api/v1/checks", { method: "POST", headers: { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Nightly Backup", schedule_type: "cron", cron_expression: "0 2 * * *", timezone: "America/New_York", grace_seconds: 600, tags: ["production", "database"], }), }); const { data: check } = await response.json(); console.log(`Ping URL: ${check.ping_url}`);
body := strings.NewReader(`{ "name": "Nightly Backup", "schedule_type": "cron", "cron_expression": "0 2 * * *", "timezone": "America/New_York", "grace_seconds": 600, "tags": ["production", "database"] }`) req, _ := http.NewRequest("POST", "https://watchcron.com/api/v1/checks", body) req.Header.Set("Authorization", "Bearer YOUR_API_KEY") req.Header.Set("Content-Type", "application/json") resp, _ := http.DefaultClient.Do(req) defer resp.Body.Close()
Response 201 Created
{
"data": {
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Nightly Backup",
"description": null,
"status": "new",
"schedule_type": "cron",
"period_seconds": null,
"cron_expression": "0 2 * * *",
"timezone": "America/New_York",
"grace_seconds": 600,
"tags": ["production", "database"],
"is_paused": false,
"ping_url": "https://watchcron.com/ping/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"last_ping_at": null,
"next_expected_at": null,
"created_at": "2026-09-14T10:00:00Z",
"updated_at": "2026-09-14T10:00:00Z"
}
}
Example: create with simple interval
curl -X POST https://watchcron.com/api/v1/checks \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Health Check Ping", "schedule_type": "simple", "period_seconds": 300, "grace_seconds": 120 }'
This creates a check that expects a ping every 5 minutes (300 seconds) with a 2-minute grace period.
Validation errors
If the cron expression is invalid, the API returns 422:
{
"error": "Invalid cron expression"
}
Get a check
/api/v1/checks/{uuid}
Returns full details for a single check.
curl -H "Authorization: Bearer YOUR_API_KEY" \ "https://watchcron.com/api/v1/checks/a1b2c3d4-e5f6-7890-abcd-ef1234567890"
$uuid = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'; $response = Http::withToken('YOUR_API_KEY') ->get("https://watchcron.com/api/v1/checks/{$uuid}"); $check = $response->json('data');
uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890" response = requests.get( f"https://watchcron.com/api/v1/checks/{uuid}", headers={"Authorization": "Bearer YOUR_API_KEY"}, ) check = response.json()["data"]
const uuid = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"; const response = await fetch( `https://watchcron.com/api/v1/checks/${uuid}`, { headers: { "Authorization": "Bearer YOUR_API_KEY" } } ); const { data: check } = await response.json();
Returns the same check object as shown in Check object. Returns 404 if the UUID does not exist or belongs to a different project.
Update a check
/api/v1/checks/{uuid}
Updates one or more fields on an existing check. Only include the fields you want to change — all fields are optional.
Request body
| Field | Type | Description |
|---|---|---|
name | string | Check name (max 255 characters) |
description | string|null | Optional description (max 1000 characters) |
schedule_type | string | simple or cron |
period_seconds | integer|null | Interval in seconds (min 60) |
cron_expression | string|null | Cron expression (max 100 characters) |
timezone | string|null | IANA timezone |
grace_seconds | integer|null | Grace period in seconds |
tags | array|null | Tag strings (replaces existing tags) |
curl -X PUT https://watchcron.com/api/v1/checks/YOUR-UUID \ -H "Authorization: Bearer YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Nightly Backup v2", "cron_expression": "30 1 * * *", "grace_seconds": 900 }'
$response = Http::withToken('YOUR_API_KEY') ->put("https://watchcron.com/api/v1/checks/{$uuid}", [ 'name' => 'Nightly Backup v2', 'cron_expression' => '30 1 * * *', 'grace_seconds' => 900, ]);
response = requests.put( f"https://watchcron.com/api/v1/checks/{uuid}", headers={"Authorization": "Bearer YOUR_API_KEY"}, json={ "name": "Nightly Backup v2", "cron_expression": "30 1 * * *", "grace_seconds": 900, }, )
const response = await fetch(`https://watchcron.com/api/v1/checks/${uuid}`, { method: "PUT", headers: { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json", }, body: JSON.stringify({ name: "Nightly Backup v2", cron_expression: "30 1 * * *", grace_seconds: 900, }), });
Returns 200 OK with the updated check object.
"tags": ["new-tag"] replaces all existing tags. To add a tag, include the full list of desired tags. Send "tags": null to clear all tags.Delete a check
/api/v1/checks/{uuid}
Permanently deletes a check and all its associated ping data.
curl -X DELETE \ -H "Authorization: Bearer YOUR_API_KEY" \ "https://watchcron.com/api/v1/checks/YOUR-UUID"
$response = Http::withToken('YOUR_API_KEY') ->delete("https://watchcron.com/api/v1/checks/{$uuid}");
response = requests.delete( f"https://watchcron.com/api/v1/checks/{uuid}", headers={"Authorization": "Bearer YOUR_API_KEY"}, )
const response = await fetch( `https://watchcron.com/api/v1/checks/${uuid}`, { method: "DELETE", headers: { "Authorization": "Bearer YOUR_API_KEY" }, } );
Returns 204 No Content on success. This action is irreversible.