Domain Watchlist
DomScan API: Monitor domains for expiration and availability changes. Get alerts when registered domains become available.
Domain Watchlist
Monitor domains for expiration and availability changes. Get alerts when registered domains become available.
Sign in with Google to access your personalized domain watchlist with email alerts, webhooks, and more.
Receive notifications via Email, Telegram, Slack, Discord, or Webhook.
Get all domains in your watchlist.
Paginated: send limit (1 to 100) and pass next_cursor back as cursor. Responses include has_more and next_cursor. Without limit the whole list is returned. See pagination.
Example response
{
"watchlist": [
{
"domain": "startup.com",
"added_at": "2024-01-15T10:30:00Z",
"status": "registered",
"expiry_date": "2025-01-15T00:00:00Z",
"days_until_expiry": 287,
"last_checked": "2024-03-01T12:00:00Z",
"notify_email": "[email protected]",
"check_count": 4
}
],
"total": 1,
"updated_at": "2024-03-01T12:00:00Z"
}
Response fields
| Field | Type |
|---|---|
has_more |
boolean |
next_cursor |
string | null |
watchlist[] |
object[] |
watchlist[] |
object |
watchlist[].domain |
string |
watchlist[].added_at |
string |
watchlist[].status |
string |
watchlist[].last_checked |
string |
watchlist[].expiry_date |
string |
watchlist[].days_until_expiry |
integer |
watchlist[].notify_email |
string |
watchlist[].check_count |
integer |
total |
integer |
updated_at |
string |
Add a domain to your watchlist.
Request body
{
"domain": "mydomain.com",
"notify_email": "[email protected]"
}
Response fields
| Field | Type |
|---|---|
success |
boolean |
message |
string |
watchlist[] |
object[] |
watchlist[] |
object |
watchlist[].domain |
string |
watchlist[].added_at |
string |
watchlist[].status |
string |
watchlist[].last_checked |
string |
watchlist[].expiry_date |
string |
watchlist[].days_until_expiry |
integer |
watchlist[].notify_email |
string |
watchlist[].check_count |
integer |
total |
integer |
Example response
{
"success": true,
"message": "Added example.org to watchlist",
"watchlist": [
{
"domain": "example.com",
"added_at": "2026-06-02T09:12:00.000Z",
"last_checked": "2026-10-09T03:00:12.000Z",
"status": "expiring_soon",
"expiry_date": "2026-12-18T14:22:08Z",
"days_until_expiry": 70,
"notify_email": "[email protected]"
},
{
"domain": "example.org",
"added_at": "2026-10-09T10:15:30.000Z",
"status": "unknown",
"notify_email": "[email protected]"
}
],
"total": 2
}
Remove from watchlist
curl -X DELETE -H "X-API-Key: your-api-key" "https://domscan.net/v1/watchlist?domain=mydomain.com"
Response fields
| Field | Type |
|---|---|
success |
boolean |
message |
string |
domain |
string |
watchlist[] |
object[] |
watchlist[] |
object |
watchlist[].domain |
string |
watchlist[].added_at |
string |
watchlist[].status |
string |
watchlist[].last_checked |
string |
watchlist[].expiry_date |
string |
watchlist[].days_until_expiry |
integer |
watchlist[].notify_email |
string |
watchlist[].check_count |
integer |
total |
integer |
Example response
{
"success": true,
"message": "Request completed",
"domain": "example.com",
"watchlist": [
{
"domain": "example.com",
"added_at": "2026-08-27T12:00:00Z",
"status": "registered",
"last_checked": "2026-08-27T12:00:00Z",
"expiry_date": "2026-08-27T12:00:00Z",
"days_until_expiry": 1,
"notify_email": "[email protected]",
"check_count": 1
}
],
"total": 1
}
Expiring soon
Paginated: send limit (1 to 100) and pass next_cursor back as cursor. Responses include has_more and next_cursor. Without limit the whole list is returned. See pagination.
Example response
{
"expiring_domains": [
{
"domain": "renewal-window.com",
"status": "expiring_soon",
"expiry_date": "2026-05-12T00:00:00Z",
"days_until_expiry": 28,
"check_count": 11
}
],
"total": 1,
"threshold_days": 30
}
Response fields
| Field | Type |
|---|---|
has_more |
boolean |
next_cursor |
string | null |
expiring_domains[] |
object[] |
expiring_domains[] |
object |
expiring_domains[].domain |
string |
expiring_domains[].added_at |
string |
expiring_domains[].status |
string |
expiring_domains[].last_checked |
string |
expiring_domains[].expiry_date |
string |
expiring_domains[].days_until_expiry |
integer |
expiring_domains[].notify_email |
string |
expiring_domains[].check_count |
integer |
total |
integer |
threshold_days |
integer |
Available
Paginated: send limit (1 to 100) and pass next_cursor back as cursor. Responses include has_more and next_cursor. Without limit the whole list is returned. See pagination.
Example response
{
"available_domains": [
{
"domain": "startupdrop.ai",
"status": "available",
"last_checked": "2026-04-14T08:30:00Z",
"check_count": 18
}
],
"total": 1,
"message": "These domains from your watchlist are now available for registration!"
}
Response fields
| Field | Type |
|---|---|
has_more |
boolean |
next_cursor |
string | null |
available_domains[] |
object[] |
available_domains[] |
object |
available_domains[].domain |
string |
available_domains[].added_at |
string |
available_domains[].status |
string |
available_domains[].last_checked |
string |
available_domains[].expiry_date |
string |
available_domains[].days_until_expiry |
integer |
available_domains[].notify_email |
string |
available_domains[].check_count |
integer |
total |
integer |
message |
string |
Alert webhooks
Receive monitoring alerts as signed JSON POST requests on your own HTTPS endpoints. Manage endpoints with an API key, or from Monitor settings while signed in.
Event types
| Monitor | Events |
|---|---|
| Watchlist availability, expiry and status | domain.available domain.expiring_30 domain.expiring_14 domain.expiring_7 domain.expiring_1 domain.status_change |
| Domain change monitoring | domain.dns_changed domain.certificate_changed domain.registration_changed domain.hosting_changed domain.technology_changed domain.email_security_changed |
| Brand monitoring (new lookalike registrations) | brand.threat_detected |
| Watchlist alert subscriptions (certificates, prices, DNS records, lookalikes) | ssl.expiring ssl.expired ssl.changed price.dropped dns.changed typosquat.detected |
| Async jobs (free, only for jobs created with notify_webhook) | job.completed job.failed job.cancelled |
| Test event (free) | webhook.test |
Read the webhook alerts API guide
Pricing
Each alert delivered to an endpoint with a 2xx response costs 2 credits. Credits are reserved just before the first attempt and refunded if the delivery fails, is cancelled or the endpoint is deleted. Test events are free. When the balance is too low, the alert is skipped and nothing is charged.
Register an HTTPS endpoint. The URL must resolve to a public address. Omit events, or pass ["*"], to receive every event type. The signing secret is returned only in this response.
Example request
curl -X POST "https://domscan.net/v1/webhooks" \
-H "X-API-Key: $DOMSCAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://hooks.example.com/domscan",
"events": ["domain.expiring_30", "domain.available", "domain.dns_changed"]
}'
Example response
{
"endpoint": {
"id": "whe_3f1c0a9b8e7d6c5b4a39281706f5e4d3",
"url": "https://hooks.example.com/domscan",
"events": ["domain.available", "domain.expiring_30", "domain.dns_changed"],
"status": "active",
"secret_hint": "9c2e"
},
"secret": "whsec_..."
}
Response fields
| Field | Type |
|---|---|
endpoint |
object |
endpoint.id |
string |
endpoint.url |
string |
endpoint.description |
string | null |
endpoint.events[] |
string[] |
endpoint.status |
string |
endpoint.disabled_reason |
string | null |
endpoint.consecutive_failures |
integer |
endpoint.secret_hint |
string |
endpoint.previous_secret_expires_at |
string | null |
endpoint.secret_rotated_at |
string | null |
endpoint.last_success_at |
string | null |
endpoint.last_failure_at |
string | null |
endpoint.last_error |
string | null |
endpoint.created_at |
string |
endpoint.updated_at |
string |
endpoint.disabled_at |
string | null |
secret |
string |
List your endpoints with their status, subscribed events, failure count and the last four characters of the secret, together with the available event types and the delivery policy.
Response fields
| Field | Type |
|---|---|
endpoints[] |
object[] |
endpoints[] |
object |
endpoints[].id |
string |
endpoints[].url |
string |
endpoints[].description |
string | null |
endpoints[].events[] |
string[] |
endpoints[].status |
string |
endpoints[].disabled_reason |
string | null |
endpoints[].consecutive_failures |
integer |
endpoints[].secret_hint |
string |
endpoints[].previous_secret_expires_at |
string | null |
endpoints[].secret_rotated_at |
string | null |
endpoints[].last_success_at |
string | null |
endpoints[].last_failure_at |
string | null |
endpoints[].last_error |
string | null |
endpoints[].created_at |
string |
endpoints[].updated_at |
string |
endpoints[].disabled_at |
string | null |
available_events[] |
string[] |
all_events |
string |
test_event |
string |
policy |
object |
policy.secret_rotation_grace_seconds |
integer |
policy.secret_rotation_credits |
integer |
policy.credits_per_delivered_alert |
integer |
policy.test_event_credits |
integer |
policy.job_event_credits |
integer |
policy.failed_deliveries_charged |
boolean |
policy.max_endpoints |
integer |
policy.max_attempts |
integer |
policy.disable_after_consecutive_failures |
integer |
policy.signature_tolerance_seconds |
integer |
Example response
{
"endpoints": [
{
"id": "example-id",
"url": "https://example.com",
"events": [
"example"
],
"status": "active",
"secret_hint": "example",
"created_at": "2026-08-27T12:00:00Z",
"description": "example",
"disabled_reason": "customer",
"consecutive_failures": 1,
"previous_secret_expires_at": "2026-08-27T12:00:00Z",
"secret_rotated_at": "2026-08-27T12:00:00Z",
"last_success_at": "2026-08-27T12:00:00Z",
"last_failure_at": "2026-08-27T12:00:00Z",
"last_error": "example",
"updated_at": "2026-08-27T12:00:00Z",
"disabled_at": "2026-08-27T12:00:00Z"
}
],
"available_events": [
"domain.available"
],
"policy": {
"credits_per_delivered_alert": 2,
"test_event_credits": 0,
"failed_deliveries_charged": false,
"max_endpoints": 1,
"max_attempts": 1,
"disable_after_consecutive_failures": 1,
"signature_tolerance_seconds": 1,
"secret_rotation_grace_seconds": 86400,
"secret_rotation_credits": 0,
"job_event_credits": 0
},
"all_events": "*",
"test_event": "webhook.test"
}
Pause or enable an endpoint, change its events or edit its description. Enabling an endpoint resets its failure count.
{ "enabled": true, "events": ["*"] }
Response fields
| Field | Type |
|---|---|
endpoint |
object |
endpoint.id |
string |
endpoint.url |
string |
endpoint.description |
string | null |
endpoint.events[] |
string[] |
endpoint.status |
string |
endpoint.disabled_reason |
string | null |
endpoint.consecutive_failures |
integer |
endpoint.secret_hint |
string |
endpoint.previous_secret_expires_at |
string | null |
endpoint.secret_rotated_at |
string | null |
endpoint.last_success_at |
string | null |
endpoint.last_failure_at |
string | null |
endpoint.last_error |
string | null |
endpoint.created_at |
string |
endpoint.updated_at |
string |
endpoint.disabled_at |
string | null |
Example response
{
"endpoint": {
"id": "example-id",
"url": "https://example.com",
"events": [
"example"
],
"status": "active",
"secret_hint": "example",
"created_at": "2026-08-27T12:00:00Z",
"description": "example",
"disabled_reason": "customer",
"consecutive_failures": 1,
"previous_secret_expires_at": "2026-08-27T12:00:00Z",
"secret_rotated_at": "2026-08-27T12:00:00Z",
"last_success_at": "2026-08-27T12:00:00Z",
"last_failure_at": "2026-08-27T12:00:00Z",
"last_error": "example",
"updated_at": "2026-08-27T12:00:00Z",
"disabled_at": "2026-08-27T12:00:00Z"
}
}
Delete an endpoint. Pending deliveries are cancelled and any reserved credits are refunded.
Response fields
| Field | Type |
|---|---|
id |
string |
deleted |
boolean |
Example response
{
"id": "example-id",
"deleted": true
}
Send one free webhook.test event and return the result. Test events are not retried and do not count toward automatic pausing.
Response fields
| Field | Type |
|---|---|
delivery |
object |
delivery.id |
string |
delivery.endpoint_id |
string |
delivery.event_id |
string |
delivery.event_type |
string |
delivery.status |
string |
delivery.attempts |
integer |
delivery.next_attempt_at |
string | null |
delivery.last_attempt_at |
string | null |
delivery.response_status |
integer | null |
delivery.last_error |
string | null |
delivery.credits_charged |
integer |
delivery.refunded |
boolean |
delivery.created_at |
string |
delivery.delivered_at |
string | null |
delivered |
boolean |
Example response
{
"delivery": {
"id": "example-id",
"endpoint_id": "example",
"event_id": "example",
"event_type": "domain",
"status": "pending",
"attempts": 1,
"next_attempt_at": "2026-08-27T12:00:00Z",
"last_attempt_at": "2026-08-27T12:00:00Z",
"response_status": 1,
"last_error": "example",
"credits_charged": 1,
"refunded": false,
"created_at": "2026-08-27T12:00:00Z",
"delivered_at": "2026-08-27T12:00:00Z"
},
"delivered": false
}
Replace the signing secret of an endpoint, including a paused one. The new secret is returned only in this response. For the next 24 hours each delivery is signed with both the new and the previous secret. Rotating is free.
Example request
curl -X POST "https://domscan.net/v1/webhooks/whe_3f1c0a9b8e7d6c5b4a39281706f5e4d3/rotate-secret" \
-H "X-API-Key: $DOMSCAN_API_KEY"
Example response
{
"endpoint": {
"id": "whe_3f1c0a9b8e7d6c5b4a39281706f5e4d3",
"status": "active",
"secret_hint": "4b7a",
"previous_secret_expires_at": "2026-10-11T12:00:00.000Z"
},
"secret": "whsec_...",
"previous_secret_expires_at": "2026-10-11T12:00:00.000Z",
"grace_period_seconds": 86400
}
Response fields
| Field | Type |
|---|---|
endpoint |
object |
endpoint.id |
string |
endpoint.url |
string |
endpoint.description |
string | null |
endpoint.events[] |
string[] |
endpoint.status |
string |
endpoint.disabled_reason |
string | null |
endpoint.consecutive_failures |
integer |
endpoint.secret_hint |
string |
endpoint.previous_secret_expires_at |
string | null |
endpoint.secret_rotated_at |
string | null |
endpoint.last_success_at |
string | null |
endpoint.last_failure_at |
string | null |
endpoint.last_error |
string | null |
endpoint.created_at |
string |
endpoint.updated_at |
string |
endpoint.disabled_at |
string | null |
secret |
string |
previous_secret_expires_at |
string |
grace_period_seconds |
integer |
Query parameters
| Parameter | Type | Description |
|---|---|---|
| limit | integer | Number of deliveries to return, from 1 to 100. Default 50. |
List recent deliveries with their status, attempts, HTTP response, credits charged and refunds. Delivery records are kept for 30 days.
Response fields
| Field | Type |
|---|---|
endpoint_id |
string |
deliveries[] |
object[] |
deliveries[] |
object |
deliveries[].id |
string |
deliveries[].endpoint_id |
string |
deliveries[].event_id |
string |
deliveries[].event_type |
string |
deliveries[].status |
string |
deliveries[].attempts |
integer |
deliveries[].next_attempt_at |
string | null |
deliveries[].last_attempt_at |
string | null |
deliveries[].response_status |
integer | null |
deliveries[].last_error |
string | null |
deliveries[].credits_charged |
integer |
deliveries[].refunded |
boolean |
deliveries[].created_at |
string |
deliveries[].delivered_at |
string | null |
Example response
{
"endpoint_id": "example",
"deliveries": [
{
"id": "example-id",
"endpoint_id": "example",
"event_id": "example",
"event_type": "domain",
"status": "pending",
"attempts": 1,
"next_attempt_at": "2026-08-27T12:00:00Z",
"last_attempt_at": "2026-08-27T12:00:00Z",
"response_status": 1,
"last_error": "example",
"credits_charged": 1,
"refunded": false,
"created_at": "2026-08-27T12:00:00Z",
"delivered_at": "2026-08-27T12:00:00Z"
}
]
}
Request format
Each alert is a POST request with a JSON body. The id field stays the same for an event and is repeated in X-DomScan-Event-Id, so you can ignore retries you have already processed.
POST /domscan HTTP/1.1
Content-Type: application/json
X-DomScan-Event: domain.expiring_30
X-DomScan-Event-Id: evt_6f1d2c3b4a5948e7b6c5d4e3f2a1b0c9
X-DomScan-Timestamp: 1791633600
X-DomScan-Signature: sha256=...
{
"id": "evt_6f1d2c3b4a5948e7b6c5d4e3f2a1b0c9",
"type": "domain.expiring_30",
"created": "2026-10-10T12:00:00.000Z",
"data": {
"domain": "acme.io",
"previous_status": "registered",
"current_status": "expiring_soon",
"expiry_date": "2026-11-09T00:00:00Z",
"days_until_expiry": 30,
"checked_at": "2026-10-10T12:00:00.000Z"
}
}
Verify signatures
Compute an HMAC-SHA256 of the X-DomScan-Timestamp value, a period and the raw request body using your endpoint secret. Compare the result with X-DomScan-Signature in constant time and reject requests whose timestamp is more than 5 minutes old.
The sample below checks every signature in the header, so it keeps working during a secret rotation.
import crypto from 'node:crypto';
// rawBody: the request body exactly as received, before JSON parsing.
function verifyDomScanWebhook(rawBody, headers, secret) {
const timestamp = headers['x-domscan-timestamp'];
const header = headers['x-domscan-signature'] || '';
if (!/^\d{10}$/.test(timestamp || '')) return false;
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const expected = Buffer.from('sha256=' + crypto
.createHmac('sha256', secret)
.update(timestamp + '.' + rawBody)
.digest('hex'));
// One entry normally; two during a secret rotation (new secret first).
return header.split(',').some((entry) => {
const candidate = Buffer.from(entry.trim());
return candidate.length === expected.length &&
crypto.timingSafeEqual(candidate, expected);
});
}
Rotate a signing secret
During the 24 hour grace period after a rotation, X-DomScan-Signature holds two signatures separated by a comma, with the new secret first, as shown below. Accept a request when any entry matches a secret you trust, deploy the new secret, then stop trusting the old one. Rotating again during the grace period retires the older previous secret at once.
X-DomScan-Signature: sha256=<new>,sha256=<previous>
Retries and automatic pausing
Return any 2xx status within 8 seconds to acknowledge an alert. Redirects, other status codes and timeouts are retried with exponential backoff (1, 4, 16, 64 and 256 minutes), up to 6 attempts in total. After 15 consecutive failed attempts the endpoint is paused; enable it again with PATCH or from Monitor settings.
When an endpoint is paused after repeated failures, the owner of the endpoint receives one email with the endpoint host, the last error and a link to Monitor settings. Fix the endpoint, then enable it again from Monitor settings or with PATCH and enabled set to true. Enabling resets the failure count to zero.
Watchlist alert subscriptions
Subscribe a watched item to the alerts you want. Each subscription watches one hostname, TLD or brand domain, and you choose which of its events to receive. Events go to your signed webhook endpoints and to your in-app alerts.
| Type | Events | When it fires |
|---|---|---|
ssl | ssl.expiring ssl.expired ssl.changed | ssl.expiring when the certificate a hostname serves expires within ssl_expiring_days (30, 14, 7 or 1, default 14), once per certificate and threshold. ssl.expired once per expired certificate. ssl.changed when a new certificate fingerprint is seen on two consecutive checks; the payload says whether the issuer changed. |
price | price.dropped | When the registration or renewal price of a TLD, at one registrar or the cheapest one, falls by at least drop_percent from the highest price since the last alert, or reaches target_price or less. Prices come from the daily pricing snapshot, and each snapshot is evaluated once. |
dns | dns.changed | When a watched record type (A, AAAA, MX, NS, TXT or CNAME) of any hostname returns the same new answer on two consecutive confirmed lookups. |
typosquat | typosquat.detected | When a lookalike of the brand domain is newly registered, confirmed by an authoritative registration lookup. The first full pass over the lookalikes sets the baseline and does not alert. |
Only exact evidence triggers an event. A failed TLS handshake, a DNS lookup that fails or times out, a missing price and a lookup that is blocked or rate limited are unknown: they change nothing and never alert or charge. The first confirmed check of a subscription sets its baseline.
Checks run automatically: certificates every 12 hours, DNS records every hour (with a confirming check 15 minutes after a change is first seen), prices every 2 hours against the daily snapshot, and lookalikes in batches of 30 with a full pass every day. After an unknown check the next attempt comes sooner.
Creating subscriptions and running checks is free. Each alert delivered to a webhook endpoint with a 2xx response costs 2 credits, like every other monitoring alert. Failed deliveries are refunded, and an account can have up to 100 subscriptions, 20 of them for lookalikes.
Create a subscription. type decides which fields apply: domain for ssl, dns and typosquat; tld, registrar, price_type, drop_percent and target_price for price. Fields that do not apply to the type are rejected.
Request body
| Parameter | Type | Description |
|---|---|---|
| type | string | ssl, price, dns or typosquat. Required. |
| domain | string | Hostname to watch for ssl and dns, or the brand domain for typosquat. |
| tld | string | TLD to watch for price, for example com. |
| registrar | string | Registrar id for price. Omit it to watch the cheapest registrar. |
| events | string[] | Events to receive. Defaults to every event of the type. |
| ssl_expiring_days | integer | Days before expiry for ssl.expiring: 30, 14, 7 or 1. Default 14. |
| price_type | string | registration (default) or renewal. |
| drop_percent | number | Alert on a drop of at least this percentage, 1 to 95. |
| target_price | number | Alert when the price in USD reaches this amount or less. A price subscription needs drop_percent, target_price or both. |
| record_types | string[] | Record types to watch for dns. Defaults to A, AAAA, MX, NS, TXT and CNAME. |
Example request
curl -X POST "https://domscan.net/v1/watchlist/alerts" \
-H "X-API-Key: $DOMSCAN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"type": "price",
"tld": "com",
"registrar": "porkbun",
"price_type": "renewal",
"drop_percent": 10,
"target_price": 9.5
}'
Example response
{
"subscription": {
"id": "mas_8c1f0e2d3b4a59687766554433221100",
"type": "price",
"target": "com",
"registrar": "porkbun",
"events": ["price.dropped"],
"status": "active",
"price_type": "renewal",
"drop_percent": 10,
"target_price": 9.5,
"currency": "USD",
"observed": null,
"last_check_status": null,
"next_check_at": "2026-10-10T12:00:00.000Z"
}
}
Response fields
| Field | Type |
|---|---|
subscription |
object |
subscription.id |
string |
subscription.type |
string |
subscription.target |
string |
subscription.registrar |
string | null |
subscription.events[] |
string[] |
subscription.status |
string |
subscription.ssl_expiring_days |
integer | null |
subscription.price_type |
string | null |
subscription.drop_percent |
number | null |
subscription.target_price |
number | null |
subscription.currency |
string | null |
subscription.record_types[] |
string[] |
subscription.observed |
object | null |
subscription.last_check_at |
string | null |
subscription.last_check_status |
string | null |
subscription.last_error |
string | null |
subscription.next_check_at |
string | null |
subscription.created_at |
string |
subscription.updated_at |
string |
List your subscriptions with their latest confirmed evidence and check status, the events each type supports, the check schedule and the alert price.
Response fields
| Field | Type |
|---|---|
subscriptions[] |
object[] |
subscriptions[] |
object |
subscriptions[].id |
string |
subscriptions[].type |
string |
subscriptions[].target |
string |
subscriptions[].registrar |
string | null |
subscriptions[].events[] |
string[] |
subscriptions[].status |
string |
subscriptions[].ssl_expiring_days |
integer | null |
subscriptions[].price_type |
string | null |
subscriptions[].drop_percent |
number | null |
subscriptions[].target_price |
number | null |
subscriptions[].currency |
string | null |
subscriptions[].record_types[] |
string[] |
subscriptions[].observed |
object | null |
subscriptions[].last_check_at |
string | null |
subscriptions[].last_check_status |
string | null |
subscriptions[].last_error |
string | null |
subscriptions[].next_check_at |
string | null |
subscriptions[].created_at |
string |
subscriptions[].updated_at |
string |
total |
integer |
available_types |
object |
available_types.ssl[] |
string[] |
available_types.price[] |
string[] |
available_types.dns[] |
string[] |
available_types.typosquat[] |
string[] |
policy |
object |
policy.credits_per_delivered_alert |
integer |
policy.check_credits |
integer |
policy.unknown_checks_charged |
boolean |
policy.max_subscriptions |
integer |
policy.max_typosquat_subscriptions |
integer |
policy.ssl_expiring_days[] |
integer[] |
policy.default_ssl_expiring_days |
integer |
policy.record_types[] |
string[] |
policy.price_types[] |
string[] |
policy.check_interval_minutes |
object |
policy.confirmation_checks |
object |
Example response
{
"subscriptions": [
{
"id": "example-id",
"type": "ssl",
"target": "example",
"registrar": "example",
"events": [
"ssl.expiring"
],
"status": "active",
"ssl_expiring_days": 30,
"price_type": "registration",
"drop_percent": 0.5,
"target_price": 0.5,
"currency": "USD",
"record_types": [
"A"
],
"observed": {},
"last_check_at": "2026-08-27T12:00:00Z",
"last_check_status": "baseline",
"last_error": "example",
"next_check_at": "2026-08-27T12:00:00Z",
"created_at": "2026-08-27T12:00:00Z",
"updated_at": "2026-08-27T12:00:00Z"
}
],
"total": 1,
"available_types": {
"ssl": [
"ssl.expiring"
],
"price": [
"price.dropped"
],
"dns": [
"dns.changed"
],
"typosquat": [
"typosquat.detected"
]
},
"policy": {
"credits_per_delivered_alert": 2,
"check_credits": 0,
"unknown_checks_charged": false,
"max_subscriptions": 1,
"check_interval_minutes": {},
"max_typosquat_subscriptions": 1,
"ssl_expiring_days": [
1
],
"default_ssl_expiring_days": 1,
"record_types": [
"A"
],
"price_types": [
"registration"
],
"confirmation_checks": {}
}
}
Get one subscription with its latest confirmed evidence and its 20 most recent events.
Response fields
| Field | Type |
|---|---|
subscription |
object |
subscription.id |
string |
subscription.type |
string |
subscription.target |
string |
subscription.registrar |
string | null |
subscription.events[] |
string[] |
subscription.status |
string |
subscription.ssl_expiring_days |
integer | null |
subscription.price_type |
string | null |
subscription.drop_percent |
number | null |
subscription.target_price |
number | null |
subscription.currency |
string | null |
subscription.record_types[] |
string[] |
subscription.observed |
object | null |
subscription.last_check_at |
string | null |
subscription.last_check_status |
string | null |
subscription.last_error |
string | null |
subscription.next_check_at |
string | null |
subscription.created_at |
string |
subscription.updated_at |
string |
events[] |
object[] |
events[] |
object |
events[].id |
string |
events[].event_type |
string |
events[].detected_at |
string |
events[].published_at |
string | null |
events[].data |
object |
Example response
{
"subscription": {
"id": "example-id",
"type": "ssl",
"target": "example",
"registrar": "example",
"events": [
"ssl.expiring"
],
"status": "active",
"ssl_expiring_days": 30,
"price_type": "registration",
"drop_percent": 0.5,
"target_price": 0.5,
"currency": "USD",
"record_types": [
"A"
],
"observed": {},
"last_check_at": "2026-08-27T12:00:00Z",
"last_check_status": "baseline",
"last_error": "example",
"next_check_at": "2026-08-27T12:00:00Z",
"created_at": "2026-08-27T12:00:00Z",
"updated_at": "2026-08-27T12:00:00Z"
},
"events": [
{
"id": "example-id",
"event_type": "ssl.expiring",
"detected_at": "2026-08-27T12:00:00Z",
"published_at": "2026-08-27T12:00:00Z",
"data": {}
}
]
}
Pause or resume a subscription with enabled, or change its events, ssl_expiring_days, drop_percent, target_price or record_types. A new target price only alerts on a later price movement.
{ "enabled": false }
Response fields
| Field | Type |
|---|---|
subscription |
object |
subscription.id |
string |
subscription.type |
string |
subscription.target |
string |
subscription.registrar |
string | null |
subscription.events[] |
string[] |
subscription.status |
string |
subscription.ssl_expiring_days |
integer | null |
subscription.price_type |
string | null |
subscription.drop_percent |
number | null |
subscription.target_price |
number | null |
subscription.currency |
string | null |
subscription.record_types[] |
string[] |
subscription.observed |
object | null |
subscription.last_check_at |
string | null |
subscription.last_check_status |
string | null |
subscription.last_error |
string | null |
subscription.next_check_at |
string | null |
subscription.created_at |
string |
subscription.updated_at |
string |
Example response
{
"subscription": {
"id": "example-id",
"type": "ssl",
"target": "example",
"registrar": "example",
"events": [
"ssl.expiring"
],
"status": "active",
"ssl_expiring_days": 30,
"price_type": "registration",
"drop_percent": 0.5,
"target_price": 0.5,
"currency": "USD",
"record_types": [
"A"
],
"observed": {},
"last_check_at": "2026-08-27T12:00:00Z",
"last_check_status": "baseline",
"last_error": "example",
"next_check_at": "2026-08-27T12:00:00Z",
"created_at": "2026-08-27T12:00:00Z",
"updated_at": "2026-08-27T12:00:00Z"
}
}
Delete a subscription. Events it has not sent yet are dropped and never charged.
Response fields
| Field | Type |
|---|---|
id |
string |
deleted |
boolean |
Example response
{
"id": "example-id",
"deleted": true
}
Example dns.changed event
{
"id": "evt_2b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e",
"type": "dns.changed",
"created": "2026-10-10T12:15:00.000Z",
"data": {
"domain": "partner-shop.example",
"changes": [
{
"record_type": "MX",
"before": ["10 mx1.mail.example"],
"after": ["10 mx.other-mail.example"],
"added": ["10 mx.other-mail.example"],
"removed": ["10 mx1.mail.example"],
"first_seen_at": "2026-10-10T12:00:00.000Z"
}
],
"confirmed_checks": 2,
"confirmed_at": "2026-10-10T12:15:00.000Z",
"subscription_id": "mas_8c1f0e2d3b4a59687766554433221100"
}
}