Code Examples

Complete, ready-to-use examples for common API workflows. Each example is a self-contained script you can copy and adapt.

PHP / Laravel

Using Laravel's HTTP client (or any PSR-18 client). These examples assume you store your API key in .env as WATCHCRON_API_KEY.

Create a check and integrate the ping

PHP — Create check and ping on success
<?php

use Illuminate\Support\Facades\Http;

$apiKey = env('WATCHCRON_API_KEY');
$baseUrl = 'https://watchcron.com/api/v1';

// 1. Create a check for your nightly backup
$response = Http::withToken($apiKey)
    ->post("{$baseUrl}/checks", [
        'name'            => 'Nightly DB Backup',
        'schedule_type'   => 'cron',
        'cron_expression' => '0 3 * * *',
        'timezone'        => 'Europe/Berlin',
        'grace_seconds'   => 600,
        'tags'            => ['production', 'database'],
    ]);

$check = $response->json('data');
$pingUrl = $check['ping_url'];

echo "Check created: {$check['uuid']}\n";
echo "Ping URL: {$pingUrl}\n";

// 2. In your actual backup script/command, ping on completion:
Http::get("{$pingUrl}/start");  // Signal start

try {
    // ... run your backup logic ...
    Http::get($pingUrl);             // Signal success
} catch (\Throwable $e) {
    Http::get("{$pingUrl}/fail");    // Signal failure
    throw $e;
}

List all down checks

PHP — Find failing checks
$response = Http::withToken($apiKey)
    ->get("{$baseUrl}/checks", ['per_page' => 100]);

$downChecks = collect($response->json('data'))
    ->filter(fn ($c) => $c['status'] === 'down');

foreach ($downChecks as $check) {
    echo "DOWN: {$check['name']} — last ping: {$check['last_ping_at']}\n";
}

Laravel Scheduler integration

app/Console/Kernel.php
// Laravel's built-in health check ping support
$schedule->command('backup:run')
    ->daily()
    ->pingBeforeIf(true, 'https://watchcron.com/ping/YOUR-UUID/start')
    ->thenPing('https://watchcron.com/ping/YOUR-UUID')
    ->pingOnFailure('https://watchcron.com/ping/YOUR-UUID/fail');

// Multiple tasks, each with its own check
$schedule->command('emails:send')
    ->everyFiveMinutes()
    ->thenPing('https://watchcron.com/ping/EMAIL-CHECK-UUID');

$schedule->command('reports:generate')
    ->weeklyOn(1, '8:00')
    ->thenPing('https://watchcron.com/ping/REPORT-CHECK-UUID');

Python

Using the requests library. Install with pip install requests.

Full workflow: create, ping, and check status

Python — Complete API workflow
import os
import requests

API_KEY = os.environ["WATCHCRON_API_KEY"]
BASE_URL = "https://watchcron.com/api/v1"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}


def create_check(name, cron_expr, grace=300, tags=None):
    """Create a new cron job check."""
    resp = requests.post(
        f"{BASE_URL}/checks",
        headers=HEADERS,
        json={
            "name": name,
            "schedule_type": "cron",
            "cron_expression": cron_expr,
            "grace_seconds": grace,
            "tags": tags or [],
        },
    )
    resp.raise_for_status()
    return resp.json()["data"]


def list_checks(tag=None):
    """List all checks, optionally filtered by tag."""
    params = {}
    if tag:
        params["tag"] = tag
    resp = requests.get(
        f"{BASE_URL}/checks",
        headers=HEADERS,
        params=params,
    )
    resp.raise_for_status()
    return resp.json()["data"]


def ping_check(ping_url, signal="success"):
    """Send a ping signal. signal: 'success', 'start', or 'fail'."""
    url = ping_url
    if signal == "start":
        url += "/start"
    elif signal == "fail":
        url += "/fail"
    requests.get(url, timeout=10)


# Usage
check = create_check("ETL Pipeline", "0 */6 * * *", tags=["etl"])
print(f"Created: {check['name']} — {check['ping_url']}")

# In your ETL script:
ping_check(check["ping_url"], "start")
try:
    # ... run ETL ...
    ping_check(check["ping_url"])
except Exception:
    ping_check(check["ping_url"], "fail")
    raise

Decorator pattern for automatic monitoring

Python — Decorator for cron job monitoring
import functools
import requests


def watchcron(ping_url):
    """Decorator that pings WatchCron on success/failure."""
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            requests.get(f"{ping_url}/start", timeout=10)
            try:
                result = func(*args, **kwargs)
                requests.get(ping_url, timeout=10)
                return result
            except Exception:
                requests.get(f"{ping_url}/fail", timeout=10)
                raise
        return wrapper
    return decorator


@watchcron("https://watchcron.com/ping/YOUR-UUID")
def run_backup():
    # Your backup logic here
    print("Backup completed")

Node.js

Using the built-in fetch API (Node.js 18+). No external dependencies needed.

API client helper

Node.js — WatchCron API client
const API_KEY = process.env.WATCHCRON_API_KEY;
const BASE_URL = "https://watchcron.com/api/v1";

async function apiRequest(method, path, body = null) {
  const options = {
    method,
    headers: {
      "Authorization": `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
  };
  if (body) options.body = JSON.stringify(body);

  const resp = await fetch(`${BASE_URL}${path}`, options);
  if (!resp.ok) {
    const err = await resp.json().catch(() => ({}));
    throw new Error(`API error ${resp.status}: ${err.error || resp.statusText}`);
  }
  if (resp.status === 204) return null;
  return resp.json();
}

// Create a check
const { data: check } = await apiRequest("POST", "/checks", {
  name: "Queue Worker Health",
  schedule_type: "simple",
  period_seconds: 300,
  grace_seconds: 120,
  tags: ["workers"],
});
console.log(`Ping URL: ${check.ping_url}`);

// List all checks
const { data: checks } = await apiRequest("GET", "/checks?per_page=100");
console.log(`Total checks: ${checks.length}`);

// Pause a check during deployment
await apiRequest("PATCH", `/checks/${check.uuid}/pause`, { paused: true });

// Resume after deployment
await apiRequest("PATCH", `/checks/${check.uuid}/pause`, { paused: false });

Go

Create check and send pings

Go — Complete example
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "net/http"
    "os"
)

const baseURL = "https://watchcron.com/api/v1"

func main() {
    apiKey := os.Getenv("WATCHCRON_API_KEY")

    // Create a check
    payload, _ := json.Marshal(map[string]any{
        "name":            "Log Rotation",
        "schedule_type":   "cron",
        "cron_expression": "0 0 * * 0",
        "grace_seconds":   1800,
    })

    req, _ := http.NewRequest("POST", baseURL+"/checks",
        bytes.NewBuffer(payload))
    req.Header.Set("Authorization", "Bearer "+apiKey)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    defer resp.Body.Close()

    var result struct {
        Data struct {
            UUID    string `json:"uuid"`
            PingURL string `json:"ping_url"`
        } `json:"data"`
    }
    json.NewDecoder(resp.Body).Decode(&result)

    fmt.Printf("Created: %s\nPing URL: %s\n",
        result.Data.UUID, result.Data.PingURL)

    // Send a ping (no auth needed)
    http.Get(result.Data.PingURL)
}

Ruby

Ruby — Create and monitor a check
require "net/http"
require "json"
require "uri"

API_KEY  = ENV["WATCHCRON_API_KEY"]
BASE_URL = "https://watchcron.com/api/v1"

def api_request(method, path, body = nil)
  uri = URI("#{BASE_URL}#{path}")
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true

  request = case method
    when :get    then Net::HTTP::Get.new(uri)
    when :post   then Net::HTTP::Post.new(uri)
    when :put    then Net::HTTP::Put.new(uri)
    when :patch  then Net::HTTP::Patch.new(uri)
    when :delete then Net::HTTP::Delete.new(uri)
  end

  request["Authorization"] = "Bearer #{API_KEY}"
  request["Content-Type"]  = "application/json"
  request.body = body.to_json if body

  response = http.request(request)
  JSON.parse(response.body) unless response.code == "204"
end

# Create a check
result = api_request(:post, "/checks", {
  name: "Sidekiq Health",
  schedule_type: "simple",
  period_seconds: 600,
  grace_seconds: 180,
})

puts "Ping URL: #{result['data']['ping_url']}"

# List all checks
checks = api_request(:get, "/checks")
checks["data"].each do |c|
  puts "#{c['name']}: #{c['status']}"
end

Bash / Shell

Manage checks from the command line

Bash — API management examples
#!/bin/bash
API_KEY="YOUR_API_KEY"
BASE="https://watchcron.com/api/v1"

# List all checks (formatted with jq)
curl -s -H "Authorization: Bearer $API_KEY" \
     "$BASE/checks" | jq '.data[] | {name, status, last_ping_at}'

# Create a check
curl -s -X POST "$BASE/checks" \
     -H "Authorization: Bearer $API_KEY" \
     -H "Content-Type: application/json" \
     -d '{
       "name": "Weekly Report",
       "schedule_type": "cron",
       "cron_expression": "0 9 * * 1",
       "grace_seconds": 3600
     }' | jq '.data.ping_url'

# Pause all checks tagged "staging" during deployment
curl -s -H "Authorization: Bearer $API_KEY" \
     "$BASE/checks?tag=staging&per_page=100" \
     | jq -r '.data[].uuid' \
     | while read uuid; do
         curl -s -X PATCH "$BASE/checks/$uuid/pause" \
              -H "Authorization: Bearer $API_KEY" \
              -H "Content-Type: application/json" \
              -d '{"paused": true}'
         echo "Paused: $uuid"
       done

Deployment automation

Pause monitoring during deploys to avoid false alerts, then resume when the deploy completes.

deploy.sh — Pause checks during deployment
#!/bin/bash
API_KEY="YOUR_API_KEY"
BASE="https://watchcron.com/api/v1"
CHECK_UUID="your-check-uuid-here"

echo "Pausing monitoring..."
curl -s -X PATCH "$BASE/checks/$CHECK_UUID/pause" \
     -H "Authorization: Bearer $API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"paused": true}'

echo "Deploying..."
# ... your deploy commands ...

echo "Resuming monitoring..."
curl -s -X PATCH "$BASE/checks/$CHECK_UUID/pause" \
     -H "Authorization: Bearer $API_KEY" \
     -H "Content-Type: application/json" \
     -d '{"paused": false}'

echo "Deploy complete, monitoring resumed."

Paginating through all results

If you have more checks than fit on a single page, loop through pages until you've seen them all.

def get_all_checks():
    all_checks = []
    page = 1
    while True:
        resp = requests.get(
            f"{BASE_URL}/checks",
            headers=HEADERS,
            params={"page": page, "per_page": 100},
        )
        data = resp.json()
        all_checks.extend(data["data"])
        meta = data["meta"]["pagination"]
        if page >= meta["last_page"]:
            break
        page += 1
    return all_checks
async function getAllChecks() {
  const allChecks = [];
  let page = 1;

  while (true) {
    const resp = await fetch(
      `${BASE_URL}/checks?page=${page}&per_page=100`,
      { headers: { "Authorization": `Bearer ${API_KEY}` } }
    );
    const { data, meta } = await resp.json();
    allChecks.push(...data);
    if (page >= meta.pagination.last_page) break;
    page++;
  }

  return allChecks;
}
$allChecks = [];
$page = 1;

do {
    $response = Http::withToken($apiKey)
        ->get("{$baseUrl}/checks", [
            'page'     => $page,
            'per_page' => 100,
        ]);

    $data = $response->json();
    $allChecks = array_merge($allChecks, $data['data']);
    $lastPage = $data['meta']['pagination']['last_page'];
    $page++;
} while ($page <= $lastPage);