API Documentation

CronMonitor provides a RESTful API for programmatic access to your monitors.

Base URL #

https://cronmonitor.io/api/v1

Authentication #

All API requests require authentication using an API token.

Getting Your API Token #

  1. Log in to your dashboard
  2. Go to Settings β†’ API Tokens
  3. Click "Generate New Token"
  4. Copy and store the token securely

⚠️ Warning: Treat your API token like a password. Never commit it to version control.

Authentication Methods #

curl -H "Authorization: Bearer your-api-token" \
     https://cronmonitor.io/api/v1/monitors

API Key Header #

curl -H "X-API-Key: your-api-token" \
     https://cronmonitor.io/api/v1/monitors

Rate Limiting #

  • Free Plan: 100 requests per hour
  • Pro Plan: 1,000 requests per hour
  • Business Plan: 10,000 requests per hour

Rate limit headers in responses:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1638360000

Endpoints #

List Monitors #

Get all monitors for your account.

GET /api/v1/monitors

Response:

{
  "data": [
    {
      "id": "mon_abc123",
      "name": "Daily Backup",
      "schedule": "0 2 * * *",
      "timezone": "Europe/Warsaw",
      "grace_period": 300,
      "status": "up",
      "last_ping_at": "2025-12-01T02:00:15Z",
      "next_expected_at": "2025-12-02T02:00:00Z",
      "created_at": "2025-11-01T10:00:00Z"
    }
  ],
  "meta": {
    "total": 1,
    "page": 1,
    "per_page": 50
  }
}

Example:

curl -H "Authorization: Bearer your-api-token" \
     https://cronmonitor.io/api/v1/monitors

Get Monitor Details #

GET /api/v1/monitors/{monitorId}

Response:

{
  "data": {
    "id": "mon_abc123",
    "name": "Daily Backup",
    "schedule": "0 2 * * *",
    "timezone": "Europe/Warsaw",
    "grace_period": 300,
    "status": "up",
    "ping_url": "https://cronmonitor.io/ping/abc123def456",
    "last_ping_at": "2025-12-01T02:00:15Z",
    "next_expected_at": "2025-12-02T02:00:00Z",
    "ping_count": 30,
    "failure_count": 0,
    "created_at": "2025-11-01T10:00:00Z"
  }
}

Example:

curl -H "Authorization: Bearer your-api-token" \
     https://cronmonitor.io/api/v1/monitors/mon_abc123

Create Monitor #

POST /api/v1/monitors

Request Body:

{
  "name": "Daily Backup",
  "schedule": "0 2 * * *",
  "timezone": "Europe/Warsaw",
  "grace_period": 300,
  "enabled": true
}

Response: 201 Created

{
  "data": {
    "id": "mon_abc123",
    "name": "Daily Backup",
    "schedule": "0 2 * * *",
    "timezone": "Europe/Warsaw",
    "grace_period": 300,
    "status": "pending",
    "ping_url": "https://cronmonitor.io/ping/abc123def456",
    "created_at": "2025-12-01T22:00:00Z"
  }
}

Examples:

cURL:

curl -X POST \
  -H "Authorization: Bearer your-api-token" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Daily Backup",
    "schedule": "0 2 * * *",
    "timezone": "Europe/Warsaw",
    "grace_period": 300
  }' \
  https://cronmonitor.io/api/v1/monitors

PHP:

<?php
$ch = curl_init('https://cronmonitor.io/api/v1/monitors');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer your-api-token',
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => json_encode([
        'name' => 'Daily Backup',
        'schedule' => '0 2 * * *',
        'timezone' => 'Europe/Warsaw',
        'grace_period' => 300,
    ]),
]);

$response = curl_exec($ch);
$data = json_decode($response, true);
curl_close($ch);

Python:

import requests

response = requests.post(
    'https://cronmonitor.io/api/v1/monitors',
    headers={'Authorization': 'Bearer your-api-token'},
    json={
        'name': 'Daily Backup',
        'schedule': '0 2 * * *',
        'timezone': 'Europe/Warsaw',
        'grace_period': 300
    }
)

data = response.json()

Update Monitor #

PATCH /api/v1/monitors/{monitorId}

Request Body:

{
  "name": "Daily Backup (Updated)",
  "grace_period": 600
}

Response: 200 OK

{
  "data": {
    "id": "mon_abc123",
    "name": "Daily Backup (Updated)",
    "schedule": "0 2 * * *",
    "timezone": "Europe/Warsaw",
    "grace_period": 600,
    "updated_at": "2025-12-01T22:00:00Z"
  }
}

Delete Monitor #

DELETE /api/v1/monitors/{monitorId}

Response: 204 No Content

Example:

curl -X DELETE \
  -H "Authorization: Bearer your-api-token" \
  https://cronmonitor.io/api/v1/monitors/mon_abc123

Pause Monitor #

POST /api/v1/monitors/{monitorId}/pause

Response: 200 OK

{
  "data": {
    "id": "mon_abc123",
    "status": "paused",
    "paused_at": "2025-12-01T22:00:00Z"
  }
}

Resume Monitor #

POST /api/v1/monitors/{monitorId}/resume

Response: 200 OK

{
  "data": {
    "id": "mon_abc123",
    "status": "up",
    "resumed_at": "2025-12-01T22:00:00Z"
  }
}

Get Ping History #

GET /api/v1/monitors/{monitorId}/pings

Query Parameters:

  • limit (optional): Number of pings to return (default: 50, max: 100)
  • from (optional): Start date (ISO 8601)
  • to (optional): End date (ISO 8601)

Response:

{
  "data": [
    {
      "id": "ping_xyz789",
      "pinged_at": "2025-12-01T02:00:15Z",
      "status": "success",
      "duration": 2.5,
      "message": "Backup completed: 1.2GB",
      "ip_address": "192.168.1.1"
    }
  ],
  "meta": {
    "total": 100,
    "page": 1,
    "per_page": 50
  }
}

Error Responses #

All errors follow this format:

{
  "error": {
    "code": "validation_error",
    "message": "Invalid schedule format",
    "details": {
      "schedule": ["Must be a valid cron expression"]
    }
  }
}

Common Error Codes #

Code HTTP Status Description
unauthorized 401 Invalid or missing API token
forbidden 403 Access denied
not_found 404 Resource not found
validation_error 422 Invalid input data
rate_limit_exceeded 429 Too many requests
server_error 500 Internal server error

Webhooks #

Configure webhooks to receive notifications about monitor events.

Webhook Payload #

When a monitor fails:

{
  "event": "monitor.failed",
  "monitor": {
    "id": "mon_abc123",
    "name": "Daily Backup",
    "schedule": "0 2 * * *",
    "status": "down"
  },
  "last_ping_at": "2025-11-30T02:00:15Z",
  "expected_at": "2025-12-01T02:00:00Z",
  "failed_at": "2025-12-01T02:05:00Z",
  "grace_period": 300
}

When a monitor recovers:

{
  "event": "monitor.recovered",
  "monitor": {
    "id": "mon_abc123",
    "name": "Daily Backup",
    "status": "up"
  },
  "recovered_at": "2025-12-01T02:00:15Z",
  "downtime_duration": 86400
}

Verifying Webhooks #

All webhooks include a signature header:

X-CronMonitor-Signature: sha256=abc123def456...

PHP Verification:

<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_CRONMONITOR_SIGNATURE'];
$secret = 'your-webhook-secret';

$expectedSignature = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expectedSignature, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$data = json_decode($payload, true);
// Process webhook...

Complete SDK Example #

PHP SDK Wrapper #

<?php
class CronMonitorAPI
{
    private string $apiToken;
    private string $baseUrl = 'https://cronmonitor.io/api/v1';

    public function __construct(string $apiToken)
    {
        $this->apiToken = $apiToken;
    }

    public function listMonitors(): array
    {
        return $this->request('GET', '/monitors');
    }

    public function getMonitor(string $id): array
    {
        return $this->request('GET', "/monitors/{$id}");
    }

    public function createMonitor(array $data): array
    {
        return $this->request('POST', '/monitors', $data);
    }

    public function updateMonitor(string $id, array $data): array
    {
        return $this->request('PATCH', "/monitors/{$id}", $data);
    }

    public function deleteMonitor(string $id): void
    {
        $this->request('DELETE', "/monitors/{$id}");
    }

    public function pauseMonitor(string $id): array
    {
        return $this->request('POST', "/monitors/{$id}/pause");
    }

    public function resumeMonitor(string $id): array
    {
        return $this->request('POST', "/monitors/{$id}/resume");
    }

    private function request(string $method, string $endpoint, ?array $data = null): array
    {
        $ch = curl_init($this->baseUrl . $endpoint);

        curl_setopt_array($ch, [
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_HTTPHEADER => [
                'Authorization: Bearer ' . $this->apiToken,
                'Content-Type: application/json',
                'Accept: application/json',
            ],
        ]);

        if ($data !== null) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }

        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($httpCode >= 400) {
            throw new Exception("API Error: {$response}");
        }

        return json_decode($response, true);
    }
}

// Usage
$api = new CronMonitorAPI('your-api-token');

// List all monitors
$monitors = $api->listMonitors();

// Create new monitor
$monitor = $api->createMonitor([
    'name' => 'Daily Backup',
    'schedule' => '0 2 * * *',
    'timezone' => 'Europe/Warsaw',
    'grace_period' => 300,
]);

// Pause monitor
$api->pauseMonitor($monitor['data']['id']);

Video Tutorial #

πŸ“Ί Watch: "Using the CronMonitor API" (10 minutes)

πŸŽ₯

API Tutorial

Video coming soon


Next Steps #