跳至主要内容
D1 Arena

D1 Arena

Loading...

D1 Arena

开发者API

社区

开发者API

构建机器人、叠加层、流工具以及与 D1Arena 数据的集成。

认证

所有 API 请求都需要在 X-API-Key / Authorization: Bearer 标头中传递 API 密钥。

# Example request curl -H "X-API-Key: d1_your_api_key_here" \ https://d1arena.com/api/v1/streams

要创建 API 密钥,请转到仪表板中的 开发者设置。您最多可以拥有 5 个钥匙。

每个 API 密钥的 API 请求受到速率限制。当超出限制时,请求将返回 429 Too Many Requests 和 Retry-After 标头。

基本网址

https://d1arena.com/api/v1

所有端点都返回 JSON。分页端点包括带有 current_page、last_page 和 total 的 meta 对象。

流

GET /streams
列出当前直播。支持分页和类别过滤。
参数类型描述
category_idinteger按游戏/类别 ID 过滤
limitinteger每页结果(默认:20)
pageinteger页码
回应
{ "data": [ { "id": 42, "name": "ProGamer99", "user_slug": "progamer99", "profile_img": "profile/abc123.jpg", "stream_title": "Ranked Grind - Road to Champion", "stream_category_id": 5, "is_vertical_stream": false, "platform_tier": "pro" } ], "meta": { "current_page": 1, "last_page": 1, "total": 3 } }
GET /streams/{slug}
通过用户名或 slug 获取单个流媒体的实时状态和流媒体详细信息。
回应
{ "data": { "user_id": 42, "name": "ProGamer99", "slug": "progamer99", "is_live": true, "stream_title": "Ranked Grind", "category_id": 5, "is_vertical": false, "platform_tier": "pro", "profile_img": "profile/abc123.jpg" } }

类别

GET /categories
列出所有游戏类别。支持搜索和分页。
参数类型描述
searchstring按名称过滤类别
limitinteger每页结果(默认:50)
回应
{ "data": [ { "id": 5, "name": "Call of Duty", "slug": "call-of-duty", "image": "categories/cod.png" } ], "meta": { "total": 24 } }

用户

GET /users/{slug}
通过用户名或别名获取玩家的公开资料和竞技统计数据。
回应
{ "data": { "user": { "id": 42, "name": "ProGamer99", "user_slug": "progamer99", "profile_img": "profile/abc.jpg", "bio": "Competitive FPS player", "platform_tier": "pro", "is_live": "1", "stream_title": "Ranked", "gold": 3, "silver": 1, "bronze": 0 }, "stats": { "elo_rating": 1842, "total_tournaments": 27, "win_rate": 64.5, "total_earnings": 1250.00 } } }

剪辑

GET /clips
列出公共剪辑。支持按主播和类别过滤。
参数类型描述
streamer_idinteger按主播用户 ID 过滤剪辑
category_idinteger按游戏/类别 ID 过滤
limitinteger每页结果(默认:20)
回应
{ "data": [ { "id": 99, "streamer_id": 42, "stream_category_id": 5, "title": "Insane 1v4 clutch", "slug": "insane-1v4-clutch-abc", "duration": 28, "view_count": 412, "is_auto_clip": false, "created_at": "2026-03-15T18:30:00.000000Z", "streamer": { "id": 42, "name": "ProGamer99", "user_slug": "progamer99" } } ], "meta": { "total": 156 } }
GET /clips/{slug}
通过 slug 获取单个剪辑的详细信息。
回应
{ "data": { "id": 99, "title": "Insane 1v4 clutch", "slug": "insane-1v4-clutch-abc", "description": "Final round comeback", "duration": 28, "view_count": 412, "streamer": { "id": 42, "name": "ProGamer99" }, "creator": { "id": 55, "name": "ClipMaster" }, "stream_category": { "id": 5, "name": "Call of Duty" } } }

锦标赛

GET /tournaments
列出锦标赛。支持按状态和联赛进行过滤。
参数类型描述
statusstring按状态过滤(例如 open、in_progress、completed)
league_idinteger按联赛 ID 过滤
limitinteger每页结果(默认:20)
回应
{ "data": [ { "id": 15, "title": "Friday Night Frenzy", "tournament_type": "single_elimination", "status": "open", "registration_fee": "5.00", "no_player": 32, "team": 0, "category": { "id": 5, "name": "Call of Duty" }, "start_date": "2026-03-28T20:00:00.000000Z" } ], "meta": { "current_page": 1, "last_page": 2, "total": 24 } }
GET /tournaments/{id}
获取锦标赛详细信息和参与者人数。
回应
{ "data": { "id": 15, "title": "Friday Night Frenzy", "tournament_type": "single_elimination", "status": "open", "registration_fee": "5.00", "no_player": 32, "team": 0 }, "meta": { "participant_count": 18 } }

ELO排名

GET /elo/leaderboard
获取 ELO 排名排行榜。可以选择按游戏类别进行过滤。
参数类型描述
category_idinteger按游戏/类别 ID 过滤
limitinteger结果数(默认:50)
回应
{ "data": [ { "rank": 1, "user_id": 42, "name": "ProGamer99", "user_slug": "progamer99", "elo_rating": 2150, "wins": 45, "losses": 12, "win_rate": 78.9, "profile_img": "profile/abc123.jpg" } ], "meta": { "total": 312 } }

联赛

GET /leagues
列出带有可选状态和类别过滤器的联赛。
参数类型描述
statusstring按联赛状态过滤
category_idinteger按游戏/类别 ID 过滤
limitinteger每页结果(默认:20)
回应
{ "data": [ { "id": 3, "name": "Spring 2026 Pro League", "status": "active", "category": { "id": 5, "name": "Call of Duty" }, "total_participants": 48, "start_date": "2026-03-01", "end_date": "2026-05-31" } ], "meta": { "current_page": 1, "last_page": 1, "total": 6 } }
GET /leagues/{id}/standings
获取联赛排名(按积分排名的球员排名)。
回应
{ "data": [ { "id": 1, "points": 2400, "wins": 12, "losses": 3, "user": { "id": 42, "name": "ProGamer99", "user_slug": "progamer99" } } ], "meta": { "total": 48 } }

错误响应

所有错误都会返回一致的 JSON 信封。 error 对象始终包含机器可读的 code 和人类可读的 message。

错误响应格式
{ "success": false, "error": { "code": "not_found", "message": "The requested resource could not be found." } }
验证错误格式 (422)
{ "success": false, "error": { "code": "validation_error", "message": "The given data was invalid.", "errors": { "category_id": ["The category id must be an integer."], "limit": ["The limit must not be greater than 100."] } } }

状态代码

200
好的 — 请求成功。响应包含请求的数据。
400
错误的请求 — 请求格式错误或缺少所需参数。检查 error.message 了解详细信息。
401
未授权 — Missing or invalid API key. Ensure you're passing a valid key in the X-API-Key header.
403
访问被拒绝 — 您的 API 密钥已被禁用或缺少此资源的权限。检查你的 开发者设置.
404
页面不存在 — 请求的资源不存在。验证 slug、ID 或端点路径。
422
验证错误 — 请求参数验证失败。 error.errors 对象将字段名称映射到其特定问题。
429
价格有限 — 请求太多。 Retry-After 标头指示重试之前要等待多少秒。
500
服务器错误 — 我们这边发生了意外错误。如果这种情况持续下去, 联系支持人员.

错误代码参考

验证码HTTP 状态描述
invalid_api_key401API 密钥丢失、格式错误或不存在
api_key_disabled403API密钥已被撤销或禁用
not_found404找不到所请求的资源
validation_error422一个或多个请求参数无效
rate_limited429超出此 API 密钥的请求速率限制
server_error500内部服务器错误 - 请重试或联系支持人员

速率限制

每个 API 密钥的 API 请求受到速率限制。当超出限制时,请求将返回 429 Too Many Requests 和 Retry-After 标头。

按级别限制

等级请求/分钟 (默认)最大按键数
起动机 (免费)605
专业版605
终极版605
伙伴605

速率限制标头

每个 API 密钥的 API 请求受到速率限制。当超出限制时,请求将返回 429 Too Many Requests 和 Retry-After 标头。

标头描述
Retry-After重试前等待的秒数(仅出现在 429 响应中)

最佳实践

保持在限制范围内的提示:
  • Cache responses locally — stream and tournament data doesn't change every second.
  • 订阅 webhooks 来获取实时事件,而不是轮询端点。
  • 尽可能批量请求 - 使用过滤器参数以更少的调用次数准确获取您需要的内容。

Webhook(EventSub)

订阅实时推送通知而不是轮询。当事件发生时,D1Arena 会向您的回调 URL 发送一个 HTTP POST,其中包含使用 HMAC-SHA256 签名的 JSON 负载。

设置

在 开发者设置 中创建 webhook 订阅。每个订阅都需要:

  • 回调地址 — 服务器上可公开访问的 HTTPS 端点。
  • 活动 — 要订阅的一种或多种事件类型。

You'll receive a whsec_ signing secret upon creation. Store it securely — it's shown only once.

有效负载格式

每个 Webhook 传递都会发送一个具有以下结构的 JSON 正文:

{ "id": "evt_a1b2c3d4e5f6", "event": "stream.online", "created_at": "2026-03-23T14:30:00Z", "data": { // Event-specific fields (see examples below) } }

标头

每个交付都包含以下用于路由和验证的标头:

标头描述
Content-Typeapplication/json
X-D1Arena-Event事件类型(例如 stream.online)
X-D1Arena-Signature原始请求正文的 HMAC-SHA256 十六进制摘要
X-D1Arena-Signature-Version签名密钥格式:当前订阅为 v2,旧订阅为 v1-hashed-secret
X-D1Arena-Delivery-Id唯一的交付 UUID — 用于重复数据删除
X-D1Arena-Timestamp发送事件时的 Unix 时间戳

验证签名

在处理 Webhook 之前,请务必验证 X-D1Arena-Signature 标头。签名计算为 HMAC-SHA256(raw_body, webhook_secret)。

对于 v2 交付,请使用创建订阅时显示的 whsec_ 密钥。对于升级前 v1-hashed-secret 交付,首先根据原始密钥计算 SHA256(whsec_secret) 并使用生成的小写十六进制摘要作为 HMAC 密钥。在可行时重新创建订阅以移动到 v2。

PHP
// Get the raw body and signature header $payload = file_get_contents('php://input'); $signature = $_SERVER['HTTP_X_D1ARENA_SIGNATURE'] ?? ''; // Compute expected signature $expected = hash_hmac('sha256', $payload, $webhookSecret); // Constant-time comparison to prevent timing attacks if (!hash_equals($expected, $signature)) { http_response_code(401); exit('Invalid signature'); } $event = json_decode($payload, true);
Node.js
const crypto = require('crypto'); app.post('/webhook', (req, res) => { const payload = req.rawBody; // Ensure raw body is available const signature = req.headers['x-d1arena-signature']; const expected = crypto .createHmac('sha256', WEBHOOK_SECRET) .update(payload) .digest('hex'); if (!crypto.timingSafeEqual( Buffer.from(expected), Buffer.from(signature) )) { return res.status(401).send('Invalid signature'); } const event = JSON.parse(payload); // Process event... res.status(200).send('OK'); });
蟒蛇
import hmac, hashlib, json def handle_webhook(request): payload = request.body signature = request.headers.get('X-D1Arena-Signature', '') expected = hmac.new( WEBHOOK_SECRET.encode(), payload, hashlib.sha256 ).hexdigest() if not hmac.compare_digest(expected, signature): return HttpResponse(status=401) event = json.loads(payload) # Process event... return HttpResponse(status=200)

可用的活动

活动描述
stream.online主播上线了
stream.offline一名主播下线了
channel.follow用户关注频道
channel.subscribe频道上有新的支持者订阅
channel.tip一条提示已发送至主播
tournament.started锦标赛比洞赛已经开始
tournament.ended一场锦标赛已经结束
tournament.match.completed记录了比赛结果
clip.created从直播中创建了一个新剪辑
overdrive.startedD1 频道开始疯狂
overdrive.level_upD1 疯狂晋级到下一个级别
overdrive.endedD1 疯狂已完成或已过期

事件负载示例

stream.online

{ "id": "evt_a1b2c3d4e5f6", "event": "stream.online", "created_at": "2026-03-23T14:30:00Z", "data": { "user_id": 42, "user_slug": "progamer99", "name": "ProGamer99", "stream_title": "Ranked Grind - Road to Champion", "category_id": 5, "category_name": "Call of Duty", "protocol": "RTMP", "started_at": "2026-03-23T14:30:00Z" } }

stream.offline

{ "id": "evt_f6e5d4c3b2a1", "event": "stream.offline", "created_at": "2026-03-23T17:45:00Z", "data": { "user_id": 42, "user_slug": "progamer99", "duration_seconds": 11700, "vod_id": 281 } }

channel.follow

{ "id": "evt_c1d2e3f4a5b6", "event": "channel.follow", "created_at": "2026-03-23T15:10:00Z", "data": { "follower_id": 88, "follower_slug": "newplayer", "followed_id": 42, "followed_slug": "progamer99" } }

channel.tip

{ "id": "evt_d1e2f3a4b5c6", "event": "channel.tip", "created_at": "2026-03-23T16:20:00Z", "data": { "streamer_id": 42, "streamer_slug": "progamer99", "tipper_id": 55, "tipper_slug": "clipmaster", "amount": "5.00", "currency": "USD", "message": "Great stream!" } }

tournament.match.completed

{ "id": "evt_e1f2a3b4c5d6", "event": "tournament.match.completed", "created_at": "2026-03-23T21:15:00Z", "data": { "tournament_id": 15, "tournament_title": "Friday Night Frenzy", "match_id": 204, "round": 2, "winner": { "id": 42, "slug": "progamer99", "name": "ProGamer99" }, "loser": { "id": 77, "slug": "rival_x", "name": "Rival_X" }, "score": "3-1" } }

clip.created

{ "id": "evt_b1c2d3e4f5a6", "event": "clip.created", "created_at": "2026-03-23T15:45:00Z", "data": { "clip_id": 99, "slug": "insane-1v4-clutch-abc", "title": "Insane 1v4 clutch", "duration": 28, "streamer_id": 42, "streamer_slug": "progamer99", "creator_id": 55, "creator_slug": "clipmaster", "category_id": 5 } }

交付和重试政策

尝试延迟注释
第一名(初始)立即事件发生后几秒内发送
第二次(重试)30秒如果第一次尝试失败或超时
第三次(重试)2分钟指数退避
第四名(决赛)10分钟标记为失败之前的最后一次尝试
Important: Your endpoint must respond with a 2xx status within 10秒. Non-2xx responses or timeouts trigger a retry. After 连续10次失败, the subscription is automatically disabled. You'll receive an email notification and can re-enable it in 开发者设置.

最佳实践

  • 始终验证签名 在处理有效负载之前以防止欺骗事件。
  • 使用 Delivery-Id 进行重复数据删除 — 重试发送相同的 ID,因此存储已处理的 ID 以避免重复处理。
  • 快速响应,异步处理 — 立即返回 200 OK 并在后台作业中处理业务逻辑。
  • 仅使用 HTTPS 端点 — Webhook URL 必须使用 TLS。 HTTP 回调被拒绝。
  • 优雅地处理未知事件 — 可能会添加新的事件类型。返回 200 表示无法识别的事件而不是错误。

D1 疯狂

D1 疯狂是由主播直播时的快速提示和订阅触发的。它分为 5 个级别,目标不断增加。

GET /api/overdrive/{streamerId}

为主播获取活跃的 D1 Frenzy。如果没有则返回 {"active": false}。

{ "active": true, "level": 2, "progress": 150, "target": 250, "progress_pct": 60.0, "total_contributions": 8, "total_contributors": 5, "expires_at": "2026-03-22T15:30:00+00:00" }

水平目标

等级积分
1100
2250
3500
41,000
52,000

D1 疯狂 — 积分: 提示 $1 → 100; 订阅 500 × 等级. 持续时间: 5 分钟; 冷却时间: 30 分钟.

扩展SDK

构建自定义面板和覆盖扩展,主播可以将其安装在其频道页面上。扩展程序在沙盒 iframe 中运行,并通过 postMessage 与主机页面通信。

开始使用

  1. 在 开发者设置 中创建 API 密钥。
  2. 将您的扩展程序构建为托管在您的域上的独立 HTML 页面(需要 HTTPS)。
  3. 在 我的扩展 部分提交以供审核。
  4. 一旦获得批准,主播就可以从扩展市场安装它。

扩展类型

类型地点行为
panel流媒体播放器下方直播时可见。全宽卡片,默认高度 300 像素。
overlay在视频播放器上直播时可见。位置/大小由流光通过叠加定位工具控制。

发布消息API

您的扩展程序在加载时会自动接收上下文数据。实施这些事件:

为每条消息使用确切的 D1Arena 父源。官方 SDK 自动从嵌入页面派生并验证此来源。

由于扩展 iframe 有意使用不透明的沙箱源,因此 D1Arena 主机会验证确切注册的 iframe 窗口。在接受上下文之前,扩展代码仍然必须验证父窗口和确切的 D1Arena 来源。

1. 信号准备情况

var d1ParentOrigin = 'https://d1arena.com'; // Tell the host page your extension is ready for context window.parent.postMessage({ type: 'D1_EXT_READY' }, d1ParentOrigin);

2. 接收上下文

window.addEventListener('message', function(e) { if (e.source === window.parent && e.origin === d1ParentOrigin && e.data && e.data.type === 'D1_CONTEXT') { var ctx = e.data.payload; // ctx.channelId - Streamer's user ID // ctx.channelName - Streamer's display name // ctx.channelSlug - Streamer's URL slug // ctx.viewerId - Current viewer's ID (null if not logged in) // ctx.isLive - Whether the stream is currently live } });

3. 发送操作(可选)

// Redirect the host page (e.g. for a "Storm" button) window.parent.postMessage({ type: 'D1_EXT_ACTION', action: 'storm', target: 'username-slug' }, d1ParentOrigin);

权限范围

声明您的扩展需要哪些数据。审阅者会验证您的代码是否符合您声明的权限。

范围授予访问权限
read:stream流状态、标题、类别
read:viewers观看人数和列表
read:chat聊天消息(通过 Pusher 频道)
read:clips通过 /api/clips/{slug} 频道剪辑
read:tournaments通过 /api/active-match/{id} 获取有效匹配信息
read:channel频道简介、关注者、时间表

安全要求

扩展在带有 sandbox="allow-scripts" 的 沙盒 iframe 中运行。您的扩展程序 不能 访问 cookie、localStorage,或向 d1arena.com 发出经过身份验证的请求。
  • 需要公共 HTTPS — 您的 iframe URL 必须使用 TLS 并仅解析为公共网络地址。
  • 人类可读的源代码 — 没有混淆或缩小的 JavaScript。审阅者必须能够阅读您的代码。
  • 无需加载外部脚本 除非您在提交的材料中声明。 CDN 库(jQuery、Chart.js 等)都很好。
  • 无数据泄露 — 扩展程序不得将查看者数据发送到第三方分析或跟踪服务。
  • 内容政策 — 没有广告、NSFW 内容、加密货币挖掘或恶意行为。

审核流程

状态含义
pending已提交,等待管理员审核(通常 1-3 个工作日)。
approved已批准并在扩展市场中可见。
rejected有理由拒绝。修复问题并重新提交。
suspended因违反政策而被暂时删除。联系支持人员。

版本更新

要更新已批准的扩展,请删除当前版本并提交版本号递增的新版本。新版本再次审核。

变更日志

跟踪 API 更改和新功能。我们遵循语义版本控制,并至少提前 30 天宣布重大变更。

v1.02026 年 3 月
  • 具有 API 密钥身份验证的初始公共 API 版本。
  • 流:列出直播流,通过slug获取流媒体详细信息。
  • 类别:搜索并列出所有游戏类别。
  • 用户:包含竞技统计数据、ELO 评级和奖牌数的公开个人资料。
  • 剪辑:浏览并检索带有主播/创作者信息的剪辑详细信息。
  • 锦标赛:列出,按状态/联赛过滤,获取参与者计数。
  • ELO 排行榜:全球和按类别排名的排行榜。
  • 联赛:列出联赛的排名和积分明细。
  • D1 疯狂:任何主播的实时疯狂状态。
  • Webhooks (EventSub): 12 种事件类型,包括流、频道、锦标赛、剪辑和 Frenzy 事件。
  • 速率限制

需要帮助吗?

关于 API 有疑问吗? 联系我们。