TLS Monitor
Register HTTPS endpoints, inspect certificate health, and queue on-demand TLS scans.
TLS Monitor API
TLS Monitor tracks HTTPS certificate health for company-owned monitor records. Creating a monitor queues its first scan. Changing the hostname clears the previous result and queues another scan; an accepted scan is asynchronous and does not mean the certificate was healthy.
List monitors
tls_monitor:readPath, query, and header parameters
pagesizehostnametagstatusResponses
Paginated monitor summaries.
{
"entities": "TlsMonitor",
"count": 1,
"per_page": 100,
"pages": {
"current": 1,
"max": 1
},
"elements": [
{
"id": "MONITOR_ID",
"name": "Customer portal",
"hostname": "https://portal.example.com",
"status": "success",
"tags": [
"production"
],
"last_check": 1789722000,
"certificate_type": "domain_validated",
"validation_type": "DV",
"expires_at": 1794902400
}
]
}Request examples
curl --request GET 'https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor.json', {
method: 'GET',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
},
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
],
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.
Create a monitor
tls_monitor:writePath, query, and header parameters
No path, query, or additional header parameters.
Request Body
{
"tlsMonitor": {
"name": "Customer portal",
"hostname": "https://portal.example.com",
"tags": [
"production",
"customer-facing"
],
"notificationTo": [
"ops@example.com"
]
}
}tlsMonitor.nameRequiredtlsMonitor.hostnameRequiredtlsMonitor.tagstlsMonitor.notificationToResponses
Monitor created and initial scan queued when available.
{
"tlsMonitor": {
"id": "MONITOR_ID",
"name": "Customer portal",
"hostname": "https://portal.example.com"
},
"scanQueued": true
}Name or HTTPS target is invalid.
{
"error": "A valid hostname (https://...) must be specified"
}Request examples
curl --request POST 'https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"tlsMonitor": {
"name": "Customer portal",
"hostname": "https://portal.example.com",
"tags": [
"production",
"customer-facing"
],
"notificationTo": [
"ops@example.com"
]
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor.json', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"tlsMonitor": {
"name": "Customer portal",
"hostname": "https://portal.example.com",
"tags": [
"production",
"customer-facing"
],
"notificationTo": [
"ops@example.com"
]
}
}),
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{
"tlsMonitor": {
"name": "Customer portal",
"hostname": "https://portal.example.com",
"tags": [
"production",
"customer-facing"
],
"notificationTo": [
"ops@example.com"
]
}
}',
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.
Retrieve a monitor
tls_monitor:readPath, query, and header parameters
tlsMonitorIdRequiredResponses
Full monitor configuration and most recent response.
{
"id": "MONITOR_ID",
"name": "Customer portal",
"hostname": "https://portal.example.com",
"tags": [
"production"
],
"last_response": {
"status": "success"
}
}Monitor not found in this company.
{
"error": "Tls monitor not found"
}Request examples
curl --request GET 'https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json', {
method: 'GET',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
},
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
],
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.
Update a monitor
tls_monitor:writePath, query, and header parameters
tlsMonitorIdRequiredRequest Body
{
"tlsMonitor": {
"name": "Customer portal EU",
"hostname": "https://eu.portal.example.com",
"tags": [
"production",
"eu"
],
"notificationTo": [
"ops@example.com"
]
}
}tlsMonitor.nametlsMonitor.hostnametlsMonitor.tagstlsMonitor.notificationToResponses
Monitor updated.
{
"tlsMonitor": {
"id": "MONITOR_ID",
"hostname": "https://eu.portal.example.com"
},
"scanQueued": true
}Monitor not found in this company.
{
"error": "Tls monitor not found"
}Request examples
curl --request PUT 'https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"tlsMonitor": {
"name": "Customer portal EU",
"hostname": "https://eu.portal.example.com",
"tags": [
"production",
"eu"
],
"notificationTo": [
"ops@example.com"
]
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json', {
method: 'PUT',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"tlsMonitor": {
"name": "Customer portal EU",
"hostname": "https://eu.portal.example.com",
"tags": [
"production",
"eu"
],
"notificationTo": [
"ops@example.com"
]
}
}),
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{
"tlsMonitor": {
"name": "Customer portal EU",
"hostname": "https://eu.portal.example.com",
"tags": [
"production",
"eu"
],
"notificationTo": [
"ops@example.com"
]
}
}',
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.
Delete a monitor
tls_monitor:writePath, query, and header parameters
tlsMonitorIdRequiredResponses
Monitor deleted.
{
"id": "MONITOR_ID",
"deleted": true
}Monitor not found in this company.
{
"error": "Tls monitor not found"
}Request examples
curl --request DELETE 'https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json', {
method: 'DELETE',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
},
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
],
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.
Queue an on-demand scan
tls_monitor:writePath, query, and header parameters
tlsMonitorIdRequiredResponses
Scan command queued; poll the monitor for the resulting status.
{
"id": "MONITOR_ID",
"scanQueued": true
}Monitor not found in this company.
{
"error": "Tls monitor not found"
}The command could not be queued.
{
"error": "Unable to enqueue tls scan now"
}Request examples
curl --request POST 'https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID/scan.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID/scan.json', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
},
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/systems/tls-monitor/TLSMONITORID/scan.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
],
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.