外部API リファレンス

SonaeTocのREST APIを使って、プログラム・CI/CDパイプライン・AIエージェントから監視を操作できます。 ベースURL: https://sonaetoc.com/v1

クイックスタート

1

APIキーを発行

ダッシュボードの 設定 > APIキー管理 からキーを作成します。キーは作成時に一度だけ表示されます。
2

最初のリクエストを送信

curl
curl https://sonaetoc.com/v1/tenant \
  -H "Authorization: Bearer sonaetoc_live_YOUR_API_KEY"
3

モニターを作成

curl
curl -X POST https://sonaetoc.com/v1/monitors \
  -H "Authorization: Bearer sonaetoc_live_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "本番トップページ",
    "type": "visual",
    "url": "https://example.com",
    "interval_minutes": 60,
    "visual_config": {
      "viewport": { "width": 1920, "height": 1080 },
      "threshold": 0.1,
      "wait_for": "networkidle",
      "full_page": true,
      "delay_ms": 1000
    }
  }'
APIキーはパスワードと同じです。リポジトリにコミットせず、環境変数で管理してください。

認証

すべてのリクエストに Authorization: Bearer ヘッダーが必要です。

Authorization: Bearer sonaetoc_live_xxxxxxxxxx

スコープ

キー作成時にスコープを制限できます。デフォルトは全権限です。

スコープ権限
monitors:readモニター設定の閲覧
monitors:writeモニターの作成・更新・削除
monitors:execute手動実行のトリガー
results:read監視結果の閲覧
crawls:readクロール結果の閲覧
crawls:writeクロールジョブの作成・削除
notifications:read通知設定の閲覧
notifications:write通知設定の作成・更新・削除

レスポンス形式

日時はすべて ISO 8601(UTC)です。

成功
{
  "data": { "id": "mon_xxx", "name": "..." },
  "meta": { "request_id": "req_abc123" }
}
一覧
{
  "data": [ ... ],
  "meta": {
    "request_id": "req_abc123",
    "has_more": true,
    "next_cursor": "eyJ..."
  }
}
エラー
{
  "error": {
    "code": "validation_error",
    "message": "name is required (1-100 chars)."
  },
  "meta": { "request_id": "req_abc123" }
}

モニター

GET/v1/monitorsmonitors:read

モニター一覧を取得

パラメータ説明
typestringvisual / healthcheck / motion
statusstringok / changed / error
is_activeboolean有効/無効でフィルタ
limitnumber取得件数(デフォルト20、最大100)
cursorstringページネーションカーソル
include_countbooleantrueで total_count を返却
POST/v1/monitorsmonitors:write

モニターを作成

ヘルスチェックの例
{
  "name": "API /health",
  "type": "healthcheck",
  "url": "https://api.example.com/health",
  "interval_minutes": 15,
  "healthcheck_config": {
    "method": "GET",
    "expected_status": 200,
    "timeout_ms": 10000
  }
}
モーションチェックの例
{
  "name": "ログインフロー",
  "type": "motion",
  "url": "https://example.com/login",
  "interval_minutes": 1440,
  "motion_config": {
    "viewport": { "width": 1920, "height": 1080 },
    "threshold": 0.5,
    "steps": [
      { "action": "fill", "selector": "#email", "value": "test@example.com" },
      { "action": "fill", "selector": "#password", "value": "secret", "is_secret": true },
      { "action": "click", "selector": "#submit", "wait_for_navigation": true }
    ]
  }
}
GET/v1/monitors/{id}monitors:read

モニター詳細を取得

PATCH/v1/monitors/{id}monitors:write

モニターを更新(シャローマージ、配列は全置換)

DELETE/v1/monitors/{id}monitors:write

モニターを削除(結果も自動削除)

POST/v1/monitors/{id}/executemonitors:execute

手動実行をトリガー(202 Accepted)

POST/v1/monitors/{id}/activatemonitors:write

モニターを有効化

POST/v1/monitors/{id}/deactivatemonitors:write

モニターを無効化

監視結果

GET/v1/monitors/{id}/resultsresults:read

結果一覧を取得

パラメータ説明
statusstringok / changed / error
fromstring開始日時(ISO 8601)
tostring終了日時(ISO 8601)
limitnumber取得件数(デフォルト20、最大100)
cursorstringページネーションカーソル

レスポンスはモニタータイプに応じて異なります:

ビジュアルチェックの結果
{
  "id": "result_xyz",
  "monitor_id": "mon_abc",
  "status": "changed",
  "is_manual": false,
  "visual": {
    "screenshot_url": "https://storage...(署名付き)",
    "previous_screenshot_url": "https://storage...",
    "diff_percentage": 3.5,
    "pixel_count": 12400
  },
  "executed_at": "2026-04-05T10:00:00Z"
}
ヘルスチェックの結果
{
  "id": "result_hc1",
  "monitor_id": "mon_hc",
  "status": "ok",
  "healthcheck": {
    "status_code": 200,
    "response_time_ms": 245,
    "error_message": null
  },
  "executed_at": "2026-04-05T10:00:00Z"
}
モーションチェックの結果
{
  "id": "result_mt1",
  "monitor_id": "mon_mt",
  "status": "changed",
  "motion": {
    "video_url": "https://storage...(署名付き)",
    "total_diff_percentage": 3.5,
    "steps_executed": 4,
    "steps_failed": 0,
    "frames": [
      { "step_index": 0, "label": "メール入力", "diff_percentage": 0, "status": "ok" },
      { "step_index": 2, "label": "ログイン", "diff_percentage": 3.5, "status": "changed" }
    ]
  },
  "executed_at": "2026-04-05T10:00:00Z"
}
GET/v1/monitors/{id}/results/latestresults:read

最新結果を1件取得(レスポンスは上記と同形式)

GET/v1/monitors/{id}/results/{resultId}results:read

結果詳細を取得(レスポンスは上記と同形式)

GET/v1/monitors/{id}/statsresults:read

統計情報を取得

パラメータ説明
periodstring24h / 7d / 30d(デフォルト 7d)
レスポンス例
{
  "monitor_id": "mon_abc",
  "period": "7d",
  "total_checks": 168,
  "status_counts": { "ok": 165, "changed": 2, "error": 1 },
  "uptime_percentage": 99.4,
  "avg_response_time_ms": 1250,
  "avg_diff_percentage": 0.03,
  "max_diff_percentage": 5.2
}
スクリーンショットURL・動画URLは署名付きで有効期限1時間です。期限切れ時は同じエンドポイントを再呼び出ししてください。

クロール

GET/v1/crawlscrawls:read

クロールジョブ一覧

POST/v1/crawlscrawls:write

クロールを開始(202 Accepted)

{
  "name": "example.com 構造チェック",
  "url": "https://example.com",
  "config": {
    "max_depth": 3,
    "max_pages": 100,
    "rendering": "javascript"
  }
}
GET/v1/crawls/{id}crawls:read

ジョブ詳細・進捗

GET/v1/crawls/{id}/pagescrawls:read

クロール済みページ一覧

DELETE/v1/crawls/{id}crawls:write

ジョブを削除

通知設定

GET/v1/notificationsnotifications:read

通知設定一覧

POST/v1/notificationsnotifications:write

通知設定を作成

Slack の例
{
  "name": "Slack通知",
  "type": "slack",
  "events": ["visual_changed", "healthcheck_down"],
  "slack_config": {
    "webhook_url": "https://hooks.slack.com/services/xxx/yyy/zzz"
  }
}
PATCH/v1/notifications/{id}notifications:write

通知設定を更新

DELETE/v1/notifications/{id}notifications:write

通知設定を削除

POST/v1/notifications/{id}/testnotifications:write

テスト通知を送信

テナント情報

GET/v1/tenant

プラン・使用量・制限値を取得

レスポンス例
{
  "id": "tenant_abc",
  "name": "My Company",
  "plan": "pro",
  "limits": {
    "max_visual": 5, "max_healthcheck": 10,
    "max_motion": 1, "max_crawls": 20,
    "min_interval_minutes": 10,
    "api_keys": 3,
    "api_requests_per_hour": 60,
    "api_requests_per_day": 500
  },
  "usage": {
    "visual_count": 3, "healthcheck_count": 5,
    "motion_count": 0, "crawls_this_month": 2,
    "api_keys_count": 1, "api_requests_today": 42
  }
}

レート制限

制限FreeProEnterprise
APIキー数1310
リクエスト/時3060300
リクエスト/日2005003,000

レスポンスヘッダー X-RateLimit-Remaining で残りリクエスト数を確認できます。 超過時は 429 が返り、X-RateLimit-Reset に再試行可能なUnixタイムスタンプが入ります。

エラーコード

HTTPcode原因と対処
400validation_errorリクエストボディが不正。message を確認してフィールドを修正
400invalid_requestURLがプライベートIPに解決される等。SSRF対策
401unauthorizedAPIキーが無効・期限切れ・未指定。Authorizationヘッダーを確認
403forbiddenスコープ不足。必要なスコープ付きのキーを使用
403plan_limit_exceededプラン上限に到達。不要なリソースを削除するかアップグレード
404not_foundリソースが存在しない。IDを確認
429rate_limit_exceededレート制限超過。X-RateLimit-Reset まで待機
500internal_errorサーバーエラー。しばらく待って再試行

CI/CD連携パターン

デプロイ後にビジュアルチェックを自動実行し、差分が閾値を超えたらパイプラインを失敗させる例です。

GitHub Actions
- name: Visual regression check
  env:
    API_KEY: ${{ secrets.SONAETOC_API_KEY }}
    MONITOR_ID: mon_xxxxxxxxxxxx
  run: |
    # 1. 手動実行をトリガー
    curl -sf -X POST \
      "https://sonaetoc.com/v1/monitors/$MONITOR_ID/execute" \
      -H "Authorization: Bearer $API_KEY"

    # 2. 結果が出るまで待機
    sleep 30

    # 3. 最新結果を取得して差分を確認
    RESULT=$(curl -sf \
      "https://sonaetoc.com/v1/monitors/$MONITOR_ID/results/latest" \
      -H "Authorization: Bearer $API_KEY")

    DIFF=$(echo "$RESULT" | jq -r '.data.visual.diff_percentage // 0')
    echo "Visual diff: $DIFF%"

    if (( $(echo "$DIFF > 5.0" | bc -l) )); then
      echo "::error::Visual regression detected ($DIFF%)"
      exit 1
    fi

冪等性(Idempotency-Key)

POSTリクエストに Idempotency-Key ヘッダーを付与すると、同じキーでの再リクエスト時にキャッシュされたレスポンスが返されます。ネットワークエラー時のリトライに安全です。

curl -X POST https://sonaetoc.com/v1/monitors \
  -H "Authorization: Bearer sonaetoc_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-123" \
  -d '{ ... }'
Idempotency-Keyは24時間有効です。UUIDの使用を推奨します。

ページネーション

一覧エンドポイントはカーソルベースのページネーションを使用します。meta.next_cursor を次のリクエストの cursor パラメータに渡します。

# 1ページ目
curl "https://sonaetoc.com/v1/monitors?limit=10" \
  -H "Authorization: Bearer $API_KEY"
# → meta.next_cursor: "eyJ..."

# 2ページ目
curl "https://sonaetoc.com/v1/monitors?limit=10&cursor=eyJ..." \
  -H "Authorization: Bearer $API_KEY"