LAST UPDATED on 20th August 2025
IMPORTANT CORRECTION: in some communication we incorrectly said we would launch our new API on Tuesday 23rd of August. That day/date does not exist. The correct date is Tuesday 26th of August
Generally speaking, we don't introduce any breaking changes to our API. On Tuesday 26th of August 2025 however, we will deploy a new version of Oh Dear in which "sites" will be renamed to "monitors" throughout the entire app. In this blog post, you'll learn why we are making this change.
This change also affects our API. In this document, we want to help you understand the changed and give instruction on how to upgrade to the latest version of our API and packages.
We are aware that breaking changes are no fun for you. We will do our utmost best to not introduce any more breaking changes in the foreseeable future.
Which changes will be introduced in our API
In Oh Dear "sites" will be renamed "monitors". This affects our API:
- The
/api/sites/
endpoint will be renamed to /api/monitors
- Every field / request parameter named
site_id
will be renamed to monitor_id
- The
/api/performance-records
endpoint will be replaced by /api/http-uptime-metrics
, /api/ping-uptime-metrics
and. /api/tcp-uptime-metrics
We've restructured how we store various parameters for our checks. When you retrieve a monitor from our API, you'll see new fields like uptime_check_settings
, broken_link_check_setttings
, ... that contains the settings for a check.
When creating or updating a monitor using our API, you can send along these settings fields as well to set or update the properties of a check.
Scheduled tasks monitoring
Our API is often used for syncing scheduled tasks to Oh Dear. That's why we'll keep supporting these existing endpoints:
GET /api/sites/<site_id>/cron-checks
POST /api/sites/<site_id>/cron-checks
POST /api/sites/<site_id>/cron-checks/sync
We will remove support for these endpoints on 1st of August 2026. By then, you should switch to using their /api/monitors/<monitor_id>
equivalents.
If you're using v3 of spatie/laravel-schedule-monitor
, it will still be able to fully sync your Laravel scheduled tasks to Oh Dear. We do encourage you to upgrade to v4. On 1st of August 2026, syncing your schedule using v3 of the package will not work anymore.
The API towards ping.ohdear.app
has not been changed at all, and will continue to work.
Updated packages
On Tuesday 26th of August we'll release a new major version our PHP SDK package and various other packages. On that date, the old versions will not work properly anymore because of the breaking API changes.
You'll find upgrade instructions in the UPGRADE.md
that's present in each repository.
Updating your packages before release 26th of August
If you are preparing the upgrade of the packages, you can already install the code as if it was a stable release.
To do this, add these two elements to your composer.json
"minimum-stability": "dev",
"prefer-stable": true
Next, you can install the newest version of any of our new packages.
# only install the packages needed
composer require ohdearapp/ohdear-php-sdk:^4.0
composer require spatie/laravel-schedule-monitor:^4.0
composer require ohdearapp/laravel-ohdear-webhooks:^2.0
These commands will actually pull in the code we have in our development branch.
After we have released our packages, you can simply remove the minimum-stability
and prefer-stable
keys and run
composer update
This will then pull in the actual released code.
The new monitors endpoint
On 26th of August we'll deploy a new /api/monitors
endpoint which replaces the old /api/sites
one. It will list all your monitors in your account.
$ OHDEAR_TOKEN="your API token"
$ curl https://ohdear.app/api/monitors \
-H "Authorization: Bearer $OHDEAR_TOKEN" \
-H 'Accept: application/json' \
-H 'Content-Type: application/json'
As a result, you get the details for every site you've added.
{
"data": [
{
"id": 1,
"team_id": 1,
"type": "http",
"url": "https://freek.dev",
"uses_https": true,
"sort_url": "freek.dev",
"label": "freek.dev",
"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": {
"uptime_check_location": "paris",
"uptime_check_expected_final_redirect_url": null,
"uptime_check_failed_notification_threshold": null,
"uptime_check_http_verb": null,
"uptime_check_timeout": null,
"uptime_check_max_redirect_count": null,
"uptime_check_payload": null,
"uptime_check_valid_status_codes": null,
"uptime_check_look_for_string": null,
"uptime_check_absent_string": null,
"uptime_check_expected_response_headers": null,
"http_client_headers": null
},
"active_snooze": null
},
{
"id": 101,
"type": "broken_links",
"label": "Broken links",
"enabled": true,
"latest_run_ended_at": "2019-09-16 07:29:05",
"latest_run_result": "succeeded",
"summary": "None",
"settings": {
"broken_links_check_include_external_links": null,
"broken_links_whitelisted_urls": null,
"crawler_headers": [],
"crawler_speed": "default",
"broken_link_types": null,
"respect_robots": true
},
"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",
"cpu_slowdown_modifier": 0,
"notification_settings": null,
"preferred_server_name": "lighthouse-checker-frankfurt-1",
"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"
},
"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"
},
{
"id": 2,
"team_id": 1,
"type": "ping",
"url": "spatie.be",
"uses_https": false,
"sort_url": "spatie.be",
"label": "spatie.be",
"group_name": "",
"tags": [],
"description": null,
"notes": null,
"latest_run_date": "2019-09-16 07:30:00",
"summarized_check_result": "succeeded",
"checks": [
{
"id": 200,
"type": "uptime",
"label": "Uptime",
"enabled": true,
"latest_run_ended_at": "2019-09-16 07:30:00",
"latest_run_result": "succeeded",
"summary": "Up",
"settings": {
"uptime_check_location": "paris",
"uptime_check_expected_final_redirect_url": null,
"uptime_check_failed_notification_threshold": null,
"uptime_check_http_verb": null,
"uptime_check_timeout": null,
"uptime_check_max_redirect_count": null,
"uptime_check_payload": null,
"uptime_check_valid_status_codes": null,
"uptime_check_look_for_string": null,
"uptime_check_absent_string": null,
"uptime_check_expected_response_headers": null,
"http_client_headers": null
},
"active_snooze": null
}
],
"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,
"timeout_in_seconds": 1,
"interval_in_seconds": 1,
"failed_notification_threshold": 2
},
"badge_id": "badge-456",
"created_at": "2019-09-16 07:26:00",
"updated_at": "2019-09-16 07:26:00"
},
{
"id": 3,
"team_id": 1,
"type": "tcp",
"url": "smtp.gmail.com:3306",
"uses_https": false,
"sort_url": "smtp.gmail.com:3306",
"label": "smtp.gmail.com:3306",
"group_name": "",
"tags": [],
"description": null,
"notes": null,
"latest_run_date": "2019-09-16 07:31:00",
"summarized_check_result": "succeeded",
"checks": [
{
"id": 300,
"type": "uptime",
"label": "Uptime",
"enabled": true,
"latest_run_ended_at": "2019-09-16 07:31:00",
"latest_run_result": "succeeded",
"summary": "Up",
"settings": {
"uptime_check_location": "paris",
"uptime_check_expected_final_redirect_url": null,
"uptime_check_failed_notification_threshold": null,
"uptime_check_http_verb": null,
"uptime_check_timeout": null,
"uptime_check_max_redirect_count": null,
"uptime_check_payload": null,
"uptime_check_valid_status_codes": null,
"uptime_check_look_for_string": null,
"uptime_check_absent_string": null,
"uptime_check_expected_response_headers": null,
"http_client_headers": null
},
"active_snooze": null
}
],
"uptime_check_settings": {
"location": "paris",
"tcp_send_string": "",
"timeout_in_ms": 1000,
"look_for_string_in_welcome_message": "",
"look_for_string_in_send_string_response": "",
"failed_notification_threshold": 2
},
"badge_id": "badge-789",
"created_at": "2019-09-16 07:27:00",
"updated_at": "2019-09-16 07:27:00"
}
],
"links": {
"first": "https://ohdear.app/api/monitors?page%5Bnumber%5D=1",
"last": "https://ohdear.app/api/monitors?page%5Bnumber%5D=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"from": 1,
"last_page": 1,
"path": "https://ohdear.app/api/monitors",
"per_page": 200,
"to": 3,
"total": 3
}
}
Let's drill this down, because the three monitors shown represent different monitor types:
-
HTTP Monitor (type: "http"
): This is an https://
website monitor that gets comprehensive monitoring including uptime, performance, certificate health, broken links, mixed content, lighthouse, DNS, domain expiration, etc.
-
Ping Monitor (type: "ping"
): This monitors server availability using ICMP ping. It only has uptime checks and uses different settings (TTL, packet size, packet loss percentage, etc.).
-
TCP Port Monitor (type: "tcp"
): This monitors specific TCP port availability (like MySQL, SMTP, etc.). It has uptime checks with TCP-specific settings like connection strings and timeouts.
Each monitor type has different available checks and settings based on what can be monitored. More on each check in our dedicated checks page.
Also notice that the content of the uptime_check_settings
depends on the type of monitor.
Get a specific monitor via the API
If you don't want to retrieve all monitors, you can get a specific monitor if you know its ID. The example below will get the details of monitor ID 99.
$ 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'
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": {
"uptime_check_location": "paris"
},
"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": []
},
"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"
}
Notice how this payload does not contain the data
wrapper (the API call to retrieve all monitors does).
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, or "tcp"
for TCP port monitoring
url
: The URL/hostname you submitted to Oh Dear (includes protocol for HTTP monitors, hostname for ping, hostname:port for TCP)
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 of when any check for this monitor last ran
summarized_check_result
: Overall monitor health - "succeeded"
, "warning"
, "failed"
, or "pending"
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
)
label
: Human-readable label for the check
enabled
: Whether this check is currently active
latest_run_ended_at
: When this specific check last completed
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
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
: Types of links to check (["link", "image", "script", "stylesheet", "og:image"])
do_not_crawl_urls
: URLs to exclude from crawling
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 (["SOA"])
check_nameservers_in_sync
: Whether to verify nameservers are synchronized
lighthouse_check_settings
: Performance audit configuration
continent
: Geographic region for testing ("europe", "america", etc.)
cpu_slowdown_modifier
: CPU throttling factor
notification_settings
: Custom notification thresholds
preferred_server_name
: Specific server to use for testing
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 ("sitemap.xml")
speed
: Crawl speed ("default", "fast", "slow")
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 if monitor is scheduled for deletion
created_at
: When the monitor was created
updated_at
: When the monitor was last modified