跳到主要內容
YUCTS Status

安裝 YUCTS Status

把 YUCTS Status 加到主畫面,便可快速打開;最後載入的狀態在離線時亦可查看。

iPhone 及 iPad(Safari)

  1. 按工具列上的「分享」按鈕。
  2. 選擇「加至主畫面」。
  3. 按「加入」。

Mac(Safari)

選擇「檔案」›「加至 Dock」(macOS Sonoma 或以上)。

Chrome、Edge 及 Android

使用下面的安裝按鈕,或網址列/瀏覽器選單中的安裝圖示。

如你的瀏覽器未能安裝網頁應用程式,請把此頁加入書籤。

開發人員及 API

提供狀態、事故及維護資料的公開 REST API,另有嵌入式小工具、狀態徽章、訂閱源及日曆。

快速入門

所有公開端點都是傳回 JSON 的 HTTPS GET 請求,毋須密鑰。先試試取得系統狀態:

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、游標分頁,並支援七種語言。

停用政策

不相容的變更只會以新版本路徑推出。準備停用的版本最少保留 12 個月,並會在移除前以 Deprecation 及 Sunset 標頭預先通知。

驗證

本頁列出的端點全部為公開的唯讀端點,毋須驗證。管理用端點不包括在此文件內,已登入的管理員可在管理介面的「API 參考」查閱。切勿把任何憑證放進網址。

端點

完整的 API 參考由提供 API 的同一套程式碼產生,以 OpenAPI 3.1 格式提供。 /openapi.json

正在載入 API 參考…

錯誤

v2 的錯誤格式一致。程式邏輯請使用 code(而不是 message),報告問題時請附上請求 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 核對。拒絕超過五分鐘的時間戳記,並以 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 小工具採用新設計、與網頁樣式隔離,並支援七種語言。

<!-- 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。