开发者与 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
错误
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 updateTypeScript
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。