The Oh Dear API
The Oh Dear API lets you configure everything about our application through a simple, structured Application Programming Interface (API).
Everything you see in your dashboard can be controlled with the API. And as a bonus, all changes you make with the API will be visible in realtime on your dashboard.
Getting started
Let's help get you started.
- Learn about our API authentication and generate your first API key
- Retrieve a list of all your sites and their checks with the API.
- Configure your status pages automatically.
Optionally, we provide a PHP SDK package to help get you started and a list of data types we use in our API.
API endpoints
All Oh Dear API endpoints are located at https://ohdear.app/api
. From there on, you will find a logical structure that follows to the REST standard.
Here's a quick summary of the API methods.
-
GET
: all GET requests are for data retrieval only (site listing, account info, ...) and will never modify any data. -
POST
: a POST method will add new sites or checks to Oh Dear -
DELETE
: the DELETE method is used to delete certain sites or checks from your account. -
PUT
: this method is used to update information on existing sites, checks or your account.
In general, GET
requests can be performed as many times as you'd like (they are idempotent), all other methods actually transform data in your account and will cause changes to take effect.
Response data
All responses from the Oh Dear API will be formatted as JSON.
Here's an example payload of the /api/sites
endpoint, that lists all sites.
{ "data": [ { "id": 1, "url": "https://yoursite.tld", ... }, { "id": 2, "url": "https://yourothersite.tld", ... } ] }
Each endpoint will return specific data for that request. More info on that in the sites and checks pages.
Get your API token
Once you are logged in to your dashboard navigate to API access and create your API token.
You can name your token, so you know where this one is going to be used, in case you ever need to revoke it.
Once you create a token, it'll be shown only once to you. Make sure to store it safely, after this it can only be revoked and you can generate a new token for use.
Once you have your token, you can authenticate against the application.
By default, tokens can perform any actions to everything in your Oh Dear account. You can also create API tokens that only can be used in API calls to a selection of sites and status pages.
Authenticate against the API
The token you've received can be used as the Authorization
header.
Here's a curl example of how you can authenticate against the API. In this example, it'll list all sites in your account.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The token bgUKSWYL30iHg5w0WTDGHfubt5L1HBTr0atAehCeSqwNTqkU9rOmsNEmWf6Y
is used to authenticate. The /api/sites
endpoint is hit to retrieve all sites. The resulting response payload may look like this.
{ "data": [ { "id": 1, "url": "https://yoursite.tld", ... }, { "id": 2, "url": "https://yourothersite.tld", ... } ] }
The actual payload is usually much bigger, but that's described in more detail in the sites and checks page.
Data types
Check Types
-
uptime
-
performance
-
broken_links
-
mixed_content
-
lighthouse
-
cron
-
application_health
-
sitemap
-
dns
-
domain
-
certificate_health
-
certificate_transparency
Link Types
-
link
-
image
-
script
-
stylesheet
-
og:image
Check Results
-
pending
-
succeeded
-
warning
-
failed
-
errored-or-timed-out
Summarized Check Results
-
succeeded
-
warning
-
failed
Crawler/Sitemap Speed
-
slowest
-
slow
-
default
-
fast
-
fastest
Lighthouse Slowdown Modifier
-
0
(fastest) to -
5
(slowest)
Lighthouse continent
-
europe
-
north-america
-
asia
Response Header Conditions
-
contains
-
not contains
-
equals
-
matches pattern
Uptime Check Locations
Africa
-
cape town
Asia
-
bangalore
-
seoul
-
singapore
-
tokyo
Australia
-
sydney
Canada
-
toronto
Europe
-
frankfurt
-
london
-
paris
Middle East
-
bahrain
South America
-
sao paulo
US East
-
new york
US Mid
-
dallas
US West
-
los angeles
-
san francisco
DNS Record Types
-
A
-
AAAA
-
CAA
-
CNAME
-
MX
-
NS
-
SOA
-
SRV
-
TXT
-
PTR
Uptime check HTTP Verb
-
get
-
post
-
patch
-
put
Sites
Get all sites in your account
The /api/sites
endpoint lists all your sites in your account.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites \ -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, "url": "http://yoursite.tld", "sort_url": "yoursite.tld", "label": "your-site", "team_id": 1, "group_name": null, "tags": ["tag a", "tag b"], "notes": "custom notes", "latest_run_date": "2019-09-16 07:29:02", "summarized_check_result": "succeeded", "created_at": "20171106 07:40:49", "updated_at": "20171106 07:40:49", "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" }, { "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": "" } ] }, { "id": 2, "url": "https://yourothersite.tld", "sort_url": "yourothersite.tld", "label": "my-site", "team_id": 1, "group_name": "My group", "tags": [], "notes": "", "latest_run_date": "2019-09-16 07:29:02", "summarized_check_result": "failed", "created_at": "20171108 07:40:16", "updated_at": "20171108 07:40:16", "checks": [ { "id": 1, "type": "uptime", "label": "Uptime", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:02", "latest_run_result": "succeeded", "summary": "up" }, { "id": 2, "type": "broken_links", "label": "Broken links", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:05", "latest_run_result": "failed", "summary": "1 found" }, { "id": 3, "type": "mixed_content", "label": "Mixed content", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:05", "latest_run_result": "succeeded", "Summary": "" }, { "id": 4, "type": "certificate_health", "label": "Certificate health", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:02", "latest_run_result": "failed", "Summary": "Problems detected" }, { "id": 5, "type": "certificate_transparency", "label": "Certificate transparency", "enabled": true, "latest_run_ended_at": null, "latest_run_result": null, "summary": null } ] } ] }
Let's drill this down, because the 2 sites that are listed each have different checks.
The first one is an http://
site, without TLS encryption. Since we can't monitor certificates or mixed content, we only check the uptime of the site and the broken links.
That's why there are only 2 checks
item for that site.
The second site is an https://
site, and it gets all the available monitoring. More on each check in our dedicated checks page.
Get a specific site via the API
If you don't want to retrieve all sites, you can get a specific site if you know its ID. The example below will get the details of site ID 99.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/99 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The resulting pageload of both calls above is a single site.
{ "id": 99, "url": "http://yoursite.tld", "sort_url": "yoursite.tld", ... "checks": [ { ... }, ... ] }
Notice how this payload does not contain the data
block (the API call to retrieve all sites does).
Return properties
The response gives you a lot of details per site. Here's the specifics;
-
id
: an internal identifier to Oh Dear -
url
: the URL you used to submit this site to Oh Dear, including the protocol. -
sort_url
: the url without the protocol and without thewww.
prefix. -
friendly_name
: the friendly name of a site -
label
: contains thefriendly_name
if one is specified, otherwise this contains thesort_url
. -
team_id
: every site belongs to a Team, this is its ID. A team can consist of multiple members (including yourself). Since you can belong to multiple teams, the corresponding team ID will be shown for every site. To know which team this is, have a look at the user info API call. -
group_name
: the name of the group your site belongs to -
tags
: the names of the tags associated with your site -
latest_run_date
: the date & time of the last time one of the checks in this site has run. -
summarized_check_result
: this gives you an overview of the health of your site at a glance. Possible values aresucceeded
,warning
orfailed
. To get the details of the status, you'll have to check the output of eachcheck
. -
uses_https
: whether it has anhttps://
prefix. -
checks
: an array of all checks that have been added to this site. More details on the checks page. -
broken_links_check_include_external_links
: boolean, whether the crawler will check for external links or not. -
broken_links_whitelisted_urls
: array of ignored URLs that should not be reported if they contain broken links. -
created_at
andupdate_at
: timestamp values for when it was created and when the site's properties were last updated.
More properties will be added over time.
Getting a summary of the results of a check
Oh Dear can perform various checks (uptime, mixed content, broken links, ...) for your sites.
If you want to know the status of a particular check, you can query the /api/sites/{siteId}/check-summary/{checkType}
endpoint.
The checkType
segment can be one of the check types we support.
Here's an example:
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/99/check-summary/uptime \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The response holds two properties:
-
result
: this is the result of the check. Possible values arepending
,succeeded
,warning
,failed
orerrored-or-timed-out
. -
summary
: a human-readable summary of the check result
Add a site through the API
To add a site, create a POST
call to the /api/sites/
endpoint. Here's an example to add the site https://mybrandnewsite.tld
to Oh Dear.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/sites \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"url":"https://mybrandnewsite.tld", "team_id":"1"}'
Remember that we love JSON? Your request payload should also be valid JSON. The minimum actual payload, when formatted, looks like this.
{ "url": "https://mybrandnewsite.tld", "team_id": "1" }
Mandatory fields are the url
we should monitor and the team_id
where this site should be added to. To find out the teams you belong to, see the user info API call.
If the API call succeeded, you'll be given output like this, showcasing every check that was added.
{ "id": 173, "url": "https://mybrandnewsite.tld", "sort_url": "mybrandnewsite.tld", "team_id": 1, ... "checks": [ { "id": 560, "type": "certificate_health", "enabled": true, "settings": [] }, { "id": 561, "type": "mixed_content", "enabled": true, "settings": [] }, ... ] }
Add a site with enabled checks
When creating a site you can control which checks get enabled. You can do so by passing an array with one of these check types.
Here's an example payload where a site is created with only the uptime
and mixed_content
checks enabled.
{ "url": "https://mybrandnewsite.tld", "team_id": "1", "checks": ["uptime", "mixed_content"] }
For more details on each check, have a look at the checks API endpoint.
Add a site with custom settings
If you need to control the settings of a site, you can pass additional parameters in the payload. Here's an example of a site with all possible settings. Please be aware:
-
url
is required -
team_id
is required and should be a team you belong to -
checks
is required and should be an array of check types -
application_health_check_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
{ "url": "https://ohdear.app/docs", "team_id": 1, "checks": [ "uptime", "performance", "broken_links", "mixed_content", "lighthouse", "cron", "application_health", "sitemap", "dns", "domain", "certificate_health", "certificate_transparency" ], "group_name": "Internal", "friendly_name": "Documentation", "tags": ["internal", "production", "docs"], "notes": "Internal notes for our team members", "description": "Oh Dear documentation", "uptime_check_location": "paris", "uptime_check_failed_notification_threshold": 2, "uptime_check_http_verb": "get", "uptime_check_timeout": 5, "uptime_check_max_redirect_count": 5, "uptime_check_payload": [ { "name": "payload-name-1", "value": "payload-value-1" } ], "uptime_check_valid_status_codes": ["2*"], "uptime_check_look_for_string": null, "uptime_check_absent_string": null, "uptime_check_expected_response_headers": [ { "name": "my-response-header", "condition": "equals", "value": "my-response-value" } ], "http_client_headers": [ { "name": "my-header", "value": "my-value" } ], "performance_threshold_in_ms": 3500, "performance_change_percentage": 50, "crawler_headers": [ { "name": "my-broken-links-header", "value": "my-broken-links-value" } ], "broken_links_check_include_external_links": false, "broken_link_types": ["link", "image", "script", "stylesheet", "og:image"], "broken_links_whitelisted_urls": [], "respect_robots": true, "sitemap_path": "/sitemap.xml", "sitemap_speed": "slow", "application_health_check_result_url": "https://mybrandnewsite.tld/health", "application_health_headers": [ {"name": "my-header", "value": "my-value"} ], "certificate_health_check_expires_soon_threshold_in_days": 14, "dns_check_nameservers_in_sync": true, "dns_monitor_main_domain": false, "dns_extra_cnames": ["cname1", "cname2"], "dns_ignored_record_types": ["A", "CNAME"], "domain_check_expires_soon_threshold_in_days": 30, "lighthouse_check_continent": "europe", "lighthouse_cpu_slowdown_modifier": 0 }
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 site settings
You can update the site settings by performing a PUT
request to the /api/sites/{siteId}
endpoint.
The payload is the same as creating a site wit the following differences:
- not all keys are required (only the ones you want to update)
-
url
is not required (but can be updated if needed) -
team_id
is not allowed as a site cannot be moved between teams -
application_health_check_secret
should not be present if you do not want to change the previously stored secret andnull
will remove the secret.
{ "url": "https://ohdear.app/docs", "checks": [ "uptime", "performance", "broken_links", "mixed_content", "lighthouse", "cron", "application_health", "sitemap", "dns", "domain", "certificate_health", "certificate_transparency" ], "group_name": "Internal", "friendly_name": "Documentation", "tags": ["internal", "production", "docs"], "notes": "Internal notes for our team members", "description": "Oh Dear documentation", "uptime_check_location": "paris", "uptime_check_failed_notification_threshold": 2, "uptime_check_http_verb": "get", "uptime_check_timeout": 5, "uptime_check_max_redirect_count": 5, "uptime_check_payload": [ { "name": "payload-name-1", "value": "payload-value-1" } ], "uptime_check_valid_status_codes": ["2*"], "uptime_check_look_for_string": null, "uptime_check_absent_string": null, "uptime_check_expected_response_headers": [ { "name": "my-response-header", "condition": "equals", "value": "my-response-value" } ], "http_client_headers": [ { "name": "my-header", "value": "my-value" } ], "performance_threshold_in_ms": 3500, "performance_change_percentage": 50, "crawler_headers": [ { "name": "my-broken-links-header", "value": "my-broken-links-value" } ], "broken_links_check_include_external_links": false, "broken_link_types": ["link", "image", "script", "stylesheet", "og:image"], "broken_links_whitelisted_urls": [], "respect_robots": true, "sitemap_path": "/sitemap.xml", "sitemap_speed": "slow", "application_health_check_result_url": "https://mybrandnewsite.tld/health", "application_health_check_secret": null, "application_health_headers": [ {"name": "my-header", "value": "my-value"} ], "certificate_health_check_expires_soon_threshold_in_days": 14, "dns_check_nameservers_in_sync": true, "dns_monitor_main_domain": false, "dns_extra_cnames": ["cname1", "cname2"], "dns_ignored_record_types": ["A", "CNAME"], "domain_check_expires_soon_threshold_in_days": 30, "lighthouse_check_continent": "europe", "lighthouse_cpu_slowdown_modifier": 0 }
Deleting a site
Use the DELETE
method to delete a site through the API. In this example, we'll delete the site with ID 1
.
$ OHDEAR_TOKEN="your API token" $ curl -X DELETE https://ohdear.app/api/sites/1 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
Notice how we're calling the DELETE
method on the /api/sites/1
endpoint. The 1
in the URL determines which site to delete.
Ignoring broken links URLs
You can add a single URL to our crawler ignore list with an easy API method. This is primarily used to quickly add just a single URL, for instance in an overview-screen where you allow users to whitelist URLs.
If you want to ignore several URLs, or remove ignored URLs, please see the more extended update-broken-links-settings API call.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/sites/1/add-to-broken-links-whitelist \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "whitelistUrl": "https://externalsite.tld/page1" }'
Modifying site settings
We now support updating all site settings from a single endpoint. But we still support updating some settings on the following dedicated endpoints.
Broken links settings
You can control whether our crawler should check for external links or stick to internal pages only.
Additionally, you can update the site settings and ignore URLs that are known to be broken (or out of your control), so we no longer report if we find broken pages listed on them.
Note: this lists the source URLs, not the destinations.
$ OHDEAR_TOKEN="your API token" $ curl -X PUT https://ohdear.app/api/sites/1/update-broken-links-settings \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "broken_links_check_include_external_links": true, "broken_links_whitelisted_urls_string":" https://externalsite.tld/page1 https://externalsite.tld/page2" }'
The inputs are as follows:
-
broken_links_check_include_external_links
: boolean value, eithertrue
orfalse
-
broken_links_whitelisted_urls_string
: string value, new-line separated list of fully qualified URLs that we should ignore and not report on
Both can be used independently, if you just want to update the broken_links_check_include_external_links
setting, there is no need to also submit the list of ignored URLs.
Updating HTTP client request headers
When performing the uptime, mixed content and broken links checks, Oh Dear can add extra headers to each request we make to a site.
You can update used headers by performing this PUT
request:
$ OHDEAR_TOKEN="your API token" $ curl -X PUT https://ohdear.app/api/sites/1/update-http-client-headers \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '[ {"name": "my-header", "value": "value-of-header"} ]'
Updating the uptime check payload
Oh Dear can send form data along with the uptime check for all non-GET requests.
You can update the sent payload by performing this PUT
request:
$ OHDEAR_TOKEN="your API token" $ curl -X PUT https://ohdear.app/api/sites/1/update-uptime-check-payload \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '[ {"name": "my-name", "value": "my-value"} ]'
Checks
Get all checks for a particular site
To know what checks are available to you, you'll need to query the sites API call first. Per site, you'll be given a set of check IDs.
In this example, we'll get the details for site ID 99
. Notice the checks
data attribute.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/99 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
Here's the response:
{ "id": 1, "url": "https://yoursite.tld", ... "checks": [ { "id": 1, "type": "uptime", "label": "Uptime", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:02", "latest_run_result": "succeeded", "settings": [] }, { "id": 2, "type": "broken_links", "label": "Broken links", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:05", "latest_run_result": "failed", "settings": [] }, { "id": 3, "type": "mixed_content", "label": "Mixed content", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:05", "latest_run_result": "succeeded", "settings": [] }, { "id": 4, "type": "certificate_health", "label": "Certificate health", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:02", "latest_run_result": "succeeded", "settings": [] }, { "id": 5, "type": "certificate_transparency", "label": "Certificate transparency", "enabled": true, "latest_run_ended_at": "2019-09-16 07:29:02", "latest_run_result": "succeeded", "settings": [] } ], }
Per check, you'll see its id
. Once you know that ID, you can enable or disable that check or request a new run, on the spot.
Enable & disable a check
Let's take the first check ID, 1
, as an example. First, we'll enable the check.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/checks/1/enable \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
You make a POST
call to /api/checks/{id}/enable
to enable that check. As a result, you'll be given a confirmation payload.
{ "id": 405, "type": "uptime", "enabled": true }
To disable, make a similar POST
to the /disable
endpoint.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/checks/1/disable \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The resulting payload will confirm the enabled
attribute is set to false.
{ "id": 405, "type": "uptime", "enabled": false }
From that point forward, we'll no longer run that particular check.
If you want to trigger an on-demand run of a check, for instance a new mixed content or broken links scan, you can send an API call to the /request-run
endpoint.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/checks/1/request-run \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
To confirm, we'll give the details of the check once again.
Snooze and unsnooze a check
You can temporarily snooze, or silence, a particular check. We will still perform the checks, but won't send out any notifications in the period that a check is snoozed. For more details on how this option works, have a look at our snooze documentation.
If you prefer to stop monitoring a check for a particular period, it's better to disable it and enable it again later on.
To snooze a check, you can call the /api/checks/{id}/snooze
endpoint and tell it how long the check should be snoozed using the minutes
payload, formatted in JSON.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/checks/1/snooze \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"minutes":"10"}'
If you receive an HTTP/1.1 200 OK
response, the snooze was applied correctly.
To unsnooze, or remove the silencing of alerts, you can call the /api/checks/{id}/unsnooze
endpoint.
$ curl -X POST https://ohdear.app/api/checks/1/unsnooze \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
If you once again received an HTTP/1.1 200 OK
response, the snooze was correctly removed.
Return properties
The response gives you some basic details of a check.
-
id
: an internal identifier to Oh Dear -
type
: what type of check this is. Possible values are:uptime
,performance
,broken_links
,certificate_health
,mixed_content
,cron
,dns
,application_health
, andcertificate_transparency
. -
label
: a human readable label of the check -
enabled
: a boolean value to indicate if this check is enabled or not. Possible values are:true
orfalse
. -
latest_run_ended_at
: a timestamp, in UTC, of the last time this check was run -
latest_run_result
: the status of the last run, can bepending
,succeeded
,warning
orfailed
-
summary
: a human readable summary of the check result
More properties will be added over time.
Uptime
If a site has the uptime check enabled, you can query the uptime percentages via the /api/uptime
endpoint. To use this endpoint you'll need to now the site id
of your site. You can get all sites ids by calling the get all sites endpoint.
To retrieve you'll need to specify a period via the started_at
and ended_at
filters. The period may not be longer than 2 years. The split
value determines how fine grained the answer periods should be. Valid values are hour
, day
and month
.
In this example we are going to get the uptime for site id 1.
$ OHDEAR_TOKEN="your API token" $ curl "https://ohdear.app/api/sites/1/uptime?filter[started_at]=20180101000000&filter[ended_at]=20180101235959&split=day" \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
Here's what the output could look like:
[ {"datetime":"2018-01-01 00:00:00","uptime_percentage":100}, {"datetime":"2018-01-01 01:00:00","uptime_percentage":99.76}, {"datetime":"2018-01-01 02:00:00","uptime_percentage":100}, {"datetime":"2018-01-01 03:00:00","uptime_percentage":98.34}, ... {"datetime":"2018-01-01 23:00:00","uptime_percentage":100} ]
Downtime
You can query the downtime via the /api/sites/{siteId}/downtime
endpoint. To use this endpoint you'll need to now the site id
of your site. You can get all sites ids by calling the get all sites endpoint.
To retrieve you'll need to specify a period via the started_at
and ended_at
filters.
In this example we are going to get the downtime periods for site number 1.
$ OHDEAR_TOKEN="your API token" $ curl "https://ohdear.app/api/sites/1/downtime?filter[started_at]=20180101150000&filter[ended_at]=20180101160000" \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
Here's what the output could look like:
{ "data": [ { "id": 1, "started_at": "2018-01-01 15:00:00", "ended_at": "2018-01-01 15:07:00", "notes_html": "We contacted our provider and they fixed the issue.", "notes_markdown": "We contacted our provider and they fixed the issue." } ] }
Deleting a downtime period
You can delete a downtime period by calling the /api/downtime/{downtimeId}
endpoint. Make sure to use the DELETE
http verb. To use this endpoint you'll need to now the downtime id
, which you can get to by calling the get downtime endpoint.
Performance records
Retrieving performance records
You can retrieve all performance records by calling the /performance-records
endpoint. This can be done per website in your Oh Dear account, so you'll need to know your site's ID first.
A filter is necessary: you decide from when to when the data should be returned.
In this example we'll get a list of all sites and use the site ID to retrieve the performance data.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' { "data": [ { "id": 1, "url": "https://www.yoursite.tld", "...", } ] }
Here, we'll query the performance data between yesterday and today, on the 1m
timeframe. That's our most granular & most detailed timeframe available.
$ curl https://ohdear.app/api/sites/1/performance-records?filter[start]=20240419132501&filter[end]=20240420132501&filter[group_by]=minute \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' { "data": [ { "dns_time_in_seconds": 0.001399, "tcp_time_in_seconds": 0.01651, "ssl_handshake_time_in_seconds": 0.053852, "remote_server_processing_time_in_seconds": 0.021595, "download_time_in_seconds": 0.000535, "total_time_in_seconds": 0.09389099999999999, "curl": { "namelookup_time": 0.001399, "connect_time": 0.017909, "appconnect_time": 0.071761, "starttransfer_time": 0.093356, "pretransfer_time": 0.071864, "redirect_time": 0, "total_time": 0.093891, "header_size": 1261, "size_download": 12814, "speed_download": 137784 }, "created_at": "2021-08-10 18:57:00" { ... } ], }
If there are no performance records in the requested period, you'll receive an empty data
array.
{ "data": [] }
Selecting the granularity for data
In the example above, we grouped the performance records per minute. These records are stored for roughly 14 days. We also stored performance records per hour (which are kept for a couple of weeks) and per day (which are kept eternally).
You can request the hourly and daily records by passing hour
or day
to group_by
.
Sorting the results
By default, the records will be sorted by newest records first. In other words, the most recent performance data will always be on top.
You can change the sorting by adding an explicit sort=created_at
query parameter to the API call. You can negate the sort (ie: reverse it) by making it sort=-created_at
.
$ curl https://ohdear.app/api/sites/1/performance-records?filter[start]=20240419132501&filter[end]=20240420132501&filter[group_by]=minute&sort=created_at \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The only field you can use to sort data is the created_at
column.
Performance record data explained
The API returns the detailed performance metrics for each datapoint we have.
{ "dns_time_in_seconds": 0.001399, "tcp_time_in_seconds": 0.01651, "ssl_handshake_time_in_seconds": 0.053852, "remote_server_processing_time_in_seconds": 0.021595, "download_time_in_seconds": 0.000535, "total_time_in_seconds": 0.09389099999999999, "curl": { "namelookup_time": 0.001399, "connect_time": 0.017909, "appconnect_time": 0.071761, "starttransfer_time": 0.093356, "pretransfer_time": 0.071864, "redirect_time": 0, "total_time": 0.093891, "header_size": 1261, "size_download": 12814, "speed_download": 137784 }, "created_at": "2021-08-10 18:57:00" },
In the curl
key, you find the raw performance values that curl
produces when we called your site. In most cases, it will be expressed in milliseconds, not seconds. So 0.0429
can be read as 42.9ms
. By multiplying each value by 1,000, you get the value in milliseconds.
The data represents the following part of the request:
-
time_namelookup
: The time it takes to resolve the domain name to an IP address via DNS. -
time_connect
: The time it takes to connect to the remote host (TCP three-way handshake). -
time_appconnect
: The total time it took for the TLS handshake to complete (cipher negotiation & encryption). -
time_remoteserver
: The time it took the server to process the request and start sending the first byte of the page. -
time_download
: The time, in seconds, it took for the page to be downloaded. -
time_total
: The total time it took from start to finish of this request.
Broken Links
Retrieving broken links
If a site has the broken links check enabled, you can get all detected broken links via the /api/broken-links
endpoint. To use this endpoint you'll need to now the site id of your site. You can get all sites ids by calling the get all sites endpoint.
In this example we are going to get the broken-links for site number 1.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/broken-links/1 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
Here's what the output could look like:
{ "data": [ { "crawled_url": "https://example.com/broken", "relative_crawled_url": "/broken", "status_code": 404, "found_on_url": "https://example.com", "relative_found_on_url": "https://example.com", "internal": true } ] }
Mixed content
Retrieving mixed content
If a site has the mixed content check enabled, you can get all detected mixed content via the /api/mixed-content
endpoint. To use this endpoint you'll need to now the site id of your site. You can get all sites ids by calling the get all sites endpoint.
In this example we are going to get the broken-links for site number 1.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/mixed-content/1 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
Here's what the output could look like:
{ "data": [ { "element_name": "img", "mixed_content_url": "http://example.com/image.jpg", "found_on_url": "https://example.com" } ] }
Certificate Health
Retrieving info on the certificate health
If a site has the certificate health check enabled, you can get feedback on the result via the /api/certificate-health
endpoint. To use this endpoint you'll need to now the site id of your site. You can get all sites ids by calling the get all sites endpoint.
Here's an example where we get the certificate health of the site with ID 1.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/certificate-health/1 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The output will be an object with these 3 keys:
-
certificate_details
: an array with some details on the detected certificate -
certificate_checks
: an array with info on the checks we performed on the certificate -
certificate_chain_issuers
: an array containing the names of all the issuers in the complete certificate chain
Here's what it looks like.
{ "certificate_details": { "issuer": "Let's Encrypt Authority X3", "valid_from": "2019-09-10 15:16:01", "valid_until": "2019-12-09 15:16:01" }, "certificate_checks": [ { "type": "notFound", "label": "Certificate present", "passed": true }, { "type": "expiresSoon", "label": "Will not expire in the next 14 days", "passed": true }, { "type": "coversWrongDomain", "label": "Covers the right domain", "passed": true }, { "type": "doesNotConnectWithRootCertificate", "label": "Connects with a root certificate", "passed": true }, { "type": "notYetActive", "label": "Is currently active", "passed": true }, { "type": "isSelfSigned", "label": "Is not self signed", "passed": true }, { "type": "usesInvalidHash", "label": "Uses valid hash", "passed": true }, { "type": "hasExpired", "label": "Has not expired", "passed": true }, { "type": "hasChanged", "label": "Unchanged since last checked", "passed": true } ], "certificate_chain_issuers": [ "US, Let's Encrypt, Let's Encrypt Authority X3", "Digital Signature Trust Co., DST Root CA X3" ] }
To determine the overal health of the certificate, you can look at all the checks in the certificate_checks
result.
Those with a value of "passed": false
have a failed check.
User Info
Retrieve your team & user info
Make a GET
request to the /api/me
endpoint.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/me \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
If the API call succeeded, you'll be presented with your team & user info.
Return properties
Here's an example payload of the API call.
{ "id": 1, "name": "Firstname Lastname", "email": "[email protected]", "photo_url": "https://www.gravatar.com/avatar/...jpg", "teams": [ { "id": 1, "name": "Your Team Name" } ] }
Let's look at all the properties that are returned.
-
id
: the identifier of the user this API key belongs to. -
name
,email
andphoto_url
: personal information about your account. -
teams
: an array of teams this user belongs to. A user can be a member of several teams.
The teams
property has an id
(team ID) and a human readable name
. The team id
will be used throughout all API calls to determine what team you want to add sites to.
Status Pages
You can make a GET
HTTP call to the /api/status-pages
endpoint to retrieve all your configured status pages.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/status-pages \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
As a result, you'll get a list of all your status pages and their metadata.
{ "data": [ { "id": 1, "team": { "id": 1, "name": "Your Team Name" }, "title": "Your Status Page Title", "domain": "status.your-domain.tld", "slug": "autem-quos-accusantium-esse-ex-numquam-odio", "full_url": "https://ohdear.app/status-page/autem-quos-accusantium-esse-ex-numquam-odio", "timezone": "Europe/Brussels", "summarized_status": "up", "sites": [ { "id": 1, "url": "https://site1.tld", ... }, { "id": 7, "url": "https://site2.tld", ... } ], "created_at": "2019-09-13 07:06:51", "updated_at": "2019-09-13 07:06:51" } ], "links": { "first": "https://ohdear.app/api/status-pages?page%5Bnumber%5D=1", "last": "https://ohdear.app/api/status-pages?page%5Bnumber%5D=1", "prev": null, "next": null }, "meta": { "current_page": 1, "from": 1, "last_page": 1, "path": "https://ohdear.app/api/status-pages", "per_page": 200, "to": 2, "total": 2 } }
There's a lot of data in there, let's unpack it.
The following fields are available in the output:
-
data
: this is an array that contains a list of all your status pages. -
team
: because you can belong to multiple teams, we'll clarify which team this status page belongs to. -
summarized_status
: this can either beup
,down
orunknown
. It'sdown
when at least one of the sites in the status page has an uptime check that reported it as down. -
sites
: this is an array with all sites that are added to this status page. It will also contain all checks from each website, so you have all information easily available to you. - the
links
andmeta
output are for pagination when you have many status pages.
Retrieve a single status page
You can also pass the ID of a status page to the /api/status-pages/{id}
endpoint to get the details of a specific status page.
In this example, we'll retrieve the status page with ID 1.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/status-pages/1 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The resulting output will contain the details of that specific status page. Note that it does not have the data
container that is used when retrieving all sites through the API.
{ "id": 1, "team": { "id": 1, "name": "Your Team Name" }, "title": "Your Status Page Title", ... "updates": [ { "id": 65, "title": "Your status page update title", ... }, ... ], "sites": [ { "id": 1, "url": "https://site1.tld", }, ... ] }
In addition to the similar output of the /api/status-pages
endpoint described above, when you get the data from a single status page we'll also include its updates
.
This will contain an array of all status page updates & messages that have been posted to your status page.
For more details, have a look at our status page updates API documentation.
The rest of the data is similar to the output described above.
Delete a status page
If you make a DELETE
HTTP call to the /api/status-pages/ID
, you can delete a status page through the API.
In this example we are going to delete the status page with ID 99.
$ OHDEAR_TOKEN="your API token" $ curl -i -X DELETE https://ohdear.app/api/status-pages/99 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
If you get an HTTP/1.1 204 No Content
response, the status page was successfully deleted. Anything else will indicate an error.
HTTP/1.1 204 No Content X-RateLimit-Limit: 180 X-RateLimit-Remaining: 176 ...
Each status page can contain updates or messages. These are used to communicate to your customers or clients in times of downtime or maintenance.
You can post these messages from your dashboard or with our API.
To list the updates or messages from a single status page, you'll need to know its ID. You can retrieve that using the /api/status-pages
API call explained in the status pages API documentation.
Once you have your ID, you can get the details as follows:
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/status-pages/1/updates \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The resulting output will contain an array of all the updates to that specific status page.
If there are no status messages, the array will be empty.
{ "data": [] }
If there are messages, we'll return those in the data
field.
{ "data": [ { "id": 65, "title": "3rd party API issue resolved", "text": "We have contacted our API provider and they have resolved the situation, everything is back to normal. We apologize for the inconvenience!", "pinned": false, "severity": "resolved", "time": "2019-09-16 08:24:00", "status_page_url": "https://ohdear.app/status-page/your-slug" }, { "id": 64, "title": "We are experiencing an outage on our service", "text": "Due to errors in our 3rd party API provider, we are experiencing an outage of our website. Our team is working on getting it resolved ASAP.", "pinned": false, "severity": "high", "time": "2019-09-16 08:11:00", "status_page_url": "https://ohdear.app/status-page/your-slug" } ] }
These are sorted by newest message to oldest. The output contains the following fields:
-
id
: the ID of that particular update -
title
andtext
: these are shown on your status page -
pinned
: when set totrue
, this update will be posted at the very top of your status page. There can only be 1 pinned message. -
severity
: these can beinfo
,warning
,high
,resolved
orscheduled
. You are free to use these any way you like. Theresolved
updates will be posted in green on your status page to inform the user the problem has been resolved. -
time
: the date in UTC at which this status page was posted. This will get translated to your configured timezone.
Post a new update to your status page
To add a new update or message to your status page, you can make a POST
call to the /api/status-page-updates
endpoint.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/status-page-updates \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"status_page_id":1, "title":"Our site is down", "text":"We are working on it!", "severity":"high", "time":"2019-09-16 10:24","pinned":true}'
As a confirmation, we'll return an HTTP/1.1 201 Created
with the received data fields.
{ "id": 66, "title": "Our site is down", "text": "We are working on it!", "pinned": true, "severity": "high", "time": "2019-09-16 08:24:00", "status_page_url": "https://ohdear.app/status-page/your-slug" }
The POST
API call should contain a valid json body with the following fields.
-
status_page_id
: the ID of the status page where you want to add this update. -
title
: the titel of your status update -
text
: a longer text describing what is happening or how you're resolving the problem -
severity
are:info
,warning
,high
,resolved
orscheduled
. -
time
: a date field that acts as a timestamp for this update, should be in UTC in theY-m-d H:i
format. -
pinned
: whether this status page message should be pinned to the very top of the page. There can only be 1 pinned message, when set totrue
it will remove thepinned
attribute from any other message. -
status_page_url
: the public URL of your status page. If you have configured a custom domain, this will point to your custom domain - otherwise it'll be the URL with your status page slug on the ohdear.app domain.
Delete an update on your status page
Let's use the API to delete the status message we just posted above, the one with ID 66.
$ OHDEAR_TOKEN="your API token" $ curl -X DELETE https://ohdear.app/api/status-page-updates/66 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
If the response code is HTTP/1.1 204 No Content
, the deletion of the status update was successful.
Maintenance windows
Retrieving maintenance periods
You can list all maintenance windows by calling the /maintenance-periods
endpoint. This can be done per website in your Oh Dear account, so you'll need to know your site's ID first.
In this example we'll get a list of all sites and use the site ID to retrieve the maintenance periods.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' { "data": [ { "id": 1, "url": "https://www.yoursite.tld", "...", } ] } $ curl https://ohdear.app/api/sites/1/maintenance-periods \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' { "data": [ { "id": 101, "site_id": 1, "starts_at": "2020-01-09 10:37:24", "ends_at": "2020-01-09 10:42:24" }, { "id": 102, "site_id": 1, "starts_at": "2020-01-09 10:37:32", "ends_at": "2020-01-09 10:42:32" }, }
If there are no maintenance periods, you'll receive an empty data
array.
{ "data": [] }
If there are maintenance windows, we'll show the time of each start end end period.
{ "data": [ { "starts_at": "2020-01-09 14:00:00", "ends_at": "2020-01-10 14:00:00" } ] }
These dates are all shown in the timezone of your team. If your timezone is configured as America/Vancouver
, you'll see the dates & times shown in your own local timezone.
Creating a new maintenance period on-demand
This method applies on a per-site basis. If you want to put the site with ID 1
in maintenance right now, you can call this API method.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/sites/1/start-maintenance \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' { "id": 101, "site_id": 1, "starts_at": "2020-01-09 10:28:54", "ends_at": "2020-01-09 11:28:54" }
This will start a maintenance period that, by default, will last for 60 minutes. In the response, you'll find the confirmation of the start- and end-date.
To stop the maintenance period, call the /stop-maintenance
endpoint.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/sites/1/stop-maintenance \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
This will change the end-date of the currently active maintenance period to the time you've called the API.
This way, you still have a list of maintenance periods to look back on (as an audit list).
On-demand maintenance window with limited duration
If you prefer, you can also pass along the amount of seconds a maintenance period needs to be active in the /start-maintenance
API call. This can be lowered or increased depending on your needs and provides a safe fallback in case your scripts execute the start-maintenance
API call, but never get to the stop-maintenance
call.
To do so, add a stop_maintenance_after_seconds
POST value in JSON, as shown here.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/sites/1/start-maintenance \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"stop_maintenance_after_seconds":"300"}' { "id": 101, "site_id": 1, "starts_at": "2020-01-09 10:37:32", "ends_at": "2020-01-09 10:42:32" }
This will create a maintenance period for 300 seconds, or 5 minutes, as confirmed by the JSON output.
Creating a maintenance period with custom start and end times
If you don't use the on-demand maintenance windows as shown above, you can create maintenance windows with a custom start- and end-date. This allows you to schedule maintenance ahead of times.
Since maintenance windows are applicable per website, you need the site ID of the website you want to put in maintenance.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/maintenance-periods \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{"site_id":"1", "starts_at":"2020-02-01 14:00","ends_at":"2020-02-01 18:00"}' { "id": 101, "site_id": "1", "starts_at": "2020-02-01 14:00:00", "ends_at": "2020-02-01 18:00:00" }
The API expects the dates to be formatted as Y:m:d H:i
(no seconds) and the ends_at
needs to be further in the future than the starts_at
.
All dates should be in your local timezone, as configured in your team settings. (You don't need to convert anything to UTC, write the dates as they feel natural to you.)
Deleting a maintenance period
To delete a maintenance period, you need its ID. That can be retrieved with the /maintenance-periods API call, as shown above.
$ OHDEAR_TOKEN="your API token" $ curl -X DELETE https://ohdear.app/api/maintenance-periods/101 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The example above deletes the maintenance period with ID 101
.
Cron Job Monitoring
Get all cron jobs for a website
Cron job monitors are attached to a website in Oh Dear. To retrieve a list of monitored cron jobs, you'll the website ID first.
The /api/sites/{$siteId}/cron-checks
endpoint lists all your cron job monitors for that particular site.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/1/cron-checks \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
As a result, you get the details for every cron job monitor attached to this site, together with its latest status:
{ "data": [ { "id": 1, "uuid": "0d210b09", "name": "cronjob number one", "type": "simple", "description": "a description goes here", "frequency_in_minutes": 15, "grace_time_in_minutes": 5, "cron_expression": null, "server_timezone": "Europe/Brussels", "ping_url": "https://ping.ohdear.app/0d210b09", "created_at": "2020-07-28 13:27:02", "latest_result": "pingFinished", "latest_ping_at": "2020-11-16 09:19:40", "human_readable_latest_ping_at": "5 minutes ago" }, { "id": 2, "uuid": "8eb64808", "name": "cronjob number two", "type": "simple", "description": "a description goes here", "frequency_in_minutes": 60, "grace_time_in_minutes": 10, "cron_expression": null, "server_timezone": "Europe/Brussels", "ping_url": "https://ping.ohdear.app/8eb64808", "created_at": "2020-07-28 13:27:02", "latest_result": "pingFinished", "latest_ping_at": "2020-11-16 09:19:40", "human_readable_latest_ping_at": "5 minutes ago" } ] }
The response is a JSON encoded array with all the details of the cron jobs you defined to be monitored.
Result types
The latest_result
response in the API can be one of the following values.
These are values actively submitted by your application to your cron monitoring URL endpoint:
-
pingStarting
: we have received the "started" pingback from your application -
pingFinished
: we have received the "finished" pingback from your application, indicating no errors occurred -
pingFailed
: we have received the "failed" pingback from your application, indicating errors have occured
These are values we may have detected ourselves, without active participation from your application:
-
checkRanTooLate
: because we did not receive a new ping URL on time, we have marked the cron task as failed because it ran too late -
sentCronNotExutedOnTimeNotification
: because the check didn't execute on time, we have sent the "did not run on time" notification -
sentPingFailedNotification
: your application reported us that the last ping contained a failure, we have now sent a notification that the ping failed
The success states of a cronjob are determined only by the pingFinished
result. All other types indicate that we are either waiting on a ping, have received a failed ping, or have received no ping at all.
Create a simple cron job monitor
You can create a new cron job monitor using our API. You'll need the site ID where you want to attach the new monitor to.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/sites/1/cron-checks \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "name": "your cron job name", "type": "simple", "frequency_in_minutes": 10, "grace_time_in_minutes": 15, "description": "a description goes here" }'
The example above will create a new cron job monitor by providing both the frequency and the gracetime. Note how the type
is set to simple
.
The response will include the Ping URL you can point your cron jobs to:
{ "id": 12, "uuid": "ba4322cf", "name": "your cron job name", "type": "simple", "description": "a description goes here", "frequency_in_minutes": 10, "grace_time_in_minutes": 15, "cron_expression": "", "server_timezone": null, "ping_url": "https://ping.ohdear.app/ba4322cf", "created_at": "2020-08-03 12:18:33" }
The ping_url
should be used in your scripts to report back the status of your cron jobs to us.
Create a new cron job monitor via crontab expression
Alternatively, you can create a new cron job monitor using the crontab expression as well.
Note how in this example the type
is set to cron
instead of simple
.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/sites/1/cron-checks \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "name": "your cron job name", "type": "cron", "cron_expression":"* * * * *", "grace_time_in_minutes": 10, "description": "a description goes here", "server_timezone": "UTC" }'
The example above will create a new cron job monitor using the crontab expression * * * * *
to indicate it should run every minute.
The response will include the Ping URL you can point your cron jobs to:
{ "id": 10, "uuid": "19eea41a", "name": "your cron job name", "type": "cron", "description": "a description goes here", "frequency_in_minutes": 0, "grace_time_in_minutes": 10, "cron_expression": "* * * * *", "server_timezone": "UTC", "ping_url": "https://ping.ohdear.app/19eea41a", "created_at": "2020-08-03 12:13:53" }
The ping_url
should be used in your scripts to report back the status of your cron jobs to us.
Bulk cron job synchronization
For our PHP-SDK, we've created a mass-update endpoint you can use to update all cron jobs for a single site. This will remove any cron job not explicitly in this sync API call, so it is a destructive action.
$ OHDEAR_TOKEN="your API token" $ curl -X POST https://ohdear.app/api/sites/1/cron-checks/sync \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json' \ -d '{ "cron_checks": [ { "name": "cron job #1", "type": "cron", "cron_expression":"* * * * *", "grace_time_in_minutes": 10, "description": "description for cron #1", "server_timezone": "UTC" }, { "name": "cron job #2", "type": "cron", "cron_expression":"* * * * *", "grace_time_in_minutes": 10, "description": "description for cron #2", "server_timezone": "UTC" } ] }'
The return data, if the API call was successful, is a confirmation of each cron job definition together with all its metadata.
[ { "id": 9, "uuid": "c1803dce", "name": "cron job #1", "type": "cron", "description": "description for cron #1", "frequency_in_minutes": null, "grace_time_in_minutes": 10, "cron_expression": "* * * * *", "server_timezone": "UTC", "ping_url": "https://ping.ohdear.app/c1803dce", "created_at": "2020-09-03 19:20:25", "latest_result": "pingFinished", "latest_ping_at": "2020-11-16 09:19:40" }, { "id": 10, "uuid": "40e8e39e", "name": "cron job #2", "type": "cron", "description": "description for cron #2", "frequency_in_minutes": null, "grace_time_in_minutes": 10, "cron_expression": "* * * * *", "server_timezone": "UTC", "ping_url": "https://ping.ohdear.app/40e8e39e", "created_at": "2020-09-03 19:20:25", "latest_result": "pingFinished", "latest_ping_at": "2020-11-16 09:19:40" } ]
Error handling
If an error occured, you'll be given a non-HTTP/200 response code. The resulting payload might look like this.
{ "message": "The given data was invalid.", "errors": { "name": ["There already exist a cron check with this name for this site."] } }
DNS Records
Retrieving DNS history for a site
To retrieve a list of your entire Dns history and issues, you'll the website ID first.
The /api/sites/{$siteId}/dns-history-items
endpoint lists all DNS related information we retrieved for your domain.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/1/dns-history-items \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
As a result, you get the history of the DNS records for your domain, together with all issues we found. Here's an example result for records retrieved for a https://freek.dev
.
The results are sorted in reverse chronological order: the topmost item will contain your current DNS records.
{ "data": [ { "id": 2, "authoritative_nameservers": [ "ns1.openprovider.nl", "ns2.openprovider.be", "ns3.openprovider.eu" ], "dns_records": [ { "host": "freek.dev", "ttl": 1017, "class": "IN", "type": "A", "ip": "138.197.187.74" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 10, "target": "aspmx.l.google.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 20, "target": "alt1.aspmx.l.google.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 20, "target": "alt2.aspmx.l.google.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 30, "target": "aspmx2.googlemail.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 30, "target": "aspmx3.googlemail.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "NS", "target": "ns1.openprovider.nl" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "NS", "target": "ns2.openprovider.be" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "NS", "target": "ns3.openprovider.eu" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "SOA", "mname": "ns1.openprovider.nl", "rname": "dns.openprovider.eu", "serial": 2021080201, "refresh": 10800, "retry": 3600, "expire": 604800, "minimum_ttl": 3600 }, { "host": "freek.dev", "ttl": 1060, "class": "IN", "type": "TXT", "txt": "v=spf1 include:amazonses.com include:eu.mailgun.org include:spf.factuursturen.be include:sendgrid.net include:_spf.google.com a mx ~all" } ], "raw_dns_records": { "ns1.openprovider.nl": [ "freek.dev.\t\t1017\tIN\tA\t138.197.187.74", "freek.dev.\t\t1060\tIN\tTXT\t\"v=spf1 include:amazonses.com include:eu.mailgun.org include:spf.factuursturen.be include:sendgrid.net include:_spf.google.com a mx ~all\"", "freek.dev.\t\t4435\tIN\tMX\t10\taspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt1.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt2.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx2.googlemail.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx3.googlemail.com.", "freek.dev.\t\t4435\tIN\tNS\tns1.openprovider.nl.", "freek.dev.\t\t4435\tIN\tNS\tns2.openprovider.be.", "freek.dev.\t\t4435\tIN\tNS\tns3.openprovider.eu.", "freek.dev.\t\t4435\tIN\tSOA\tns1.openprovider.nl.\tdns.openprovider.eu.\t2021080201\t10800\t3600\t604800\t3600" ], "ns2.openprovider.be": [ "freek.dev.\t\t1060\tIN\tTXT\t\"v=spf1 include:amazonses.com include:eu.mailgun.org include:spf.factuursturen.be include:sendgrid.net include:_spf.google.com a mx ~all\"", "freek.dev.\t\t4435\tIN\tMX\t10\taspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt1.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt2.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx2.googlemail.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx3.googlemail.com.", "freek.dev.\t\t4435\tIN\tNS\tns1.openprovider.nl.", "freek.dev.\t\t4435\tIN\tNS\tns2.openprovider.be.", "freek.dev.\t\t4435\tIN\tNS\tns3.openprovider.eu.", "freek.dev.\t\t4435\tIN\tSOA\tns1.openprovider.nl.\tdns.openprovider.eu.\t2021080201\t10800\t3600\t604800\t3600" ], "ns3.openprovider.eu": [ "freek.dev.\t\t1017\tIN\tA\t138.197.187.74", "freek.dev.\t\t1060\tIN\tTXT\t\"v=spf1 include:amazonses.com include:eu.mailgun.org include:spf.factuursturen.be include:sendgrid.net include:_spf.google.com a mx ~all\"", "freek.dev.\t\t4435\tIN\tMX\t10\taspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt1.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt2.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx2.googlemail.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx3.googlemail.com.", "freek.dev.\t\t4435\tIN\tNS\tns1.openprovider.nl.", "freek.dev.\t\t4435\tIN\tNS\tns2.openprovider.be.", "freek.dev.\t\t4435\tIN\tNS\tns3.openprovider.eu.", "freek.dev.\t\t4435\tIN\tSOA\tns1.openprovider.nl.\tdns.openprovider.eu.\t2021080201\t10800\t3600\t604800\t3600" ] }, "issues": [ { "name": "NameserversAreNotInSync", "nameservers": [ "ns2.openprovider.be" ] } ], "diff_summary": "No changes", "created_at": "2021-11-05 16:07:38" }, { "id": 1, "authoritative_nameservers": [ "ns1.openprovider.nl", "ns2.openprovider.be", "ns3.openprovider.eu" ], "dns_records": [ { "host": "freek.dev", "ttl": 1017, "class": "IN", "type": "A", "ip": "138.197.187.74" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 10, "target": "aspmx.l.google.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 20, "target": "alt1.aspmx.l.google.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 20, "target": "alt2.aspmx.l.google.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 30, "target": "aspmx2.googlemail.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "MX", "pri": 30, "target": "aspmx3.googlemail.com" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "NS", "target": "ns1.openprovider.nl" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "NS", "target": "ns2.openprovider.be" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "NS", "target": "ns3.openprovider.eu" }, { "host": "freek.dev", "ttl": 4435, "class": "IN", "type": "SOA", "mname": "ns1.openprovider.nl", "rname": "dns.openprovider.eu", "serial": 2021080201, "refresh": 10800, "retry": 3600, "expire": 604800, "minimum_ttl": 3600 }, { "host": "freek.dev", "ttl": 1060, "class": "IN", "type": "TXT", "txt": "v=spf1 include:amazonses.com include:eu.mailgun.org include:spf.factuursturen.be include:sendgrid.net include:_spf.google.com a mx ~all" } ], "raw_dns_records": { "ns1.openprovider.nl": [ "freek.dev.\t\t1017\tIN\tA\t138.197.187.74", "freek.dev.\t\t1060\tIN\tTXT\t\"v=spf1 include:amazonses.com include:eu.mailgun.org include:spf.factuursturen.be include:sendgrid.net include:_spf.google.com a mx ~all\"", "freek.dev.\t\t4435\tIN\tMX\t10\taspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt1.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt2.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx2.googlemail.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx3.googlemail.com.", "freek.dev.\t\t4435\tIN\tNS\tns1.openprovider.nl.", "freek.dev.\t\t4435\tIN\tNS\tns2.openprovider.be.", "freek.dev.\t\t4435\tIN\tNS\tns3.openprovider.eu.", "freek.dev.\t\t4435\tIN\tSOA\tns1.openprovider.nl.\tdns.openprovider.eu.\t2021080201\t10800\t3600\t604800\t3600" ], "ns2.openprovider.be": [ "freek.dev.\t\t1017\tIN\tA\t138.197.187.74", "freek.dev.\t\t1060\tIN\tTXT\t\"v=spf1 include:amazonses.com include:eu.mailgun.org include:spf.factuursturen.be include:sendgrid.net include:_spf.google.com a mx ~all\"", "freek.dev.\t\t4435\tIN\tMX\t10\taspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt1.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt2.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx2.googlemail.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx3.googlemail.com.", "freek.dev.\t\t4435\tIN\tNS\tns1.openprovider.nl.", "freek.dev.\t\t4435\tIN\tNS\tns2.openprovider.be.", "freek.dev.\t\t4435\tIN\tNS\tns3.openprovider.eu.", "freek.dev.\t\t4435\tIN\tSOA\tns1.openprovider.nl.\tdns.openprovider.eu.\t2021080201\t10800\t3600\t604800\t3600" ], "ns3.openprovider.eu": [ "freek.dev.\t\t1017\tIN\tA\t138.197.187.74", "freek.dev.\t\t1060\tIN\tTXT\t\"v=spf1 include:amazonses.com include:eu.mailgun.org include:spf.factuursturen.be include:sendgrid.net include:_spf.google.com a mx ~all\"", "freek.dev.\t\t4435\tIN\tMX\t10\taspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt1.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t20\talt2.aspmx.l.google.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx2.googlemail.com.", "freek.dev.\t\t4435\tIN\tMX\t30\taspmx3.googlemail.com.", "freek.dev.\t\t4435\tIN\tNS\tns1.openprovider.nl.", "freek.dev.\t\t4435\tIN\tNS\tns2.openprovider.be.", "freek.dev.\t\t4435\tIN\tNS\tns3.openprovider.eu.", "freek.dev.\t\t4435\tIN\tSOA\tns1.openprovider.nl.\tdns.openprovider.eu.\t2021080201\t10800\t3600\t604800\t3600" ] }, "issues": [], "diff_summary": "No changes", "created_at": "2021-11-05 16:02:38" } }
Possible values of issues
The issues
property will return an array with issues we detected. Each item in that array will have a property name
that can contain on of the following values:
-
CouldNotDiscoverNameservers
: we couldn't find the authoritative nameservers for your domain -
CouldNotFindAnyDnsRecords
: some nameservers of your domain did not return any records. These nameservers are listed in thenameservers
property of this array -
NameserversAreNotInSync
: a nameserver of your domain returned different records than the other nameservers. The names of the nameservers that are not in sync are listed in thenameservers
property of this array
Application Health Monitoring
Retrieving application health check for a site
To retrieve a list of application health checks, you'll need the website ID first.
The /api/sites/{$siteId}/application-health-checks
endpoint lists all application health checks that are running for
your site.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/1/application-health-checks \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
This is what could get as a result:
{ "data": [ { "id": 1, "name": "DiskUsage", "label": "Disk usage", "status": "failed", "message": "The disk is nearly full (91%)", "short_summary": "91%", "meta": { "usage": 91 }, "detected_at": "2021-01-01 00:00:00", "updated_at": "2021-01-01 00:00:00" } ] }
Available fields
The message
property will be filled when a check failed. It will contain the message that we also have sent via a
notification.
The short_summary
property contains a string that we'll also display on the application health check overview of your
site.
The status
property can contain one of the following values:
-
ok
: the check was ok -
warning
: the check is closed to failing -
failed
: the check did fail -
crashed
: something went wrong running the check itself -
skipped
: the check wasn't performed in this run
The meta
property contains an object that contain extra info that was sent along with the check result.
Retrieving the history of a health check
The /api/sites/{$siteId}/application-health-checks/{$applicationHealthCheckId}
endpoint lists the history of results
of an application health check.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/1/application-health-checks/1 \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
It will return the history of the check results. The newest items appear first in the list.
{ "data": [ { "id": 2, "status": "ok", "message": "", "short_summary": "60%", "meta": { "usage": 60 }, "detected_at": "2021-01-01 00:01:00", "updated_at": "2021-01-01 00:01:00" }, { "id": 1, "status": "failed", "message": "The disk is nearly full (91%)", "short_summary": "91%", "meta": { "usage": 91 }, "detected_at": "2021-01-01 00:00:00", "updated_at": "2021-01-01 00:00:00" } ] }
Domain monitoring
Retrieving domain information for a site
To retrieve domain information of a site, you'll need the website ID first.
The /api/sites/{$siteId}/domain
endpoint displays domain related information we retrieved for your domain.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/1/domain \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
The response contains the most important dates of the domain, and the domain status. In the rdap_domain_response
key, you'll find the raw response we got from RDAP about your domain. The created_at
key contains the date on which we queried RDAP.
Here's example output when monitoring google.com:
{ "expires_at": "2028-09-14 04:00:00", "registered_at": "1997-09-15 04:00:00", "last_changed_at": "2019-09-09 15:39:04", "last_updated_in_rdap_db_at": "2022-06-11 00:32:59", "domain_statuses": { "client delete prohibited": true, "client transfer prohibited": true, "client update prohibited": true, "server delete prohibited": true, "server transfer prohibited": true, "server update prohibited": true }, "rdap_domain_response": { "links": [ { "rel": "self", "href": "https://rdap.verisign.com/com/v1/domain/GOOGLE.COM", "type": "application/rdap+json", "value": "https://rdap.verisign.com/com/v1/domain/GOOGLE.COM" }, { "rel": "related", "href": "https://rdap.markmonitor.com/rdap/domain/GOOGLE.COM", "type": "application/rdap+json", "value": "https://rdap.markmonitor.com/rdap/domain/GOOGLE.COM" } ], "events": [ { "eventDate": "1997-09-15T04:00:00Z", "eventAction": "registration" }, { "eventDate": "2028-09-14T04:00:00Z", "eventAction": "expiration" }, { "eventDate": "2019-09-09T15:39:04Z", "eventAction": "last changed" }, { "eventDate": "2022-06-11T00:32:59Z", "eventAction": "last update of RDAP database" } ], "handle": "2138514_DOMAIN_COM-VRSN", "status": [ "client delete prohibited", "client transfer prohibited", "client update prohibited", "server delete prohibited", "server transfer prohibited", "server update prohibited" ], "ldhName": "GOOGLE.COM", "notices": [ { "links": [ { "href": "https://www.verisign.com/domain-names/registration-data-access-protocol/terms-service/index.xhtml", "type": "text/html" } ], "title": "Terms of Use", "description": ["Service subject to Terms of Use."] }, { "links": [ { "href": "https://icann.org/epp", "type": "text/html" } ], "title": "Status Codes", "description": [ "For more information on domain status codes, please visit https://icann.org/epp" ] }, { "links": [ { "href": "https://icann.org/wicf", "type": "text/html" } ], "title": "RDDS Inaccuracy Complaint Form", "description": [ "URL of the ICANN RDDS Inaccuracy Complaint Form: https://icann.org/wicf" ] } ], "entities": [ { "roles": ["registrar"], "handle": "292", "entities": [ { "roles": ["abuse"], "vcardArray": [ "vcard", [ ["version", [], "text", "4.0"], ["fn", [], "text", ""], [ "tel", { "type": "voice" }, "uri", "tel:+1.2086851750" ], ["email", [], "text", "[email protected]"] ] ], "objectClassName": "entity" } ], "publicIds": [ { "type": "IANA Registrar ID", "identifier": "292" } ], "vcardArray": [ "vcard", [ ["version", [], "text", "4.0"], ["fn", [], "text", "MarkMonitor Inc."] ] ], "objectClassName": "entity" } ], "secureDNS": { "delegationSigned": false }, "nameservers": [ { "ldhName": "NS1.GOOGLE.COM", "objectClassName": "nameserver" }, { "ldhName": "NS2.GOOGLE.COM", "objectClassName": "nameserver" }, { "ldhName": "NS3.GOOGLE.COM", "objectClassName": "nameserver" }, { "ldhName": "NS4.GOOGLE.COM", "objectClassName": "nameserver" } ], "objectClassName": "domain", "rdapConformance": [ "rdap_level_0", "icann_rdap_technical_implementation_guide_0", "icann_rdap_response_profile_0" ] }, "created_at": "2022-06-10 20:33:06" }
Lighthouse SEO monitoring
To retrieve Lighthouse SEO reports of a site, you'll need the website ID first.
Getting the latest report
The /api/sites/{$siteId}/lighthouse-reports/latest
endpoint displays that latest Lighthouse report we generated for your site.
$ OHDEAR_TOKEN="your API token" $ curl https://ohdear.app/api/sites/1/lighthouse-reports/latest \ -H "Authorization: Bearer $OHDEAR_TOKEN" \ -H 'Accept: application/json' \ -H 'Content-Type: application/json'
This will return a result like
{ "id": 1, "performance_score": 50, "accessibility_score": 98, "best_practices_score": 92, "seo_score": 92, "progressive_web_app_score": 30, "first_contentful_paint_in_ms": 1851.45, "speed_index_in_ms": 1866, "largest_contentful_paint_in_ms": 1851.45, "time_to_interactive_in_ms": 2473.87, "total_blocking_time_in_ms": 123.77, "cumulative_layout_shift": 0.01, "performed_on_checker_server": "lighthouse-checker-frankfurt-1", "json_report": { /* Omitted for brevity, will contain the full JSON report generated by the lighthouse tool */ }, "issues": [ { "category": "performance", "actualScore": 50, "notificationThreshold": 70 } ], "created_at": "2023-01-14 00:00:55" }
Getting a list of all reports
The /api/sites/{$siteId}/lighthouse-reports
endpoint returns all Lighthouse SEO reports.
Here's some example output. Notice that we don't return the json_report
in the response for this endpoint.
{ "data": [ { "id": 1423, "performance_score": 97, "accessibility_score": 98, "best_practices_score": 92, "seo_score": 92, "progressive_web_app_score": 30, "first_contentful_paint_in_ms": 1851.45, "speed_index_in_ms": 1866, "largest_contentful_paint_in_ms": 1851.45, "time_to_interactive_in_ms": 2473.87, "total_blocking_time_in_ms": 123.77, "cumulative_layout_shift": 0.01, "performed_on_checker_server": "lighthouse-checker-frankfurt-1", "issues": [ { "category": "performance", "actualScore": 97, "notificationThreshold": 99 } ], "created_at": "2023-01-14 00:00:55" }, { "id": 1321, "performance_score": 89, "accessibility_score": 98, "best_practices_score": 92, "seo_score": 92, "progressive_web_app_score": 30, "first_contentful_paint_in_ms": 294.65, "speed_index_in_ms": 328, "largest_contentful_paint_in_ms": 294.65, "time_to_interactive_in_ms": 1585.48, "total_blocking_time_in_ms": 445.9, "cumulative_layout_shift": 0.06, "performed_on_checker_server": "lighthouse-checker-frankfurt-1", "issues": [ { "category": "performance", "actualScore": 89, "notificationThreshold": 99 } ], "created_at": "2023-01-12 23:38:19" } ], "links": { "first": "https://ohdear.app/api/sites/1/lighthouse-reports?page%5Bnumber%5D=1", "last": "https://ohdear.app/api/sites/1/lighthouse-reports?page%5Bnumber%5D=1", "prev": null, "next": null }, "meta": { "current_page": 1, "from": 1, "last_page": 1, "links": [ { "url": null, "label": "« Previous", "active": false }, { "url": "https://ohdear.app/api/sites/1/lighthouse-reports?page%5Bnumber%5D=1", "label": "1", "active": true }, { "url": null, "label": "Next »", "active": false } ], "path": "https://ohdear.app/api/sites/1/lighthouse-reports", "per_page": 200, "to": 2, "total": 2 } }
Getting a specific Lighthouse SEO report
The /api/sites/{$siteId}/lighthouse-reports/{$reportId}
endpoint returns a specific report. You can get the $reportId
by retrieving the list of Lighthouse reports (see above)
Here's an example response.
{ "id": 1, "performance_score": 50, "accessibility_score": 98, "best_practices_score": 92, "seo_score": 92, "progressive_web_app_score": 30, "first_contentful_paint_in_ms": 1851.45, "speed_index_in_ms": 1866, "largest_contentful_paint_in_ms": 1851.45, "time_to_interactive_in_ms": 2473.87, "total_blocking_time_in_ms": 123.77, "cumulative_layout_shift": 0.01, "performed_on_checker_server": "lighthouse-checker-frankfurt-1", "json_report": { /* Omitted for brevity, will contain the full JSON report generated by the lighthouse tool */ }, "issues": [ { "category": "performance", "actualScore": 50, "notificationThreshold": 70 } ], "created_at": "2023-01-14 00:00:55" }
Notification destinations
Using our API, you can retrieve notification destination of your site or teams. Because the results of these API calls can contain sensitive values, only admins and team owners are allowed to use them.
Getting the notification destinations of all your teams
The /api/team-notification-destinations
endpoint will return all notification destinations defined on the team level
for all your teams.
{ "data": [ { "id": 123, "team_id": 1, "channel": "mail", "destination": { "mail": "[email protected]" }, "notification_types": [ "UptimeCheckFailedNotification", "UptimeCheckRecoveredNotification", ... ] } ] }
Getting the notification destinations of a site
To retrieve the notification destinations of a site, you'll need the website ID first.
The /api/sites/{$siteId}/notification-destinations
endpoint will return all notification destinations for the site.
{ "data": [ { "id": 456, "channel": "mail", "destination": { "mail": "[email protected]" }, "notification_types": [ "UptimeCheckFailedNotification", "UptimeCheckRecoveredNotification", ... ] } ] }
Getting the notification destinations of a tag
The /api/tags/notification-destinations
endpoint will return all notification destinations defined on the tag level
for all your teams.
{ "data": [ { "id": 123, "tag": { "id": 1, "name": "Production", "slug": "production" }, "team_id": 1, "channel": "mail", "destination": { "mail": "[email protected]" }, "notification_types": [ "UptimeCheckFailedNotification", "UptimeCheckRecoveredNotification", ... ] } ] }
Creating notification destinations
You can create a new notification destination for a site or team. The required payload is in the same format as the API to retrieve notification destinations which makes it easy to copy notification configurations across sites and teams.
Sites: /api/sites/{$siteId}/notification-destinations
Teams: /api/team-notification-destinations/{$teamId}
Tags: /api/tags/notification-destinations/{$tagId}
Payload
{ "channel": "mail", "destination": { "mail": "[email protected]" }, "notification_types": [ "UptimeCheckRecoveredNotification", "UptimeCheckFailedNotification", ] }
Note: an empty array will create your configuration but will not respond to any Oh Dear events. Make sure the array has at least one item.
Payload (all events)
You can accept all supported notification types by removing the notification_types
array from your request.
{ "channel": "mail", "destination": { "mail": "[email protected]" } }
Sending a test notification
You can also trigger a test notification as part of the creation process by adding test: true|false
to you request body. By default this will be false
.
{ "test": true, "channel": "mail", "destination": { "mail": "[email protected]" } }
Updating notification destinations
You can update an existing notification destination by sending a PUT/PATCH
request with the updated payload to the following endpoints:
Sites: /api/sites/{$siteId}/notification-destinations/{$destinationId}
Teams: /api/team-notification-destinations/{$teamId}/destination/{$destinationId}
Tags: /api/tags/notification-destinations/{$tagId}/destination/{$destinationId}
{ "test": true, "channel": "mail", "destination": { "mail": "[email protected]" } }
You can also send test notifications on updates by adding test: true
to your request body. By default this will be false
.
Deleting notifications destinations#
You can delete a notification destination by sending a DELETE
request to the following endpoints:
Sites: /api/sites/{$siteId}/notification-destinations/{$destinationId}
Teams: /api/team-notification-destinations/{$teamId}/destination/{$destinationId}
Tags: /api/tags/{$tagId}/notification-destinations/destination/{$destinationId}
No other parameters are required and a 204 response will be returned if the deletion was successful.
Channels and destinations
Each channel requires a valid destination object. You can find the supported channels and their config objects below.
{ "channel": "mail", "destination": { "mail": "[email protected]" }, }
Discord
{ "channel": "discord", "destination": { "url": "https://discord.com/api/webhooks/your-webhook-url" } }
Microsoft Teams
{ "channel": "microsoftTeams", "destination": { "url": "https://teams.microsoft.com/webhook/your-webhook-url" } }
Pushover
{ "channel": "pushover", "destination": { "userKey": "your-user-key", "apiToken": "your-api-token", "priority": "0" } }
Priority [lowest - emergency]: -2
, -1
, 0
, 1
, 2
Slack
{ "channel": "slack", "destination": { "url": "https://hooks.slack.com/services/your-webhook-url" } }
Slack API
{ "channel": "slackApi", "destination": { "token": "xoxp-rest-of-your-token-here", "channel": "#general" } }
Telegram
{ "channel": "telegram", "destination": { "chat_id": "your-chat-id", } }
SMS
{ "channel": "sms", "destination": { "apiKey": "your-vonage-api-key", "apiSecret": "your-vonage-api-secret", "from": "your-sender-number", "to": "your-recipient-number" } }
Webhook
{ "channel": "webhooks", "destination": { "url": "https://your-webhook-url" } }
Opsgenie
{ "channel": "opsgenie", "destination": { "apiKey": "your-api-key", "euEndpoint": true, "priority": "P3" } }
Priority: P1
, P2
, P3
, P4
, P5
Pager Duty
{ "channel": "pagerDuty", "destination": { "apiKey": "your-service-key", "serviceId": "your-service-id", "fromEmail": "[email protected]" } }
Notification types
The following notification types are valid for both teams and sites:
- ApplicationHealthClientErrorNotification
- ApplicationHealthProblemDetectedNotification
- ApplicationHealthProblemFixedNotification
- ApplicationHealthResultsTooOldNotification
- BrokenLinksFoundNotification
- BrokenLinksFixedNotification
- CertificateExpiresSoonNotification
- CertificateFixedNotification
- CertificateHasChangedNotification
- CertificateIssuedNotification
- CertificateUnhealthyNotification
- CronFailedNotification
- CronNotExecutedOnTimeNotification
- DnsIssuesFoundNotification
- DnsIssuesFixedNotification
- DnsRecordsChangedNotification
- DomainIssuesFoundNotification
- DomainIssuesFixedNotification
- LighthouseIssuesDetectedNotification
- LighthouseIssuesFixedNotification
- MixedContentFoundNotification
- MixedContentFixedNotification
- PerformanceDeltaExceededNotification
- PerformanceThresholdExceededNotification
- PerformanceThresholdRecoveredNotification
- SitemapIssuesFoundNotification
- SitemapIssuesFixedNotification
- UptimeCheckFailedNotification
- UptimeCheckRecoveredNotification
Team notification types
In addition to the generic notification types listed above the following are also valid for teams only:
- SiteAddedNotification
Feel free to reach out via [email protected] or on Twitter via @OhDearApp if you have any other questions. We'd love to help!