メインコンテンツへスキップ
YUCTS Status

YUCTS Status をインストール

ホーム画面に追加すると、すぐに開けます。最後に読み込んだ状態はオフラインでも表示できます。

iPhone・iPad(Safari)の場合

  1. ツールバーの共有ボタンをタップします。
  2. 「ホーム画面に追加」を選びます。
  3. 「追加」をタップします。

Mac(Safari)の場合

「ファイル」›「Dock に追加」を選びます(macOS Sonoma 以降)。

Chrome・Edge・Android の場合

下のインストールボタン、またはアドレスバーやブラウザーのメニューにあるインストールアイコンを使います。

ウェブアプリをインストールできないブラウザーでは、このページをブックマークしてください。

開発者向け情報・API

ステータス・インシデント・メンテナンス情報を取得できる公開 REST API と、埋め込みウィジェット、バッジ、フィード、カレンダーを提供しています。

はじめに

公開エンドポイントはすべて HTTPS の GET リクエストで、JSON を返します。キーは不要です。まずはシステムの状態を取得してみましょう:

curl -s "https://status.yucts.com/api/v2/status?locale=en"

# Conditional request — 304 Not Modified when nothing changed
curl -s -i "https://status.yucts.com/api/v2/services?locale=ja" -H 'If-None-Match: "<etag from the previous response>"'

API のバージョン

  • v1(/api/*)は既存のアプリやウィジェットが利用している安定版 1.x API です。仕様は凍結されており、フィールドの削除や名前の変更は行いません。
  • v2(/api/v2/*)が現行の API です。統一されたレスポンス形式、エラーコード、リクエスト ID、ETag、カーソル方式のページング、7 言語に対応しています。

廃止ポリシー

互換性のない変更は新しいバージョンのパスでのみ提供します。廃止予定のバージョンは少なくとも 12 か月間利用でき、削除前に Deprecation と Sunset ヘッダーで告知します。

認証

このページのエンドポイントはすべて公開の読み取り専用で、認証は不要です。管理用エンドポイントはこのドキュメントに含まれず、サインインした管理者が管理画面の「API リファレンス」で確認できます。認証情報を URL に含めないでください。

エンドポイント

API を提供しているコードから生成した完全なリファレンスを、OpenAPI 3.1 形式で公開しています。 /openapi.json

API リファレンスを読み込んでいます…

エラー

v2 のエラーはすべて同じ形式です。処理の分岐にはメッセージではなく code を使い、問題を報告する際はリクエスト ID を添えてください。

{
  "error": {
    "code": "not_found",
    "message": "Incident not found.",
    "status": 404,
    "request_id": "c0ffee00-…"
  }
}

レート制限

エッジキャッシュにヒットしなかったリクエストは、クライアント IP ごとに制限されます(既定は毎分 600 回)。制限を超えると HTTP 429 と Retry-After ヘッダーが返ります。

キャッシュ

公開レスポンスは 30 秒間(v1 は 60 秒間)キャッシュでき、ETag が付きます。If-None-Match で送り返すと、変更がなければ 304 Not Modified が返ります。言語判定などの個人向けレスポンスはキャッシュされません。

言語

locale=zh-TW、zh-HK、zh-CN、en、ja、ko、vi を指定できます。翻訳がない場合は日本語にフォールバックし、各テキストの *_locale フィールドに実際に返した言語を示します。

Webhook

管理者は、インシデントやメンテナンスのイベントを HTTPS エンドポイント(汎用 JSON、Discord、Slack)に送信できます。すべてのリクエストには署名が付きます:

X-Yucts-Signature: t=1767225600,v1=5f2c…
X-Yucts-Event: incident.created
X-Yucts-Delivery: 42

Webhook のシークレットで "<t>.<リクエスト本文>" の HMAC-SHA256 を計算し、v1 と定数時間で比較してください。5 分より古いタイムスタンプは拒否し、X-Yucts-Delivery で重複を排除してください。

import { createHmac, timingSafeEqual } from 'node:crypto';

// header = X-Yucts-Signature, rawBody = the exact request body string
export function verifyYuctsSignature(rawBody, header, secret) {
  const m = /^t=(\d+),v1=([0-9a-f]{64})$/.exec(header ?? '');
  if (!m) return false;
  const [, t, sig] = m;
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // replay window
  const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest();
  return timingSafeEqual(Buffer.from(sig, 'hex'), expected);
}

コード例

JavaScript
const res = await fetch('https://status.yucts.com/api/v2/status?locale=en');
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const { data } = await res.json();
console.log(data.status);             // "operational" | "degraded" | "partial_outage" | ...
console.log(data.active_incidents);   // ongoing incidents with their latest update
TypeScript
type ServiceStatus = 'operational' | 'degraded' | 'down' | 'maintenance' | 'unknown';
interface ServiceSummary {
  id: number;
  name: string;
  status: ServiceStatus;
  uptime: { h24: number | null; d30: number | null; d90: number | null }; // null = no data
}

async function services(locale = 'ja'): Promise<ServiceSummary[]> {
  const res = await fetch(`https://status.yucts.com/api/v2/services?locale=${locale}`);
  if (!res.ok) {
    const { error } = await res.json(); // { code, message, status, request_id }
    throw new Error(`${error.code} (${error.request_id})`);
  }
  return (await res.json()).data;
}
Swift / SwiftUI
struct Envelope<T: Decodable>: Decodable { let data: T }
struct SystemStatus: Decodable {
    let status: String
    let counts: Counts
    struct Counts: Decodable { let total, operational, degraded, down, maintenance, unknown: Int }
}

func fetchStatus(locale: String = "zh-TW") async throws -> SystemStatus {
    var url = URLComponents(string: "https://status.yucts.com/api/v2/status")!
    url.queryItems = [URLQueryItem(name: "locale", value: locale)]
    let (data, response) = try await URLSession.shared.data(from: url.url!)
    guard (response as? HTTPURLResponse)?.statusCode == 200 else { throw URLError(.badServerResponse) }
    return try JSONDecoder().decode(Envelope<SystemStatus>.self, from: data).data
}
PHP (WordPress)
<?php
// WordPress: cache the status for 60 seconds with a transient.
function yucts_status() {
    $cached = get_transient('yucts_status');
    if ($cached !== false) return $cached;
    $res = wp_remote_get('https://status.yucts.com/api/v2/status?locale=en', ['timeout' => 5]);
    if (is_wp_error($res) || wp_remote_retrieve_response_code($res) !== 200) return null;
    $body = json_decode(wp_remote_retrieve_body($res), true);
    set_transient('yucts_status', $body['data'], 60);
    return $body['data'];
}

Swift/SwiftUI、JavaScript/TypeScript、WordPress、XenForo の手順は、リポジトリのドキュメントにまとめています。

埋め込みウィジェット

XenForo、WordPress、通常の HTML など、どのページにも最新の状態を表示できます。1.x のウィジェットはそのまま動作します。v2 ウィジェットは新しいデザイン、ページのスタイルからの分離、7 言語に対応しています。

<!-- 2.0 widget: same attributes, Shadow DOM isolation, 7 languages -->
<div class="yucts-status" data-view="overview" data-locale="zh-TW"></div>
<script src="https://status.yucts.com/embed/v2.js" defer></script>
<!-- 1.x widget (unchanged) -->
<div id="yucts-status"></div>
<script src="https://status.yucts.com/embed.js" defer></script>

変更履歴

  • 2.0 — API v2、OpenAPI 3.1、全コンテンツのベトナム語対応、埋め込み v2、バッジ、フィード、iCalendar、エクスポート、OpenMetrics(それぞれ機能スイッチで制御)。
  • 1.x — /api/overview、/api/status、/api/incidents、/api/slo、/api/maintenance、/api/geo、embed.js。