Docs/API

Monitors

Monitors are the core resource in Oh Dear. Each monitor tracks a URL or hostname and runs checks against it. You can monitor websites (HTTP), servers (ping), TCP ports, and use AI to verify page content.

You'll need a team_id to create monitors -- see the user info endpoint to find your teams.

Example request:

$ OHDEAR_TOKEN="your API token"
$ curl https://ohdear.app/api/monitors/99 \
    -H "Authorization: Bearer $OHDEAR_TOKEN" \
    -H 'Accept: application/json' \
    -H 'Content-Type: application/json'

All endpoints below follow the same authentication pattern.

Get a specific monitor #

GET /api/monitors/{monitorId}

Retrieve a single monitor by its ID.

The resulting response is a single monitor object:

{
  "id": 99,
  "team_id": 1,
  "type": "http",
  "url": "https://example.com",
  "uses_https": true,
  "sort_url": "example.com",
  "label": "example.com",
  "group_name": "",
  "tags": [],
  "description": null,
  "notes": null,
  "latest_run_date": "2019-09-16 07:29:02",
  "summarized_check_result": "succeeded",
  "checks": [
    {
      "id": 100,
      "type": "uptime",
      "label": "Uptime",
      "enabled": true,
      "latest_run_ended_at": "2019-09-16 07:29:02",
      "latest_run_result": "succeeded",
      "summary": "Up",
      "settings": {
        "location": "paris",
        "look_for_string": "",
        "absent_string": null,
        "expected_response_headers": [],
        "failed_notification_threshold": 2,
        "http_verb": "get",
        "payload": [],
        "timeout": 5,
        "valid_status_codes": ["2*"],
        "max_redirect_count": 5,
        "expected_final_redirect_url": null,
        "http_client_headers": []
      },
      "active_snooze": null
    }
  ],
  "uptime_check_settings": {
    "location": "paris",
    "look_for_string": "",
    "absent_string": null,
    "expected_response_headers": [],
    "failed_notification_threshold": 2,
    "http_verb": "get",
    "payload": [],
    "timeout": 5,
    "valid_status_codes": ["2*"],
    "max_redirect_count": 5,
    "expected_final_redirect_url": null,
    "http_client_headers": []
  },
  "certificate_health_check_settings": {
    "expires_soon_threshold_in_days": null
  },
  "broken_links_check_settings": {
    "whitelisted_urls": [],
    "check_include_external_links": false,
    "types": ["link", "image", "script", "stylesheet", "og:image"],
    "do_not_crawl_urls": [],
    "force_crawl_urls": [],
    "new_links_only": false
  },
  "dns_check_settings": {
    "extra_cnames": [],
    "monitor_main_domain": false,
    "ignored_record_types": ["SOA"],
    "check_nameservers_in_sync": true
  },
  "lighthouse_check_settings": {
    "continent": "europe",
    "device_emulation": "desktop",
    "notification_settings": null,
    "http_client_headers": []
  },
  "application_health_check_settings": {
    "result_url": null,
    "secret": "your-secret-key",
    "headers": []
  },
  "domain_check_settings": {
    "not_supported_reason": null,
    "expires_soon_threshold_in_days": null
  },
  "performance_check_settings": {
    "threshold_in_ms": 3500,
    "change_percentage": 50
  },
  "sitemap_check_settings": {
    "path": "sitemap.xml",
    "speed": "default"
  },
  "ports_check_settings": {
    "expected_open_ports": [80, 443],
    "expected_closed_ports": [22, 3306],
    "timeout_per_port_ms": 3000,
    "failure_threshold": 2
  },
  "dns_blocklist_check_settings": {
    "use_all_blocklists": true,
    "enabled_blocklists": []
  },
  "ai_check_settings": null,
  "crawler_headers": [],
  "send_report_to_emails": [],
  "include_check_types_in_report": [],
  "badge_id": "badge-123",
  "marked_for_deletion_at": null,
  "created_at": "2019-09-16 07:25:00",
  "updated_at": "2019-09-16 07:25:00"
}

Get a specific monitor by URL #

GET /api/monitors/url/{monitorUrl}

Retrieve a monitor by its exact URL. The value should be URL-encoded.

Returns the same monitor object as the ID-based endpoint.

Get all monitors in your account #

GET /api/monitors

Lists all your monitors. Each item follows the same shape as the single monitor response above.

Notice that the uptime_check_settings shape depends on the monitor type. Here's a response showing all three types:

{
  "data": [
    {
      "id": 1,
      "type": "http",
      "url": "https://freek.dev",
      "summarized_check_result": "succeeded",
      "uptime_check_settings": {
        "location": "paris",
        "http_verb": "get",
        "timeout": 5,
        "valid_status_codes": ["2*"],
        "..."
      },
      "..."
    },
    {
      "id": 2,
      "type": "ping",
      "url": "spatie.be",
      "summarized_check_result": "succeeded",
      "uptime_check_settings": {
        "location": "paris",
        "ttl": 64,
        "count": 5,
        "packet_size_in_bytes": 56,
        "acceptable_packet_loss_percentage": 0,
        "acceptable_average_response_time_in_ms": 400,
        "..."
      },
      "..."
    },
    {
      "id": 3,
      "type": "tcp",
      "url": "smtp.gmail.com:3306",
      "summarized_check_result": "succeeded",
      "uptime_check_settings": {
        "location": "paris",
        "tcp_send_string": "",
        "timeout_in_ms": 1000,
        "look_for_string_in_welcome_message": "",
        "..."
      },
      "..."
    }
  ],
  "links": { "..." },
  "meta": { "..." }
}

The three monitor types are:

  1. HTTP Monitor (type: "http"): Monitors websites with comprehensive checks including uptime, performance, certificate health, broken links, mixed content, lighthouse, DNS, domain expiration, and more.
  2. Ping Monitor (type: "ping"): Monitors server availability using ICMP ping. Only has uptime checks with different settings (TTL, packet size, packet loss percentage, etc.).
  3. TCP Port Monitor (type: "tcp"): Monitors specific TCP port availability (like MySQL, SMTP). Has uptime checks with TCP-specific settings like connection strings and timeouts.

Each monitor type has different available checks and settings. More on each check in our dedicated checks page.

Monitor properties #

The response gives you comprehensive details for each monitor. Here are the properties:

Core properties #

  • id: Unique internal identifier for the monitor
  • team_id: Every monitor belongs to a Team. This is the team's ID. Since you can belong to multiple teams, the corresponding team ID will be shown for every monitor.
  • type: The monitor type -- "http" for websites, "ping" for ICMP ping monitoring, "tcp" for TCP port monitoring, or "ai" for AI verification monitors
  • url: The URL/hostname you submitted to Oh Dear (includes protocol for HTTP monitors, hostname for ping, hostname:port for TCP, and the target URL for AI monitors)
  • uses_https: Boolean indicating whether it uses HTTPS (mainly relevant for HTTP monitors)
  • sort_url: The URL without protocol and www. prefix, used for sorting
  • label: Display name for the monitor (defaults to sort_url if no custom name provided)
  • group_name: Name of the group this monitor belongs to (empty string if ungrouped)
  • tags: Array of tag names associated with this monitor
  • description: Optional description for the monitor
  • notes: Custom notes for the monitor
  • latest_run_date: Timestamp (UTC) of when any check for this monitor last ran
  • summarized_check_result: Overall monitor health. Possible values: "succeeded", "warning", "failed", "pending" -- see summarized check results

Checks array #

  • checks: Array of all checks configured for this monitor. Each check includes:
    • id: Unique identifier for the check
    • type: Check type (uptime, performance, certificate_health, broken_links, mixed_content, lighthouse, cron, application_health, sitemap, dns, domain, ai, ports, dns_blocklist)
    • label: Human-readable label for the check
    • enabled: Whether this check is currently active
    • latest_run_ended_at: When this specific check last completed (UTC)
    • latest_run_result: Result of the last run (succeeded, failed, warning, pending, errored-or-timed-out)
    • summary: Human-readable summary of the current status
    • settings: Check-specific configuration (varies by check type)
    • active_snooze: Information about any active notification snoozing

Monitor type-specific settings #

Depending on the monitor type, different settings objects are included:

HTTP Monitors (type: "http"):

  • uptime_check_settings: HTTP-specific uptime settings
    • location: Server location for checks (e.g., "paris")
    • look_for_string: Text that must be present in response
    • absent_string: Text that must NOT be present in response
    • expected_response_headers: Headers that must be present (with conditions)
    • failed_notification_threshold: How many failures before alerting
    • http_verb: HTTP method to use ("get", "post", etc.)
    • payload: Request body for POST/PUT requests
    • timeout: Request timeout in seconds
    • valid_status_codes: Array of acceptable HTTP status codes (e.g., ["2*", "3*"])
    • max_redirect_count: Maximum redirects to follow
    • expected_final_redirect_url: Expected final URL after redirects
    • http_client_headers: Custom headers to send with requests

Ping Monitors (type: "ping"):

  • uptime_check_settings: ICMP ping settings
    • location: Server location for checks
    • ttl: Time-to-live for ping packets
    • count: Number of ping packets to send
    • packet_size_in_bytes: Size of each ping packet
    • acceptable_packet_loss_percentage: Maximum acceptable packet loss
    • acceptable_average_response_time_in_ms: Maximum acceptable average response time
    • timeout_in_seconds: Timeout for each ping
    • interval_in_seconds: Interval between pings
    • failed_notification_threshold: How many failures before alerting

TCP Monitors (type: "tcp"):

  • uptime_check_settings: TCP connection settings
    • location: Server location for checks
    • tcp_send_string: String to send after connecting
    • timeout_in_ms: Connection timeout in milliseconds
    • look_for_string_in_welcome_message: Text to look for in initial server response
    • look_for_string_in_send_string_response: Text to look for in response to sent string
    • failed_notification_threshold: How many failures before alerting

Check-specific settings objects #

All monitors include these settings objects (even if the checks are disabled):

  • certificate_health_check_settings: SSL certificate monitoring
    • expires_soon_threshold_in_days: Days before expiration to warn
  • broken_links_check_settings: Broken link detection
    • whitelisted_urls: URLs to ignore if broken
    • check_include_external_links: Whether to check external links
    • types: Link types to check (["link", "image", "script", "stylesheet", "og:image"])
    • do_not_crawl_urls: URLs to exclude from crawling (currently returned in responses; not accepted in create/update payload validation)
    • force_crawl_urls: URLs to always crawl
    • new_links_only: Only check newly discovered links
  • dns_check_settings: DNS monitoring configuration
    • extra_cnames: Additional CNAME records to monitor
    • monitor_main_domain: Whether to monitor the main domain
    • ignored_record_types: DNS record types to ignore (e.g., ["SOA"])
    • check_nameservers_in_sync: Whether to verify nameservers are synchronized
  • lighthouse_check_settings: Performance audit configuration
    • continent: Geographic region for testing ("europe", "north-america", "asia")
    • device_emulation: Device to emulate ("desktop" or "mobile")
    • notification_settings: Custom notification thresholds
    • http_client_headers: Custom headers for the audit
  • application_health_check_settings: Custom application health endpoint
    • result_url: URL of your health check endpoint
    • secret: Secret token for authentication
    • headers: Custom headers to send
  • domain_check_settings: Domain expiration monitoring
    • not_supported_reason: Why domain monitoring isn't available (if applicable)
    • expires_soon_threshold_in_days: Days before expiration to warn
  • performance_check_settings: Response time monitoring
    • threshold_in_ms: Maximum acceptable response time
    • change_percentage: Percentage change threshold for alerts
  • sitemap_check_settings: Sitemap validation
    • path: Path to sitemap file (e.g., "sitemap.xml")
    • speed: Crawl speed ("default", "fast", "slow")
  • ports_check_settings: Port availability monitoring
    • expected_open_ports: Array of ports that should be open (max 20, values 1-65535)
    • expected_closed_ports: Array of ports that should be closed (max 20, values 1-65535)
    • timeout_per_port_ms: Timeout per port in milliseconds (500-10000)
    • failure_threshold: How many consecutive failures before alerting (default: 2)
  • dns_blocklist_check_settings: DNS blocklist monitoring
    • use_all_blocklists: Whether to check all available blocklists (default: true)
    • enabled_blocklists: Array of specific blocklist names to check (only used when use_all_blocklists is false)
  • ai_check_settings: AI verification monitoring (only for type: "ai" monitors)
    • prompt: The AI prompt used to verify the page content
    • frequency_unit / frequency_value: How often the AI check runs
    • suppress_repeated_success_notifications: Whether repeated success notifications are suppressed
    • throttle_failed_interval_unit / throttle_failed_interval_value: Failure notification throttling interval
    • html_stripping_level: How much HTML to strip before sending to AI ("basic", "aggressive", or "none")
    • location and wizard_* fields may also be present in responses

Additional properties #

  • crawler_headers: Custom headers sent during crawling operations
  • send_report_to_emails: Email addresses that receive the monthly reports
  • include_check_types_in_report: Which check types are included in monthly reports
  • badge_id: Unique identifier for status badge integration
  • marked_for_deletion_at: Timestamp (UTC) if monitor is scheduled for deletion
  • created_at: When the monitor was created (UTC)
  • updated_at: When the monitor was last modified (UTC)

Add a monitor through the API #

POST /api/monitors

Create a new monitor and start monitoring immediately.

Request body (JSON):

  • url (string, required) -- the URL/hostname to monitor
  • team_id (integer, required) -- the team this monitor belongs to. See user info to find your teams.
  • type (string, required) -- "http" for websites, "ping" for ICMP ping, "tcp" for TCP port, or "ai" for AI verification
  • checks (array, optional) -- array of check types to enable. If omitted, the default checks for the monitor type will be enabled.
{
  "url": "https://example.com",
  "team_id": "1",
  "type": "http"
}

Returns a monitor object with all checks set to "pending".

Add a monitor with enabled checks #

When creating a monitor you can control which checks get enabled by passing an array of check types.

Here's an example payload where only the uptime and mixed_content checks are enabled:

{
  "url": "https://mybrandnewsite.tld",
  "team_id": "1",
  "type": "http",
  "checks": ["uptime", "mixed_content"]
}

For more details on each check, have a look at the checks API endpoint.

Add a monitor with custom settings #

You can pass additional parameters to control the settings of a monitor. You can also control the monthly report settings using send_report_to_emails and include_check_types_in_report.

Please be aware:

  • application_health_check_settings.secret should not be present if you want to generate a random secret
  • default values will be used for any settings not present in the payload
  • we suggest only adding settings you want to change from the defaults

Here's the full payload with all possible settings:

{
  "url": "https://ohdear.app/docs",
  "team_id": 1,
  "type": "http",
  "checks": [
    "uptime",
    "performance",
    "broken_links",
    "mixed_content",
    "lighthouse",
    "cron",
    "application_health",
    "sitemap",
    "dns",
    "domain",
    "certificate_health",
    "ports",
    "dns_blocklist"
  ],
  "group_name": "Internal",
  "friendly_name": "Documentation",
  "tags": ["internal", "production", "docs"],
  "notes": "Internal notes for our team members",
  "description": "Oh Dear documentation",
  "uptime_check_settings": {
    "location": "paris",
    "expected_final_redirect_url": "https://redirect-to-this-url.com",
    "failed_notification_threshold": 2,
    "http_verb": "get",
    "timeout": 5,
    "max_redirect_count": 5,
    "payload": [
      {
        "name": "payload-name-1",
        "value": "payload-value-1"
      }
    ],
    "valid_status_codes": ["2*"],
    "look_for_string": null,
    "absent_string": null,
    "expected_response_headers": [
      {
        "name": "my-response-header",
        "condition": "equals",
        "value": "my-response-value"
      }
    ],
    "http_client_headers": [
      {
        "name": "my-header",
        "value": "my-value"
      }
    ]
  },
  "performance_check_settings": {
    "threshold_in_ms": 3500,
    "change_percentage": 50
  },
  "crawler_settings": {
    "headers": [
      {
        "name": "my-broken-links-header",
        "value": "my-broken-links-value"
      }
    ]
  },
  "broken_links_check_settings": {
    "whitelisted_urls": [],
    "check_include_external_links": false,
    "types": ["link", "image", "script", "stylesheet", "og:image"],
    "force_crawl_urls": [],
    "new_links_only": false
  },
  "sitemap_check_settings": {
    "path": "/sitemap.xml",
    "speed": "slow"
  },
  "application_health_check_settings": {
    "result_url": "https://mybrandnewsite.tld/health",
    "headers": [
      {"name": "my-header", "value": "my-value"}
    ]
  },
  "certificate_health_check_settings": {
    "expires_soon_threshold_in_days": 14
  },
  "dns_check_settings": {
    "extra_cnames": ["cname1", "cname2"],
    "monitor_main_domain": false,
    "ignored_record_types": ["A", "CNAME"],
    "check_nameservers_in_sync": true
  },
  "domain_check_settings": {
    "expires_soon_threshold_in_days": 30
  },
  "lighthouse_check_settings": {
    "continent": "europe",
    "device_emulation": "desktop"
  },
  "ports_check_settings": {
    "expected_open_ports": [80, 443],
    "expected_closed_ports": [22, 3306],
    "timeout_per_port_ms": 3000
  },
  "send_report_to_emails": [
    "[email protected]",
    "[email protected]"
  ],
  "include_check_types_in_report": [
    "uptime",
    "performance",
    "broken_links",
    "mixed_content",
    "lighthouse",
    "cron",
    "application_health",
    "sitemap",
    "dns",
    "domain",
    "certificate_health",
    "ports",
    "dns_blocklist"
  ]
}

Error handling #

If an error occurred, you'll be given a non-HTTP/200 response code. The resulting payload might look like this:

{
  "message": "The given data was invalid.",
  "errors": {
    "url": ["The url field is required."],
    "team_id": ["The team id field is required."]
  }
}

If you've got both the url and the team_id in your payload, but the data is invalid, you'll get a detailed error message:

{
  "message": "The given data was invalid.",
  "errors": {
    "url": ["You should enter a url that starts with either \"http://\" or \"https://\"."],
    "team_id": ["You do not belong to that team."]
  }
}

Updating monitor settings #

PUT /api/monitors/{monitorId}

All fields are optional -- only include what you want to change.

The payload accepts the same fields as creating a monitor with custom settings with the following differences:

  • url is not required (but can be updated if needed)
  • team_id is not allowed as a monitor cannot be moved between teams
  • type is not allowed as a monitor's type cannot be changed after creation

Returns the updated monitor object.

Deleting a monitor #

DELETE /api/monitors/{monitorId}

Deletes the specified monitor and all its checks.

Returns 204 No Content on success.

POST /api/monitors/{monitorId}/add-to-broken-links-whitelist

Add a single URL to the broken links whitelist. This is primarily used to quickly whitelist a single URL from an overview screen.

Request body (JSON):

  • whitelistUrl (string, required) -- the URL to add to the whitelist
{
  "whitelistUrl": "https://externalsite.tld/page1"
}

For bulk whitelist management, use the update endpoint with the broken_links_check_settings.whitelisted_urls field.

Modifying individual monitor settings #

Use the update endpoint with only the fields you want to change. You don't need to send the full payload.

For example, to enable external link checking:

{
  "broken_links_check_settings": {
    "check_include_external_links": true,
    "whitelisted_urls": ["https://externalsite.tld/page1", "https://externalsite.tld/page2"]
  }
}

Or to update the uptime check payload:

{
  "uptime_check_settings": {
    "payload": [{"name": "my-name", "value": "my-value"}]
  }
}
Was this page helpful?

Feel free to reach out via [email protected] or on X via @OhDearApp if you have any other questions. We'd love to help!