Site health check API
Runs the TLS certificate check, the security headers check and the RDAP lookup in parallel and returns one section per check. A section that fails is marked and the status becomes unknown. There is no score.
GET https://api.lookproof.dev/v1/site/health
Updated 2026-10-09
Examples use the Base (eip155:8453) network.
Input
Query parameters.
| Name | Type | Required | Limits | Description |
|---|---|---|---|---|
domain | string | Yes | 1–1024 characters | The domain to check, for example example.com. |
Example request
curl -i 'https://api.lookproof.dev/v1/site/health?domain=example.com'import asyncio
import os
from eth_account import Account
from x402 import x402Client
from x402.http.clients import x402HttpxClient
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact import register_exact_evm_client
async def main() -> None:
signer = EthAccountSigner(Account.from_key(os.environ["EVM_PRIVATE_KEY"]))
client = register_exact_evm_client(x402Client(), signer, networks="eip155:8453")
async with x402HttpxClient(client) as http:
response = await http.get('https://api.lookproof.dev/v1/site/health', params={'domain': 'example.com'})
response.raise_for_status()
print(response.json())
asyncio.run(main())
import { wrapFetchWithPaymentFromConfig } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY);
const fetchWithPayment = wrapFetchWithPaymentFromConfig(fetch, {
schemes: [{ network: "eip155:8453", client: new ExactEvmScheme(account) }],
});
const response = await fetchWithPayment("https://api.lookproof.dev/v1/site/health?domain=example.com");
console.log(await response.json());
curl: unpaid request — returns 402 with the price (PAYMENT-REQUIRED). The Python and JavaScript clients pay it and send the request again. Only ordinary wallets (EOA) can pay; smart-contract wallets get a 402 without charge. See payments.
Example response
{
"checked_at": "2026-10-24T12:00:00Z",
"data": {
"domain": "example.com",
"http": {
"domain": "example.com",
"from_http": {
"error": null,
"final_status": 200,
"final_url": "https://example.com/",
"hops": [
{
"location": "https://example.com/",
"status": 301,
"url": "http://example.com/"
},
{
"location": null,
"status": 200,
"url": "https://example.com/"
}
],
"start_url": "http://example.com/"
},
"from_https": {
"error": null,
"final_status": 200,
"final_url": "https://example.com/",
"hops": [
{
"location": null,
"status": 200,
"url": "https://example.com/"
}
],
"start_url": "https://example.com/"
},
"headers": {
"content_security_policy": "default-src 'self'; frame-ancestors 'none'",
"content_security_policy_report_only": null,
"cookies": [
{
"http_only": true,
"name": "session",
"same_site": "lax",
"secure": true
}
],
"cross_origin_opener_policy": "same-origin",
"permissions_policy": "camera=(), microphone=()",
"referrer_policy": "strict-origin-when-cross-origin",
"strict_transport_security": {
"include_subdomains": true,
"max_age": 63072000,
"preload": true,
"raw": "max-age=63072000; includeSubDomains; preload",
"valid": true
},
"x_content_type_options": "nosniff",
"x_frame_options": null
}
},
"rdap": {
"created": "1995-08-14T04:00:00Z",
"days_to_expiry": 292,
"delegation_signed": true,
"domain": "example.com",
"expires": "2027-08-13T04:00:00Z",
"last_changed": "2026-08-14T07:01:39Z",
"ldh_name": "example.com",
"nameservers": [
"a.iana-servers.net",
"b.iana-servers.net"
],
"rdap_server": "rdap.verisign.com",
"registered": true,
"registrar": "RESERVED-Internet Assigned Numbers Authority",
"registrar_iana_id": 376,
"statuses": [
"client delete prohibited",
"client transfer prohibited",
"client update prohibited"
]
},
"tls": {
"address_family": "ipv4",
"chain": [
{
"issuer": "CN=Example Issuing CA",
"subject": "CN=example.com"
},
{
"issuer": "CN=Example Issuing CA",
"subject": "CN=Example Issuing CA"
}
],
"cipher": "TLS_AES_256_GCM_SHA384",
"days_remaining": 36,
"domain": "example.com",
"hostname_match": true,
"issuer": "CN=Example Issuing CA",
"key_bits": 256,
"key_type": "ec",
"not_after": "2026-11-30T00:00:00Z",
"not_before": "2026-09-01T00:00:00Z",
"san": [
"example.com",
"www.example.com"
],
"serial_number": "5ec0de",
"signature_algorithm": "ecdsa-with-SHA256",
"subject_cn": "example.com",
"tls_version": "TLSv1.3",
"trusted": true,
"untrusted_reason": null
}
},
"endpoint": "site.health",
"findings": [],
"meta": {
"cache_hit": false,
"duration_ms": 42,
"fresh_until": "2026-10-24T12:05:00Z",
"observed_at": "2026-10-24T12:00:00Z",
"resolver": null,
"source": "dns"
},
"request_id": "req_aaaaaaaaaaaaaaaaaaaaaaaaaa",
"schema_version": "1.0",
"status": "ok"
}
Response fields
| Field | Meaning |
|---|---|
request_id | Unique id of this request. Quote it when you contact support. |
endpoint | The endpoint id, for example mail.spf. |
schema_version | Version of the response format, currently 1.0. |
checked_at | When the check ran (ISO 8601, UTC). |
status | ok, info, warning or error from the worst finding, or unknown when the check was incomplete. unknown is not an error in the domain. |
data | The check's own data. Its fields are listed below. |
findings | What was found: code, severity, message, explanation and evidence. |
meta | Duration, cache use, resolver and how long the result stays fresh. |
Fields in data
| Field | Type |
|---|---|
domain | string |
tls | TlsCertificateData or null |
http | SecurityHeadersData or null |
rdap | RdapData or null |
Status codes
| Status | Code | Meaning | Do you pay? |
|---|---|---|---|
| 200 | — | The result is delivered, also when it has negative findings. | Yes: charged once per payment; redelivery of the same payment is free |
| 402 | — | Payment is required, or the attached payment was refused. The body states the price. | No |
| 400 | bad_request | The request is malformed. | No |
| 409 | payment_in_progress, payment_bound_to_other_request | This payment is already being processed, or it is bound to a different request. No new payment is taken. | No |
| 422 | invalid_input | The input failed validation on a request that carries a payment; nothing is charged. Without a payment, invalid input gets a 402 whose error field names the problem. | No |
| 429 | rate_limited | Too many requests from this IP address or payer. | No |
| 502 | check_failed | The check could not be completed. | No |
| 503 | busy, unavailable, payments_unavailable | The service is busy or temporarily unavailable. | No |
| 504 | deadline_exceeded | The check ran out of time. | No |
Errors use the common error body. See errors.
Findings this endpoint can return
Cookies (1)
- Warning
COOKIE_NOT_SECUREThe HTTPS site sets a cookie without the Secure attribute.
Content Security Policy (2)
- Info
CSP_MISSINGThe HTTPS site sends no Content-Security-Policy header. - Info
CSP_UNSAFE_INLINEThe Content Security Policy allows inline or eval'd scripts.
DNS (2)
- Warning
DNS_RESOLVER_FAILUREThe DNS resolver returned a server failure. - Warning
DNS_RESOLVER_TIMEOUTThe DNS resolver did not answer in time.
Domain registration (6)
- Error
DOMAIN_EXPIREDThe domain registration has expired. - Warning
DOMAIN_EXPIRING_SOONThe domain registration expires in less than 30 days. - Info
DOMAIN_NOT_REGISTEREDThe registry has no record of the domain. - Error
DOMAIN_ON_HOLDThe domain is on hold and is not published in DNS. - Error
DOMAIN_PENDING_DELETEThe domain is about to be deleted. - Info
DOMAIN_TRANSFER_UNLOCKEDThe domain has no transfer lock.
Frame protection (1)
- Info
FRAME_PROTECTION_MISSINGThe HTTPS site does not restrict who may frame it.
HSTS (3)
- Warning
HSTS_MISSINGThe HTTPS site sends no valid Strict-Transport-Security header. - Info
HSTS_NOT_PRELOAD_READYThe domain does not meet the HSTS preload requirements. - Info
HSTS_SHORT_MAX_AGEThe HSTS max-age is shorter than one year.
HTTP (2)
- Warning
HTTP_NO_HTTPS_REDIRECTPlain HTTP is not redirected to HTTPS. - Info
HTTP_UNAVAILABLEThe site does not answer over plain HTTP.
HTTPS (1)
- Error
HTTPS_UNAVAILABLEThe site could not be loaded over HTTPS.
RDAP (1)
- Info
RDAP_UNAVAILABLEThe registry's RDAP service could not be asked about the domain.
Redirects (2)
- Warning
REDIRECT_LIMITThe site redirects more than five times in a row. - Info
REDIRECT_OFFSITEThe site redirects to another domain.
Referrer-Policy (1)
- Info
REFERRER_POLICY_MISSINGThe HTTPS site sends no Referrer-Policy header.
TLS certificate (8)
- Error
TLS_CERT_EXPIREDThe TLS certificate has expired. - Info
TLS_CERT_EXPIRINGThe TLS certificate expires within 30 days. - Warning
TLS_CERT_EXPIRING_SOONThe TLS certificate expires in less than 14 days. - Error
TLS_HOSTNAME_MISMATCHThe TLS certificate is not valid for the domain name. - Error
TLS_UNAVAILABLENo TLS connection to the domain on port 443 could be made. - Error
TLS_UNTRUSTEDThe TLS certificate does not chain to a trusted certificate authority. - Warning
TLS_WEAK_KEYThe TLS certificate uses a weak public key. - Warning
TLS_WEAK_SIGNATUREA certificate in the chain is signed with SHA-1 or MD5.
X-Content-Type-Options (1)
- Info
XCTO_MISSINGThe HTTPS site sends no X-Content-Type-Options: nosniff header.