Domain Health (report)
/api/v1/reports/domain-healthRequest
/api/v1/reports/domain-healthcurl -X GET 'https://app.mailyte.com/api/v1/reports/domain-health' \
-H 'Authorization: Bearer mk_live_YOUR_API_KEY'const response = await fetch('https://app.mailyte.com/api/v1/reports/domain-health', {
method: 'GET',
headers: {
Authorization: 'Bearer mk_live_YOUR_API_KEY',
},
});
const { data } = await response.json();import requests
response = requests.get(
"https://app.mailyte.com/api/v1/reports/domain-health",
headers={"Authorization": "Bearer mk_live_YOUR_API_KEY"},
)
data = response.json()["data"]<?php
$response = Http::withToken('mk_live_YOUR_API_KEY')
->get('https://app.mailyte.com/api/v1/reports/domain-health');
$data = $response->json('data');require "net/http"
require "json"
uri = URI("https://app.mailyte.com/api/v1/reports/domain-health")
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer mk_live_YOUR_API_KEY"
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(request) }Response
Success.
dataobjectobjectstringdomain_health_reportgenerated_atstringWhen this response was computed, ISO 8601 UTC. Every report answers it, so "is this figure stale?" never depends on which report you asked.
periodobjectAlways null. This report is a snapshot of current DNS state, not a windowed aggregate: `ReportService::domainHealth()` takes no date range and the `date_range` query parameter is ignored.
start_atstringend_atstringgranularitystringdayThe width of one `series` bucket. Always `day`: the `granularity` query parameter is accepted and ignored.
domainsarray<object>One row per domain in your organization, soft-deleted domains excluded.
objectstringdomain_healthdomainstringThe domain name. NOT NULLABLE, and that is a claim rather than an oversight: `domains.domain` is `varchar(255) NOT NULL UNIQUE` and the only producer reads it straight off the model, so there is no path that yields a row without one. Publishing it as nullable would have made every caller write a null check for a case that cannot occur, which is its own wrong promise. Pinned by PublicReportContractTest::test_a_domain_health_row_never_publishes_a_null_domain.
dnsobjectThe one lifecycle answer for this domain's DNS. The row used to carry the domains table's own `status` ("Active"/"Inactive") beside `dns_status`, which could disagree with it.
statestringverified | pending | failed | unknownNormalised and closed. The underlying column is free text and holds both `failed` and `Failed`, plus NULL for most rows; anything outside the three known values is `unknown`, which is why the buckets in `totals` always sum.
verifiedbooleanTrue only for `verified`. `pending` and `failed` are both "not verified" to a caller deciding whether to send.
spam_scorenumberAlways null today: nothing in this stack computes a spam score. Null rather than 0 because 0 would read as the worst possible verdict rather than as a gap. Kept in the shape because reputation IS domain health -- this report exists to answer it.
reputation_scorenumberAlways null today, for the same reason as `spam_score`.
checked_atstringSourced from the domain record's `updated_at`, so it moves whenever anything about the domain changes and is not necessarily when DNS was last checked. Treat it as "as of", not as a check timestamp.
totalsobjectDNS-state bucket counts, recounted from the rows above rather than copied from the service. `verified + pending + failed + unknown` always equals `domains`. NOTE these count domains, not messages: `failed` here is a DNS state, unrelated to the delivery report's `failed`.
domainsintegerRows in `domains`.
verifiedintegerDomains whose DNS has passed.
pendingintegerDomains whose DNS check has not finished.
failedintegerDomains whose DNS check failed.
unknownintegerDomains whose `dns_config_status` is NULL or a value outside the closed set. Most domains sit here. Before the buckets were recounted, these were counted into nothing and the three buckets silently failed to add up to the number of domains.
Returned inside the standard envelope.
Errors
| Status | When |
|---|---|
401 | The API key is missing, unknown, revoked or expired. All four answer identically, on purpose: distinguishing them would confirm which keys exist. |
403 | The key is valid but may not do this: it lacks the required scope, its IP allowlist does not include you, or this endpoint does not accept API keys. |
404 | No such resource in this organization. |
422 | The request was understood but the values were not acceptable. |
429 | Too many requests, or the organization has spent its sending allowance. `Retry-After` says how long to wait. |
Every status, with what causes it and what to do, is on the error reference.