公共 API 为组织管理员提供对你所在组织的实时数据的直接 HTTP 访问——任何能够发出 HTTP 请求的网站、应用、机器人或自动化流程都可以接入。这是 Business 方案 的一项功能。

该密钥的作用域限定为你的组织——所有端点都会自动作用于该组织。基础 URL:https://api.ludoya.com/public/v1。认证请求头:X-Api-Key: YOUR_KEY。速率限制:每分钟 100 次请求,超过后你将收到 429。
密钥以 ldy_ 开头,长度为 36 个字符,因此在配置文件中很容易发现——若它出现在不该出现的地方也便于扫描检出。请将其视为密码:仅限服务器端使用;若发生泄露,可在同一页面撤销。
可访问的内容
- 地点 — 你的组织可用的地点及其位置;在创建活动时用作输入
- 活动(读取) — 即将到来和过往的活动,包含标题、描述、日期/时间、时区、容量、参与者数量和状态
- 活动(写入) — 通过 POST 和 PUT 创建与更新活动,可完全控制地点、容量、权限、可见性和图片
- 子活动 — 列出嵌套在父活动内的活动
- 参与者 — 将某人加入活动、更改其出席状态或将其移除
- 成员 — 含用户资料与角色(所有者、管理员、成员)的成员列表,支持分页
- 邀请 — 邀请某人加入你的组织
- 搜索 — 查找 Ludoya 用户和桌游目录,以便在写入前将名称解析为 ID
- 收藏 — 桌游收藏,可按拥有情况、名称、玩家人数和列表筛选;可排序并分页;每个桌游都包含 BGG 元数据
- 统计 — 任意时间段的对局统计:总计、平均值、含胜场与得分的顶尖玩家、按玩家人数细分、按地点、按桌游
- 战役(读取) — 列出组织的战役及成员数和场次数;获取完整战役详情,包括成员、过往场次和已安排的活动
- 战役(写入) — 为组织创建战役,并更新其名称、描述、状态与可见性
- 战役成员 — 在战役中添加、更新和移除人员
端点
GET /locations
返回组织的可用地点。每个地点包含 id、name、可选的 address、capacity、一个 isDefault 标志,以及一个 spots 数组(每个位置都有自己的 id、name 和 capacity)。创建活动时请使用地点和位置的 ID。
使用 Ludoya 登录
保存你 API 密钥的同一页面也会将你的组织变成一个登录提供方。让人们使用他们的 Ludoya 账户登录你自己的网站、论坛或社区平台——他们无需再记另一套密码,你也无需运行用户数据库。
为什么值得
当有人批准登录时,他们会与你的组织关联:根据你们群组的加入策略,他们要么(开放)立即成为成员,要么(申请加入)提交加入请求供管理员批准,或(仅限邀请)仅登录而不加入。无论哪种情况,他们都会像其他人一样出现在 /members 端点中——因此你的网站登录与 Ludoya 成员列表会自动保持同步。
设置方法
这是标准的 OpenID Connect,因此大多数平台只需要一个发行者 URL,再加上客户端 ID 和密钥。从 Public API 页面注册你的应用以获取这些凭据,并列出你的网站将使用的重定向 URI——你可以注册多个,每一个都必须与网站发送的 redirect_uri 逐字符完全匹配,包括末尾的斜杠。轻微的不匹配是首次登录尝试失败的最常见原因。
- Discourse —— 安装 OpenID Connect 插件,粘贴发现 URL,添加凭据
- WordPress —— 任何通用的 OpenID Connect 插件,使用其 "auto discover" 选项
- 其他任何平台 —— 如果支持 OIDC,指向发行者 URL 即可自动完成配置
每次登录都会返回该用户的永久标识符、用户名、显示名和头像,以及其电子邮件地址。包含手动流程在内的完整设置说明,位于应用内的开发者指南:开发者 → 使用 Ludoya 登录。
给正在登录的用户
任何曾使用 Ludoya 在某处登录过的人,都可以在 设置 → 已连接的应用 下查看这些连接,查看每个连接的连接时间与上次使用时间,并可随时断开任意连接。断开会立即切断该网站的访问权限,但不会将他们从你的群组中移除。
GET /events
以两个彼此独立的分页列表返回未来和过去的活动。
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
onlyFuture |
布尔值 | true |
将其设为 false 以同时返回过去的活动 |
每个活动包含: type(MEETUP 或 PLANNED_PLAY)、title、description、startsAt、endsAt、timeZone、imageUrl、capacity、participantCount、canceled、teacher(用户对象或 null)、master(用户对象或 null)。用户对象包含 id、username、name、avatarUrl。
POST /events
在群组中创建一个活动。必填字段:type 和 title。如果省略 locationId,将使用群组的默认地点;如果不存在,则返回 400。
可选字段包括:description,locationId,spotId,gameId,parentEventId(用于子活动),startsAt,endsAt,restrictedAttendance,capacity,minParticipants,estimatedDurationMinutes,maxReservationsPerUser,takeGamesPermission,organizePlaysPermission,teacherUserId,masterUserId,visibility,image。
image 字段接受 {"base64": "data:image/jpeg;base64,..."} or {"url": "https://..."}。最大 5 MB。
返回 {"id": "string"},状态码 201。
PUT /events/{eventId}
更新现有的活动。请求体结构与 POST 相同——只需包含你想更改的字段。调用方必须是该活动的组织者(群组账号)。返回 202,响应体为空。
GET /events/{eventId}
根据 ID 获取单个活动,返回的数据结构与 GET /events 中的条目相同。
GET /events/{eventId}/children
列出嵌套在父级活动内的子活动——更大型聚会的各个专题或场次。每个子活动与常规活动具有相同的结构。
参与者管理
三个端点让你在 Ludoya 之外管理活动的参与者名单——当报名发生在你自己的网站上,或你正在导入现有名单时,这非常方便。
| 方法 | 路径 | 作用 |
|---|---|---|
POST |
`/events/ |
GET /members
返回分页的成员列表。
| 参数 | 类型 | 默认值 |
|---|---|---|
pagination.size |
int | 50 |
pagination.offset |
int | 0 |
每个成员包含: id、username、name、avatarUrl、role(OWNER、ADMIN 或 MEMBER)。
POST /members/invite
将某人邀请加入你的群组。此接口可直接接收一个 username —— 无需查找 ID —— 因此你可以直接从你自己的网站或管理工具添加成员。
GET /search/users 和 GET /search/boardgames
这两个查找端点。大多数写操作需要 id 而不是名称,而你可以通过它们获取到 id。
GET /search/users
| 参数 | 类型 | 默认值 |
|---|---|---|
query |
字符串 | 必填 |
intent |
字符串 | — |
pagination.size |
整数 | 20 |
pagination.offset |
整数 | 0 |
GET /search/boardgames
| 参数 | 类型 | 默认值 |
|---|---|---|
query |
字符串 | 必填 |
filter |
字符串 | — |
pagination.size |
整数 | 50 |
pagination.offset |
整数 | 0 |
桌游筛选器采用与收藏筛选器相同的以分号分隔的 key=value 形式,因此你可以按玩家人数、游戏时长、复杂度、年份、年龄或标签在目录中搜索。
GET /collection
返回你的桌游收藏,并支持筛选、排序和分页。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
filter |
string | — | 用分号分隔的 key=value 对。键:ownership (OWNED, PREVIOUSLY_OWNED, PREORDERED, WISHLISTED)、played (boolean)、listId、nameFilter、playerCountFilterType (OFFICIAL, GOOD, BEST)、playerCountFilter (number) |
groupExpansions |
boolean | true |
将扩展归类到其基础桌游下 |
sort |
string | — | 格式:property,direction — 例如 name,asc |
pagination |
string | — | 格式:size,pageIndex — 例如 20,0 |
响应: totalGames、totalExpansions、games[] — 每个包含:id、slug、name、imageUrl、isExpansion、yearPublished、minPlayerCount、maxPlayerCount。
GET /stats
返回可配置时间窗口的对局统计数据。
| 参数 | 类型 | 默认值 | 描述 |
|---|---|---|---|
period |
字符串 | ALL_TIME | 格式:PERIOD,date,index。取值:ALL_TIME、ONE_YEAR、ONE_MONTH、THIRTY_DAYS、SEVEN_DAYS、ONE_DAY、CUSTOM。index 将窗口向后偏移(0 = 当前,1 = 上一段)。自定义:CUSTOM,startDate,0,endDate |
响应包括:
- 摘要 — 总对局数、总/平均对局时长、唯一桌游、玩家和地点数量
- 按玩家 — 每人对局数、胜场、平均分和最佳分
- 按玩家人数 — 2 人、3 人、4 人等对局的细分
- 按地点 — 对局次数及每个场地的唯一桌游数量
- 按桌游 — 对局次数、总/平均对局时长,以及每个桌游标题的唯一玩家数
GET /campaigns
返回属于该群组的分页战役列表。
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
status |
string | — | 按状态筛选:ACTIVE、COMPLETED 或 ARCHIVED |
pagination.size |
int | 50 | 每页条目数 |
pagination.offset |
int | 0 | 偏移量 |
每个战役包含: id, game (id, name, imageUrl), name, image, status, visibility, createdAt, updatedAt, memberCount, sessionCount.
GET /campaigns/{campaignId}
返回属于该群组的战役的完整详细信息。
响应包含: 所有列表字段,以及 template、description、globalNotes、globalState、members[](每个包含 user、role、characterNotes、characterState)、sessions[] 和 events[]。
POST /campaigns
为该群组创建一个战役。必填字段:gameId 和 name。若省略,可见性默认为仅群组成员(ONLY_GROUP)。
可选字段:templateId、description、visibility(PUBLIC、ONLY_GROUP、ONLY_FRIENDS 或 PRIVATE)。
返回 {"id": "string"},状态码为 201。
PUT /campaigns/{campaignId}
更新现有战役。所有字段均为可选——只需包含你想更改的内容。
可选字段:name、description、status(ACTIVE、COMPLETED、ARCHIVED)、visibility。
返回 202,响应体为空。
战役成员
以与管理活动参与者相同的方式管理战役中的成员。
| 方法 | 路径 | 执行的操作 |
|---|---|---|
POST |
`/campaigns/ |
错误代码
| 状态 | 何时 |
|---|---|
| 400 | 验证失败(缺少必填字段,未找到地点,图片无效) |
| 401 | 缺少或无效的 API 密钥 |
| 403 | 操作不被允许,或群组未使用 Business 方案 |
| 404 | 未找到资源 |
| 429 | 已超出速率限制 |
开始使用
1. 生成 API 密钥

- 前往你的组织资料页面
- 点击菜单(⋮)→ 公共 API
- 点击 生成密钥
- 立即复制你的密钥 — 它只会显示一次,之后无法再次找回
该密钥与你的组织绑定。请妥善保密:任何持有该密钥的人都可以读写以上所有数据。
2. 撤销或重新生成
要撤销现有密钥,返回 公共 API 页面并点击 撤销。在对话框中确认。任何使用旧密钥的系统将立即开始收到 401 错误。要生成新的密钥,请再次点击 生成密钥。
相关: