DOJ 公开 API · V1
API 文档
以 JSON 格式获取 DOJ 的公开用户、题目、比赛和等级分数据。不会公开题面和私密运营数据。
https://doj.kr/api/v1快速入门
目前的API版本不需要API密钥,可以从浏览器或服务器调用。
const response = await fetch("https://doj.kr/api/v1/users/dadas08/rating-history?limit=200");
if (!response.ok) throw new Error(`DOJ API: ${response.status}`);
const { points } = await response.json();
const chartData = points.map(({ occurredAt, newRating }) => ({
x: new Date(occurredAt),
y: newRating
}));通用规则
- 响应格式
- UTF-8 JSON
- CORS
Access-Control-Allow-Origin: *- 时间
- UTC ISO 8601 字符串
- 请求频率限制
- 每个IP每分钟约有120次请求
请查看 X-RateLimit-Limit、X-RateLimit-Remaining 和 X-RateLimit-Reset 响应头。多个服务器实例之间的限制可能是近似值。
不会返回私密题目和比赛、受保护的比赛题目列表、邮箱、Discord 账号、权限和提交源代码。个人主页图片使用公开访问链接;旧版 Base64 图片可能省略。
接口端点概览
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/v1/tags | 算法标签目录 |
| GET | /api/v1/users | 搜索用户 |
| GET | /api/v1/users/{handle} | 公开用户主页 |
| GET | /api/v1/users/{handle}/contest-participations | 已结束的比赛参赛记录 |
| GET | /api/v1/users/{handle}/virtual-participations | 已结束的分类虚拟参赛记录 |
| GET | /api/v1/users/{handle}/rating-history | 图表用等级分历史 |
| GET | /api/v1/problems | 搜索公开题目 |
| GET | /api/v1/problems/{displayId} | 公开题目元数据 |
| GET | /api/v1/contests | 搜索可见的比赛 |
| GET | /api/v1/contests/{slug} | 比赛元数据 |
用户
所有用户 API 端点均区分用户名大小写。搜索词和路径中的用户名须与存储的用户名大小写完全一致。
/api/v1/users搜索用户| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
q | string | "" | 区分大小写的部分用户名 |
limit | 1..100 | 20 | 每页的结果 |
cursor | string | - | 上一次响应中的 nextCursor |
GET /api/v1/users?q=dadas&limit=20
{
"users": [{
"handle": "dadas08",
"rating": 1542,
"contestsCount": 12,
"solvedProblemCount": 84,
"certified": true,
"avatarUrl": "/api/storage-assets/...",
"countryCode": "KR",
"organization": null
}],
"nextCursor": null
}/api/v1/users/{handle}公开用户主页在搜索字段基础上增加简介、账号创建时间和关注者及关注人数。账号不存在或未公开时返回 404。
/api/v1/users/{handle}/contest-participations参赛记录按比赛时间降序返回已结束的公开比赛和邀请赛,排除进行中的比赛和私密比赛。支持 limit 和 cursor。
/api/v1/users/{handle}/virtual-participations分类虚拟参赛记录返回公开分类中已结束的虚拟参赛记录。团队记录按实际成员查询,不包含各题得分和提交记录。
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
limit | 1..200 | 100 | 每页历史记录点数 |
cursor | string | - | 上一次响应中的 nextCursor |
{
"user": { "handle": "dadas08" },
"participations": [{
"category": {
"path": "algorithm/graphs",
"contents": [
{ "locale": "en", "name": "Graphs" },
{ "locale": "ko", "name": "그래프" }
]
},
"mode": "TEAM",
"team": { "handle": "graph-team" },
"startedAt": "2026-09-12T09:00:00.000Z",
"endedAt": "2026-09-12T11:00:00.000Z",
"totalScore": 420,
"penaltySeconds": 3510
}],
"nextCursor": null
}/api/v1/users/{handle}/rating-history等级分图表数据按时间从早到晚返回数据点。使用 occurredAt 作为横轴、newRating 作为纵轴。私密比赛的变动仍保留数值连续性,但 contest 返回 null。
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
limit | 1..200 | 100 | 每页历史记录点数 |
cursor | string | - | 上一次响应中的 nextCursor |
{
"user": { "handle": "dadas08" },
"points": [{
"id": "...",
"occurredAt": "2026-07-21T09:00:00.000Z",
"oldRating": 1501,
"newRating": 1542,
"delta": 41,
"kind": "CONTEST",
"contest": {
"slug": "doj-contest-1",
"title": "DOJ Contest 1",
"startAt": "2026-07-21T09:00:00.000Z"
}
}],
"nextCursor": null
}题目
/api/v1/problems搜索公开题目| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
q | string | "" | 与问题列表相同的搜索语法:显示 ID、slug、标题、@handle、#tag、范围和逻辑表达式 |
difficultyMin | integer | - | 最低难度值 |
difficultyMax | integer | - | 难度最大值 |
tags | CSV | "" | 必须全部匹配的标签,最多 10 个 |
sort | enum | display_id_asc | 下面的排序值之一 |
limit | 1..100 | 20 | 每页的结果 |
cursor | string | - | 上一次响应中的 nextCursor |
display_id_asc display_id_desc difficulty_asc difficulty_desc solves_desc published_desc
GET /api/v1/problems?tags=dp,graphs&difficultyMin=6&sort=solves_desc
{
"problems": [{
"displayId": 95,
"slug": "95",
"titles": { "ko": "문제 제목", "en": "Problem title" },
"difficulty": 12,
"solveCount": 37,
"timeLimitMs": 2000,
"pythonTimeLimitMs": 4000,
"memoryLimitMb": 512,
"problemType": "STANDARD",
"tags": ["dp", "graphs"],
"authors": ["setter"],
"reviewers": [],
"publishedAt": "2026-08-01T00:00:00.000Z"
}],
"nextCursor": null
}/api/v1/problems/{displayId}公开题目元数据返回单道题目的相同元数据,不包含题面、输入输出说明、限制、样例、题解和评测数据。
比赛
/api/v1/contests搜索比赛| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
q | string | "" | 搜索 slug 或标题 |
status | enum | all | all、upcoming、running 或 ended |
limit | 1..100 | 20 | 每页的结果 |
cursor | string | - | 上一次响应中的 nextCursor |
/api/v1/contests/{slug}比赛元数据返回时间、个人参赛时间段设置、是否计入等级分、题目数量、描述和规则。私密比赛返回 404。
分页
如果 nextCursor 不为 null,请将其原样传入下一次请求的 cursor,不要解码或修改。更改筛选条件或排序后,不要复用旧游标。
GET /api/v1/problems?limit=20&cursor=eyJvZmZzZXQiOjIwfQ错误和缓存
| HTTP | 错误 | 含义 |
|---|---|---|
| 400 | invalid_request | 查询格式或范围无效 |
| 400 | invalid_cursor | 游标无效 |
| 404 | not_found | 资源不存在或未公开 |
| 429 | rate_limit_exceeded | 超出请求频率限制 |
| 502/503 | api_unavailable | 后端暂时故障 |
{ "error": "not_found" }请遵循 Cache-Control 响应头,避免反复请求相同数据。不兼容的变更将使用新的版本路径。
DOJ 的通用指南请参阅 DOJ 指南。