How do I update to the latest version of the Oh Dear API
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 tomonitor_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.
- ohdearapp/ohdear-php-sdk: this package has been rewritten from scratch. The new version is v4. We recommend reading the readme to learn about the exact changes. Our SDK is now based on Saloon, which unlocks deep customizations.
- ohdearapp/ohdear-pulse: you should upgrade to v2.
- ohdearapp/laravel-ohdear-webhooks: you should upgrade to v2.
- spatie/laravel-schedule-monitor: you should upgrade to v4.
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 anhttps://
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 monitorteam_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 monitoringurl
: 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 andwww.
prefix, used for sortinglabel
: 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 monitordescription
: Optional description for the monitornotes
: Custom notes for the monitorlatest_run_date
: Timestamp of when any check for this monitor last ransummarized_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 checktype
: Check type (uptime
,performance
,certificate_health
,broken_links
,mixed_content
,lighthouse
,cron
,application_health
,sitemap
,dns
,domain
)label
: Human-readable label for the checkenabled
: Whether this check is currently activelatest_run_ended_at
: When this specific check last completedlatest_run_result
: Result of the last run (succeeded
,failed
,warning
,pending
,errored-or-timed-out
)summary
: Human-readable summary of the current statussettings
: 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 settingslocation
: Server location for checks (e.g., "paris")look_for_string
: Text that must be present in responseabsent_string
: Text that must NOT be present in responseexpected_response_headers
: Headers that must be presentfailed_notification_threshold
: How many failures before alertinghttp_verb
: HTTP method to use ("get", "post", etc.)payload
: Request body for POST/PUT requeststimeout
: Request timeout in secondsvalid_status_codes
: Array of acceptable HTTP status codes (e.g., ["2*", "3*"])max_redirect_count
: Maximum redirects to followexpected_final_redirect_url
: Expected final URL after redirectshttp_client_headers
: Custom headers to send with requests
Ping Monitors (type: "ping"
):
uptime_check_settings
: ICMP ping settingslocation
: Server location for checksttl
: Time-to-live for ping packetscount
: Number of ping packets to sendpacket_size_in_bytes
: Size of each ping packetacceptable_packet_loss_percentage
: Maximum acceptable packet lossacceptable_average_response_time_in_ms
: Maximum acceptable average response timetimeout_in_seconds
: Timeout for each pinginterval_in_seconds
: Interval between pingsfailed_notification_threshold
: How many failures before alerting
TCP Monitors (type: "tcp"
):
uptime_check_settings
: TCP connection settingslocation
: Server location for checkstcp_send_string
: String to send after connectingtimeout_in_ms
: Connection timeout in millisecondslook_for_string_in_welcome_message
: Text to look for in initial server responselook_for_string_in_send_string_response
: Text to look for in response to sent stringfailed_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 monitoringexpires_soon_threshold_in_days
: Days before expiration to warn
broken_links_check_settings
: Broken link detectionwhitelisted_urls
: URLs to ignore if brokencheck_include_external_links
: Whether to check external linkstypes
: Types of links to check (["link", "image", "script", "stylesheet", "og:image"])do_not_crawl_urls
: URLs to exclude from crawlingforce_crawl_urls
: URLs to always crawlnew_links_only
: Only check newly discovered links
dns_check_settings
: DNS monitoring configurationextra_cnames
: Additional CNAME records to monitormonitor_main_domain
: Whether to monitor the main domainignored_record_types
: DNS record types to ignore (["SOA"])check_nameservers_in_sync
: Whether to verify nameservers are synchronized
lighthouse_check_settings
: Performance audit configurationcontinent
: Geographic region for testing ("europe", "america", etc.)cpu_slowdown_modifier
: CPU throttling factornotification_settings
: Custom notification thresholdspreferred_server_name
: Specific server to use for testinghttp_client_headers
: Custom headers for the audit
application_health_check_settings
: Custom application health endpointresult_url
: URL of your health check endpointsecret
: Secret token for authenticationheaders
: Custom headers to send
domain_check_settings
: Domain expiration monitoringnot_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 monitoringthreshold_in_ms
: Maximum acceptable response timechange_percentage
: Percentage change threshold for alerts
sitemap_check_settings
: Sitemap validationpath
: Path to sitemap file ("sitemap.xml")speed
: Crawl speed ("default", "fast", "slow")
Additional Properties
crawler_headers
: Custom headers sent during crawling operationssend_report_to_emails
: Email addresses that receive the monthly reportsinclude_check_types_in_report
: Which check types are included in monthly reportsbadge_id
: Unique identifier for status badge integrationmarked_for_deletion_at
: Timestamp if monitor is scheduled for deletioncreated_at
: When the monitor was createdupdated_at
: When the monitor was last modified