> For the complete documentation index see https://domscan.net/llms.txt. Markdown versions of every docs page are available by appending .md to the page URL.

Source: https://domscan.net/ja/docs/watchlist

# ドメイン ウォッチリスト

DomScan APIでドメインの失効と可用性の変更を監視します。登録されたドメインが利用可能になるとアラートを取得します。

ドメインの失効と可用性の変更を監視します。登録されたドメインが利用可能になるとアラートを取得します。

**モニター**

Googleでサインインして、メールアラート、Webhooks、その他を備えたパーソナライズされたドメインウォッチリストにアクセスしてください。

メール、Telegram、Slack、Discord、またはWebhookから通知を受け取ります。

[モニター](https://domscan.net/ja/monitor)
[設定](https://domscan.net/ja/monitor/settings)
[ブランドモニタリング](https://domscan.net/ja/brand-monitor-api)

GET /v1/watchlist

ウォッチリスト内のすべてのドメインを取得します。

#### レスポンス例

```json
{
                "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": "alerts@example.com",
                "check_count": 4
                }
                ],
                "total": 1,
                "updated_at": "2024-03-01T12:00:00Z"
                }
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

POST /v1/watchlist

ウォッチリストにドメインを追加します。

#### リクエストボディ

```json
{
                "domain": "mydomain.com",
                "notify_email": "alerts@example.com"
                }
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

#### レスポンス例

```json
{
  "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": "alerts@example.com"
    },
    {
      "domain": "example.org",
      "added_at": "2026-10-09T10:15:30.000Z",
      "status": "unknown",
      "notify_email": "alerts@example.com"
    }
  ],
  "total": 2
}
```

DELETE /v1/watchlist?domain=mydomain.com

ウォッチリストから削除

```bash
curl -X DELETE -H "X-API-Key: your-api-key" "https://domscan.net/v1/watchlist?domain=mydomain.com"
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

#### レスポンス例

```json
{
  "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": "user@example.com",
      "check_count": 1
    }
  ],
  "total": 1
}
```

GET /v1/watchlist/expiring?days=30

間もなく有効期限切れ

#### レスポンス例

```json
{
                "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
                }
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

GET /v1/watchlist/available

利用可能

ページネーション対応: `limit` (1 から 100) を送信し、`next_cursor` を `cursor` として渡します。レスポンスには `has_more` と `next_cursor` が含まれます。`limit` を指定しない場合は、リスト全体が返されます。[ページネーション](https://domscan.net/docs/response-format#pagination)を参照してください。

#### レスポンス例

```json
{
                "available_domains": [
                {
                "domain": "startupdrop.ai",
                "status": "available",
                "last_checked": "2026-04-14T08:30:00Z",
                "check_count": 18
                }
                ],
                "total": 1,
                "message": "ウォッチリストのこれらのドメインが登録可能になりました！"
                }
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

### アラート Webhook

監視アラートを、署名付きの JSON POST リクエストとして、ご自身の HTTPS エンドポイントで受信できます。エンドポイントは API キーで管理するほか、サインイン中はモニター設定からも管理できます。

#### イベントタイプ

| モニター | イベント |
| --- | --- |
| ウォッチリストの空き状況、有効期限、ステータス | `domain.available`, `domain.expiring_30`, `domain.expiring_14`, `domain.expiring_7`, `domain.expiring_1`, `domain.status_change` |
| ドメイン変更の監視 | `domain.dns_changed`, `domain.certificate_changed`, `domain.registration_changed`, `domain.hosting_changed`, `domain.technology_changed`, `domain.email_security_changed` |
| ブランド監視（類似ドメインの新規登録） | `brand.threat_detected` |
| ウォッチリストのアラート購読 (証明書、価格、DNS レコード、類似ドメイン) | `ssl.expiring`, `ssl.expired`, `ssl.changed`, `price.dropped`, `dns.changed`, `typosquat.detected` |
| 非同期ジョブ(無料、notify_webhook を指定して作成したジョブのみ) | `job.completed`, `job.failed`, `job.cancelled` |
| テストイベント（無料） | `webhook.test` |

[Webhook アラート API ガイドを読む](https://domscan.net/ja/webhook-alerts-api)

#### 料金

2xx レスポンスでエンドポイントに配信できたアラートは 1 件につき 2 クレジットです。クレジットは最初の送信の直前に確保され、配信が失敗した場合、キャンセルされた場合、またはエンドポイントが削除された場合は返金されます。テストイベントは無料です。残高が不足しているときはアラートがスキップされ、課金は発生しません。

POST /v1/webhooks

HTTPS エンドポイントを登録します。URL は公開アドレスに解決される必要があります。events を省略するか ["*"] を渡すと、すべてのイベントタイプを受信します。署名シークレットが返されるのは、このレスポンスだけです。

#### リクエスト例

```bash
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"]
  }'
```

#### レスポンス例

```json
{
  "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_..."
}
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

GET /v1/webhooks

登録済みのエンドポイントを、ステータス、購読中のイベント、失敗回数、シークレットの末尾 4 文字とともに一覧表示します。利用可能なイベントタイプと配信ポリシーも含まれます。

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

#### レスポンス例

```json
{
  "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"
}
```

PATCH /v1/webhooks/:webhook_id

エンドポイントの一時停止と再開、イベントの変更、説明の編集を行います。エンドポイントを有効にすると、失敗回数はリセットされます。

```json
{ "enabled": true, "events": ["*"] }
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

#### レスポンス例

```json
{
  "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 /v1/webhooks/:webhook_id

エンドポイントを削除します。保留中の配信はキャンセルされ、確保済みのクレジットは返金されます。

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `id` | string |
| `deleted` | boolean |

#### レスポンス例

```json
{
  "id": "example-id",
  "deleted": true
}
```

POST /v1/webhooks/:webhook_id/test

無料の webhook.test イベントを 1 件送信し、結果を返します。テストイベントは再試行されず、自動一時停止の回数にも含まれません。

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

#### レスポンス例

```json
{
  "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
}
```

POST /v1/webhooks/:webhook_id/rotate-secret

一時停止中のエンドポイントを含め、エンドポイントの署名シークレットを新しいものに置き換えます。新しいシークレットはこのレスポンスでのみ返されます。以後 24 時間は、各配信に新旧両方のシークレットで署名します。ローテーションは無料です。

#### リクエスト例

```bash
curl -X POST "https://domscan.net/v1/webhooks/whe_3f1c0a9b8e7d6c5b4a39281706f5e4d3/rotate-secret" \
  -H "X-API-Key: $DOMSCAN_API_KEY"
```

#### レスポンス例

```json
{
  "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
}
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

GET /v1/webhooks/:webhook_id/deliveries

#### クエリパラメータ

| パラメータ | タイプ | 説明 |
| --- | --- | --- |
| limit | integer | 返す配信の件数（1 から 100）。デフォルトは 50 です。 |

最近の配信を、ステータス、試行回数、HTTP レスポンス、課金されたクレジット、返金とともに一覧表示します。配信記録は 30 日間保持されます。

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

#### レスポンス例

```json
{
  "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"
    }
  ]
}
```

#### リクエスト形式

各アラートは、JSON 本文を持つ POST リクエストです。id フィールドは同じイベントでは変わらず、X-DomScan-Event-Id にも同じ値が入るため、処理済みの再試行は無視できます。

```http
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"
  }
}
```

#### 署名の検証

エンドポイントのシークレットを使い、X-DomScan-Timestamp の値、ピリオド、そして生のリクエスト本文をこの順に連結したデータの HMAC-SHA256 を計算します。結果を X-DomScan-Signature と定数時間で比較し、タイムスタンプが 5 分より古いリクエストは拒否してください。

以下のサンプルはヘッダー内のすべての署名を確認するため、シークレットのローテーション中も動作し続けます。

```javascript
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);
  });
}
```

#### 署名シークレットのローテーション

ローテーション後の 24 時間の猶予期間中は、X-DomScan-Signature にカンマ区切りで 2 つの署名が入り、先頭が新しいシークレットのものです。以下の例のとおり、いずれかの値が信頼するシークレットと一致すればリクエストを受け入れてください。新しいシークレットを展開したら、古いシークレットを信頼対象から外します。猶予期間中にもう一度ローテーションすると、さらに古い以前のシークレットは直ちに無効になります。

```http
X-DomScan-Signature: sha256=<new>,sha256=<previous>
```

#### 再試行と自動一時停止

アラートを受け取ったことを知らせるには、8 秒以内に任意の 2xx ステータスを返してください。リダイレクト、その他のステータスコード、タイムアウトは、指数バックオフ（1、4、16、64、256 分）で再試行され、合計で最大 6 回まで試行されます。連続 15 回失敗するとエンドポイントは一時停止されます。PATCH またはモニター設定から再び有効にしてください。

失敗が続いてエンドポイントが一時停止されると、エンドポイントの所有者に、エンドポイントのホスト、最後のエラー、モニター設定へのリンクを記載したメールが 1 通届きます。エンドポイントを修正したら、モニター設定から、または PATCH で enabled を true にして再び有効にしてください。有効にすると失敗回数は 0 にリセットされます。

### ウォッチリストのアラート購読

監視対象の項目に、受け取りたいアラートを購読します。各購読は 1 つのホスト名、TLD、またはブランドドメインを監視し、受け取るイベントを選択できます。イベントは署名付き Webhook エンドポイントとアプリ内アラートに送信されます。

| 種類 | イベント | 発火条件 |
| --- | --- | --- |
| `ssl` | `ssl.expiring`, `ssl.expired`, `ssl.changed` | ssl.expiring は、ホスト名が提供する証明書が ssl_expiring_days (30、14、7、1 のいずれか、デフォルトは 14) 以内に期限切れになるときに、証明書としきい値ごとに 1 回発火します。ssl.expired は期限切れの証明書ごとに 1 回発火します。ssl.changed は、新しい証明書フィンガープリントが 2 回連続のチェックで確認されたときに発火し、ペイロードには発行元が変わったかどうかが含まれます。 |
| `price` | `price.dropped` | TLD の登録価格または更新価格が、特定のレジストラまたは最安のレジストラで、前回のアラート以降の最高価格から drop_percent 以上下落したとき、または target_price 以下になったときに発火します。価格は毎日の価格スナップショットから取得し、各スナップショットは 1 回だけ評価されます。 |
| `dns` | `dns.changed` | 監視中のレコードタイプ (A、AAAA、MX、NS、TXT、CNAME) について、任意のホスト名が 2 回連続の確認済みルックアップで同じ新しい応答を返したときに発火します。 |
| `typosquat` | `typosquat.detected` | ブランドドメインの類似ドメインが新たに登録され、権威ある登録情報の照会で確認されたときに発火します。類似ドメインの最初の全件チェックはベースラインを設定するだけで、アラートは送信されません。 |

正確な証拠がある場合にのみイベントが発生します。TLS ハンドシェイクの失敗、失敗またはタイムアウトした DNS ルックアップ、価格の欠落、ブロックまたはレート制限されたルックアップは不明として扱われ、何も変更せず、アラートも課金も発生しません。購読の最初の確認済みチェックでベースラインが設定されます。

チェックは自動で実行されます。証明書は 12 時間ごと、DNS レコードは 1 時間ごと (変更を最初に検知してから 15 分後に確認チェックを実施)、価格は毎日のスナップショットに対して 2 時間ごと、類似ドメインは 30 件ずつのバッチで実行され、毎日全件を一巡します。不明な結果になった場合は、次の試行が早まります。

購読の作成とチェックの実行は無料です。2xx レスポンスで Webhook エンドポイントに配信された各アラートは、他のモニタリングアラートと同様に 2 クレジットかかります。配信に失敗した分は返金されます。1 アカウントあたり最大 100 件の購読を作成でき、そのうち類似ドメイン用は 20 件までです。

POST /v1/watchlist/alerts

購読を作成します。type によって使用できるフィールドが決まります。ssl、dns、typosquat では domain、price では tld、registrar、price_type、drop_percent、target_price を使用します。その type に該当しないフィールドは拒否されます。

#### リクエストボディ

| パラメータ | タイプ | 説明 |
| --- | --- | --- |
| type | string | ssl、price、dns、typosquat のいずれか。必須。 |
| domain | string | ssl と dns では監視するホスト名、typosquat ではブランドドメイン。 |
| tld | string | price で監視する TLD。例: com。 |
| registrar | string | price 用のレジストラ ID。省略すると最安のレジストラを監視します。 |
| events | string[] | 受け取るイベント。デフォルトはその type のすべてのイベントです。 |
| ssl_expiring_days | integer | ssl.expiring の有効期限までの日数。30、14、7、1 のいずれか。デフォルトは 14。 |
| price_type | string | registration (デフォルト) または renewal。 |
| drop_percent | number | この割合以上の下落でアラートを送信します。1 から 95 の範囲。 |
| target_price | number | USD 建ての価格がこの金額以下になったときにアラートを送信します。価格の購読には drop_percent、target_price、またはその両方が必要です。 |
| record_types | string[] | dns で監視するレコードタイプ。デフォルトは A、AAAA、MX、NS、TXT、CNAME です。 |

#### リクエスト例

```bash
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
  }'
```

#### レスポンス例

```json
{
  "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"
  }
}
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

GET /v1/watchlist/alerts

購読の一覧を、最新の確認済み証拠とチェック状況、各 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 |

#### レスポンス例

```json
{
  "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 /v1/watchlist/alerts/:subscription_id

1 件の購読を、最新の確認済み証拠と直近 20 件のイベントとともに取得します。

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

#### レスポンス例

```json
{
  "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": {}
    }
  ]
}
```

PATCH /v1/watchlist/alerts/:subscription_id

enabled で購読を一時停止または再開するか、events、ssl_expiring_days、drop_percent、target_price、record_types を変更します。新しい目標価格は、その後の価格変動に対してのみアラートを送信します。

```json
{ "enabled": false }
```

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `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 |

#### レスポンス例

```json
{
  "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 /v1/watchlist/alerts/:subscription_id

購読を削除します。未送信のイベントは破棄され、課金されません。

#### レスポンスフィールド

| フィールド | タイプ |
| --- | --- |
| `id` | string |
| `deleted` | boolean |

#### レスポンス例

```json
{
  "id": "example-id",
  "deleted": true
}
```

#### dns.changed イベントの例

```json
{
  "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"
  }
}
```
