Cron Jobs

Create and manage cron job monitors, and record pings from your scheduled jobs.

Cron job monitors track scheduled tasks by receiving pings when jobs complete. If a ping is not received within the expected window, the job is marked as late and alerts are triggered.

GET /api/v1/cron-jobs

Returns the cron job monitors for your team. This endpoint is paginated; see Pagination for how to page through the full list.

Required scope: cron-jobs:read

Query Parameters

  • perPageinteger

    Results per page, 1-200 (default: 50)

  • cursorstring

    Page to fetch, taken from a Link header

The cursors for this page arrive in meta.pagination:

  • meta.pagination.nextstring | null

    Cursor for the following page, null on the last

  • meta.pagination.prevstring | null

    Cursor for the preceding page, null on the first

  • meta.pagination.perPageinteger

    Results this page was built with

  • meta.pagination.totalinteger

    Cron jobs matching, across every page

Errors (3)
StatusTypeMeaning
400bad-requestThe request is malformed
401unauthorizedThe API key is missing or invalid
403forbiddenThe API key lacks the required scope
Response fields (200)
  • dataobjectRequired
    Show nested fields
    • cronJobsCronJob[]Required
      Show nested fields
      • idstringRequired
      • namestringRequired
      • descriptionstring | nullRequired
      • cronExpressionstringRequired

        Stored normalized

      • gracePeriodSecondsintegerRequired
      • timezonestringRequired

        IANA time zone the schedule runs in

      • statusstringRequired

        One of healthy, late, missed, new.

      • alertOnLatebooleanRequired
      • lastPingAtinteger | nullRequired

        Epoch milliseconds

      • nextExpectedAtinteger | nullRequired

        Epoch milliseconds

      • enabledAtinteger | nullRequired

        When enabled; null if disabled

      • createdAtintegerRequired

        Epoch milliseconds

      • updatedAtintegerRequired

        Epoch milliseconds

  • metaobjectRequired
    Show nested fields
    • requestIdstringRequired

      Format: uuid.

    • timestampstringRequired

      Format: date-time.

    • paginationobjectRequired
      Show nested fields
      • nextstring | nullRequired

        Cursor of the following page

      • prevstring | nullRequired

        Cursor of the preceding page

      • perPageintegerRequired
      • totalinteger

cURL

Terminal
curl "https://uptime.sergiodxa.com/api/v1/cron-jobs?perPage=25" \
  -H "Authorization: Bearer uptime_your_api_key"
request.js
let response = await fetch("https://uptime.sergiodxa.com/api/v1/cron-jobs?perPage=25", {
	headers: {
		"Authorization": "Bearer uptime_your_api_key",
	},
});
let result = await response.json();

Response

json
{
	"data": {
		"cronJobs": [
			{
				"id": "cron_abc123",
				"name": "Daily Backup",
				"description": "Runs database backup every night",
				"cronExpression": "0 2 * * *",
				"gracePeriodSeconds": 300,
				"timezone": "America/New_York",
				"status": "healthy",
				"alertOnLate": true,
				"lastPingAt": 1771052412000,
				"nextExpectedAt": 1771138800000,
				"enabledAt": 1768055400000,
				"createdAt": 1768055400000,
				"updatedAt": 1770282900000
			}
		]
	},
	"meta": {
		"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
		"timestamp": "2026-02-14T12:00:00.000Z",
		"pagination": {
			"next": "eyJkIjoiYWZ0ZXIi",
			"prev": null,
			"perPage": 25,
			"total": 34
		}
	}
}

POST /api/v1/cron-jobs

Creates a new cron job monitor and answers 201 Created.

Required scope: cron-jobs:write

Request Body

  • namestringRequired

    Display name (1-100 characters)

  • cronExpressionstringRequired

    Valid cron expression (e.g., 0 * * * *)

  • descriptionstring

    Optional description (max 500 characters)

  • gracePeriodSecondsinteger

    Seconds to wait before marking late (60-86400, default 300)

  • timezonestring

    IANA timezone, or UTC (default UTC). Any other value is rejected with a validation-error problem.

  • alertOnLateboolean

    Send alerts when job is late (default false)

  • enabledboolean

    Whether the monitor is active (default true)

Errors (6)
StatusTypeMeaning
400validation-errorThe request failed validation
400idempotency-key-invalidThe Idempotency-Key header is not valid
401unauthorizedThe API key is missing or invalid
403forbiddenThe API key lacks the required scope
409idempotency-key-in-useA request with this idempotency key is still being processed
422idempotency-key-reusedThis idempotency key was already used for a different request
Response fields (201)
  • dataobjectRequired
    Show nested fields
    • cronJobobjectRequired
      Show nested fields
      • idstringRequired
      • namestringRequired
      • descriptionstring | nullRequired
      • cronExpressionstringRequired

        Stored normalized

      • gracePeriodSecondsintegerRequired
      • timezonestringRequired

        IANA time zone the schedule runs in

      • statusstringRequired

        One of healthy, late, missed, new.

      • alertOnLatebooleanRequired
      • lastPingAtinteger | nullRequired

        Epoch milliseconds

      • nextExpectedAtinteger | nullRequired

        Epoch milliseconds

      • enabledAtinteger | nullRequired

        When enabled; null if disabled

      • createdAtintegerRequired

        Epoch milliseconds

      • updatedAtintegerRequired

        Epoch milliseconds

  • metaobjectRequired
    Show nested fields
    • requestIdstringRequired

      Format: uuid.

    • timestampstringRequired

      Format: date-time.

cURL

Terminal
curl -X POST https://uptime.sergiodxa.com/api/v1/cron-jobs \
  -H "Authorization: Bearer uptime_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Daily Backup",
    "cronExpression": "0 2 * * *",
    "description": "Runs database backup every night",
    "gracePeriodSeconds": 600,
    "timezone": "America/New_York",
    "alertOnLate": true
  }'
request.js
let response = await fetch("https://uptime.sergiodxa.com/api/v1/cron-jobs", {
	method: "POST",
	headers: {
		"Authorization": "Bearer uptime_your_api_key",
		"Content-Type": "application/json",
	},
	body: JSON.stringify({
		"name": "Daily Backup",
		"cronExpression": "0 2 * * *",
		"description": "Runs database backup every night",
		"gracePeriodSeconds": 600,
		"timezone": "America/New_York",
		"alertOnLate": true
	}),
});
let result = await response.json();

Response

json
{
	"data": {
		"cronJob": {
			"id": "cron_abc123",
			"name": "Daily Backup",
			"description": "Runs database backup every night",
			"cronExpression": "0 2 * * *",
			"gracePeriodSeconds": 600,
			"timezone": "America/New_York",
			"status": "new",
			"alertOnLate": true,
			"lastPingAt": null,
			"nextExpectedAt": 1771138800000,
			"enabledAt": 1771083000000,
			"createdAt": 1771083000000,
			"updatedAt": 1771083000000
		}
	},
	"meta": {
		"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
		"timestamp": "2026-02-14T12:00:00.000Z"
	}
}

GET /api/v1/cron-jobs/:id

Returns a single cron job monitor by ID.

Required scope: cron-jobs:read

Errors (4)
StatusTypeMeaning
400validation-errorThe request failed validation
401unauthorizedThe API key is missing or invalid
403forbiddenThe API key lacks the required scope
404not-foundThe resource does not exist
Response fields (200)
  • dataobjectRequired
    Show nested fields
    • cronJobobjectRequired
      Show nested fields
      • idstringRequired
      • namestringRequired
      • descriptionstring | nullRequired
      • cronExpressionstringRequired

        Stored normalized

      • gracePeriodSecondsintegerRequired
      • timezonestringRequired

        IANA time zone the schedule runs in

      • statusstringRequired

        One of healthy, late, missed, new.

      • alertOnLatebooleanRequired
      • lastPingAtinteger | nullRequired

        Epoch milliseconds

      • nextExpectedAtinteger | nullRequired

        Epoch milliseconds

      • enabledAtinteger | nullRequired

        When enabled; null if disabled

      • createdAtintegerRequired

        Epoch milliseconds

      • updatedAtintegerRequired

        Epoch milliseconds

  • metaobjectRequired
    Show nested fields
    • requestIdstringRequired

      Format: uuid.

    • timestampstringRequired

      Format: date-time.

cURL

Terminal
curl https://uptime.sergiodxa.com/api/v1/cron-jobs/cron_abc123 \
  -H "Authorization: Bearer uptime_your_api_key"
request.js
let response = await fetch("https://uptime.sergiodxa.com/api/v1/cron-jobs/cron_abc123", {
	headers: {
		"Authorization": "Bearer uptime_your_api_key",
	},
});
let result = await response.json();

Response

json
{
	"data": {
		"cronJob": {
			"id": "cron_abc123",
			"name": "Daily Backup",
			"description": "Runs database backup every night",
			"cronExpression": "0 2 * * *",
			"gracePeriodSeconds": 600,
			"timezone": "America/New_York",
			"status": "healthy",
			"alertOnLate": true,
			"lastPingAt": 1771052412000,
			"nextExpectedAt": 1771138800000,
			"enabledAt": 1768055400000,
			"createdAt": 1768055400000,
			"updatedAt": 1770282900000
		}
	},
	"meta": {
		"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
		"timestamp": "2026-02-14T12:00:00.000Z"
	}
}

PATCH /api/v1/cron-jobs/:id

Updates an existing cron job monitor with a JSON merge patch.

Required scope: cron-jobs:write

Request Body

All fields are optional, with the same limits as a create; only the ones you send change. null clears description and resets gracePeriodSeconds, timezone, alertOnLate and enabled to their defaults; name and cronExpression cannot be removed.

  • namestring

    Display name (1-100 characters)

  • cronExpressionstring

    Valid cron expression

  • descriptionstring

    Optional description (max 500 characters)

  • gracePeriodSecondsinteger

    Seconds to wait before marking late (60-86400)

  • timezonestring

    IANA timezone, or UTC. Any other value is rejected with a validation-error problem.

  • alertOnLateboolean

    Send alerts when job is late

  • enabledboolean

    Whether the monitor is active

Update With PUT

PUT /api/v1/cron-jobs/:id takes the same fields, for integrations written before PATCH existed. A field you leave out keeps its value, null is refused, enabled: true sets enabledAt to now on every request, and a cronExpression you send recomputes nextExpectedAt even when it is unchanged.

Required scope: cron-jobs:write

Errors (4)
StatusTypeMeaning
400validation-errorThe request failed validation
401unauthorizedThe API key is missing or invalid
403forbiddenThe API key lacks the required scope
404not-foundThe resource does not exist
Response fields (200)
  • dataobjectRequired
    Show nested fields
    • cronJobobjectRequired
      Show nested fields
      • idstringRequired
      • namestringRequired
      • descriptionstring | nullRequired
      • cronExpressionstringRequired

        Stored normalized

      • gracePeriodSecondsintegerRequired
      • timezonestringRequired

        IANA time zone the schedule runs in

      • statusstringRequired

        One of healthy, late, missed, new.

      • alertOnLatebooleanRequired
      • lastPingAtinteger | nullRequired

        Epoch milliseconds

      • nextExpectedAtinteger | nullRequired

        Epoch milliseconds

      • enabledAtinteger | nullRequired

        When enabled; null if disabled

      • createdAtintegerRequired

        Epoch milliseconds

      • updatedAtintegerRequired

        Epoch milliseconds

  • metaobjectRequired
    Show nested fields
    • requestIdstringRequired

      Format: uuid.

    • timestampstringRequired

      Format: date-time.

cURL

Terminal
curl -X PATCH https://uptime.sergiodxa.com/api/v1/cron-jobs/cron_abc123 \
  -H "Authorization: Bearer uptime_your_api_key" \
  -H "Content-Type: application/merge-patch+json" \
  -d '{
    "gracePeriodSeconds": 900,
    "alertOnLate": false
  }'
request.js
let response = await fetch("https://uptime.sergiodxa.com/api/v1/cron-jobs/cron_abc123", {
	method: "PATCH",
	headers: {
		"Authorization": "Bearer uptime_your_api_key",
		"Content-Type": "application/merge-patch+json",
	},
	body: JSON.stringify({
		"gracePeriodSeconds": 900,
		"alertOnLate": false
	}),
});
let result = await response.json();

Response

json
{
	"data": {
		"cronJob": {
			"id": "cron_abc123",
			"name": "Daily Backup",
			"description": "Runs database backup every night",
			"cronExpression": "0 2 * * *",
			"gracePeriodSeconds": 900,
			"timezone": "America/New_York",
			"status": "healthy",
			"alertOnLate": false,
			"lastPingAt": 1771052412000,
			"nextExpectedAt": 1771138800000,
			"enabledAt": 1768055400000,
			"createdAt": 1768055400000,
			"updatedAt": 1771087500000
		}
	},
	"meta": {
		"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
		"timestamp": "2026-02-14T12:00:00.000Z"
	}
}

DELETE /api/v1/cron-jobs/:id

Deletes a cron job monitor. This action cannot be undone.

Required scope: cron-jobs:delete

Errors (4)
StatusTypeMeaning
400validation-errorThe request failed validation
401unauthorizedThe API key is missing or invalid
403forbiddenThe API key lacks the required scope
404not-foundThe resource does not exist
Response fields (200)
  • dataobjectRequired
    Show nested fields
    • deletedtrueRequired
  • metaobjectRequired
    Show nested fields
    • requestIdstringRequired

      Format: uuid.

    • timestampstringRequired

      Format: date-time.

cURL

Terminal
curl -X DELETE https://uptime.sergiodxa.com/api/v1/cron-jobs/cron_abc123 \
  -H "Authorization: Bearer uptime_your_api_key"
request.js
let response = await fetch("https://uptime.sergiodxa.com/api/v1/cron-jobs/cron_abc123", {
	method: "DELETE",
	headers: {
		"Authorization": "Bearer uptime_your_api_key",
	},
});
let result = await response.json();

Response

json
{
	"data": {
		"deleted": true
	},
	"meta": {
		"requestId": "3f2504e0-4f89-11d3-9a0c-0305e82c3301",
		"timestamp": "2026-02-14T12:00:00.000Z"
	}
}

POST /api/v1/cron-jobs/:id/ping

Records a ping for a cron job monitor. Call this endpoint when your scheduled task completes successfully.

Like every other endpoint on this page, it requires an API key: send it as Authorization: Bearer <key>. A key reaches only the monitors of the team that owns it—pinging another team's monitor returns 404, exactly as an id that doesn't exist does, so the endpoint can't be used to discover which ids are real.

Because this URL lives in crontabs and deploy scripts, it also accepts the monitor's plain UUID in place of its cron_ id, so an address saved before the id got its prefix keeps working. Both forms name the same monitor and share the same rate limits. An id in neither form answers 404 not-found. Use the cron_ id shown by List Cron Jobs for anything new.

Rate Limits: Two limits apply, and both answer a 429 rate-limited problem with a Retry-After header giving the seconds to wait:

  • Caller budget: 60 requests per minute for each calling IP address (CF-Connecting-IP) and monitor pair, where every IPv6 address in one /64 network counts as one caller, counted whether or not the ping is accepted. It is spent before the API key is checked, so requests with a missing or invalid key count against it too. Responses from this limit also carry the quota headers.

  • Minimum interval: a monitor accepts one ping every 30 seconds. A ping that arrives sooner after the previous accepted one is rejected.

Required scope: cron-jobs:ping

Unlike the rest of /api/v1, this endpoint answers with the bare object above rather than the { data, meta } envelope, so a shell script can read the result without unwrapping it.

wasOnTime is true when the ping arrived within the job's grace period, and false when it arrived after it — a late ping is still recorded and still answers 201.

Errors (5)
StatusTypeMeaning
401unauthorizedThe API key is missing or invalid
403forbiddenThe API key lacks the required scope
404not-foundThe resource does not exist
409conflictThe resource's state prevents this request
429rate-limitedToo many requests
Response fields (201)
  • wasOnTimebooleanRequired

    False when the ping arrived after the grace period

cURL

Terminal
curl -X POST https://uptime.sergiodxa.com/api/v1/cron-jobs/cron_abc123/ping \
  -H "Authorization: Bearer uptime_your_api_key"
request.js
let response = await fetch("https://uptime.sergiodxa.com/api/v1/cron-jobs/cron_abc123/ping", {
	method: "POST",
	headers: {
		"Authorization": "Bearer uptime_your_api_key",
	},
});
let result = await response.json();

Response

Returns 201 Created:

json
{
	"wasOnTime": true
}

Response Fields

All cron job responses include these fields:

FieldTypeDescription
idstringUnique identifier (prefixed with cron_)
namestringDisplay name
descriptionstring | nullOptional description
cronExpressionstringCron schedule expression
gracePeriodSecondsintegerSeconds to wait before marking late
timezonestringIANA timezone for the schedule
statusstringCurrent status: healthy, late, missed, or new
alertOnLatebooleanWhether alerts are sent when the job is late
lastPingAtinteger | nullUnix timestamp in milliseconds of the last ping, or null if never
nextExpectedAtinteger | nullUnix timestamp in milliseconds of the next expected ping
enabledAtinteger | nullUnix timestamp in milliseconds when enabled, or null if disabled
createdAtintegerUnix timestamp in milliseconds when created
updatedAtintegerUnix timestamp in milliseconds when last updated
Documentation