Preparing the next screen and the freshest data.
Preparing the next screen and the freshest data.
DOJ PUBLIC API · V1
Read public DOJ user, problem, contest, and rating data as JSON. Statements and private operational data are not exposed.
https://doj.kr/api/v1The current v1 read API does not require an API key and can be called from browsers or servers.
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
}));Access-Control-Allow-Origin: *Inspect X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset response headers. Limits may be approximate across multiple server instances.
Private problems and contests, protected contest problem lists, emails, Discord accounts, permissions, and submission source are never returned. Profile images use public delivery URLs; legacy Base64 images may be omitted.
| Method | Path | Description |
|---|---|---|
| GET | /api/v1/tags | Algorithm tag catalog |
| GET | /api/v1/users | Search users |
| GET | /api/v1/users/{handle} | Public user profile |
| GET | /api/v1/users/{handle}/contest-participations | Finished contest participations |
| GET | /api/v1/users/{handle}/rating-history | Rating history for charts |
| GET | /api/v1/problems | Search public problems |
| GET | /api/v1/problems/{displayId} | Public problem metadata |
| GET | /api/v1/contests | Search visible contests |
| GET | /api/v1/contests/{slug} | Contest metadata |
User handles are case-sensitive across all user API endpoints. Search terms and handles in paths must use the same letter casing as the stored handle.
/api/v1/usersSearch users| Name | Type | Default | Description |
|---|---|---|---|
q | string | "" | Case-sensitive partial handle |
limit | 1..100 | 20 | Results per page |
cursor | string | - | nextCursor from the previous response |
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}Public user profileAdds bio, account creation time, and follower/following counts to the search fields. Missing or non-public accounts return 404.
/api/v1/users/{handle}/contest-participationsContest participationsReturns finished public and invite-only contests in descending contest-time order. Running and private contests are excluded. Supports limit and cursor.
/api/v1/users/{handle}/rating-historyRating chart dataReturns oldest points first. Use occurredAt for the x-axis and newRating for the y-axis. Changes from private contests preserve numeric continuity while returning contest as null.
| Name | Type | Default | Description |
|---|---|---|---|
limit | 1..200 | 100 | History points per page |
cursor | string | - | nextCursor from the previous response |
{
"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/problemsSearch public problems| Name | Type | Default | Description |
|---|---|---|---|
q | string | "" | Search display ID, slug, or title |
difficultyMin | integer | - | Minimum difficulty value |
difficultyMax | integer | - | Maximum difficulty value |
tags | CSV | "" | Tags that must all match, up to 10 |
sort | enum | display_id_asc | One of the sort values below |
limit | 1..100 | 20 | Results per page |
cursor | string | - | nextCursor from the previous response |
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}Public problem metadataReturns the same metadata for one problem. Statements, I/O descriptions, constraints, samples, editorials, and judge data are excluded.
/api/v1/contestsSearch contests| Name | Type | Default | Description |
|---|---|---|---|
q | string | "" | Search slug or title |
status | enum | all | all, upcoming, running, or ended |
limit | 1..100 | 20 | Results per page |
cursor | string | - | nextCursor from the previous response |
/api/v1/contests/{slug}Contest metadataReturns timing, window settings, rated state, problem count, description, and rules. Private contests return 404.
When nextCursor is not null, pass it unchanged as cursor in the next request. Do not decode or edit it, and do not reuse it after changing filters or sort order.
GET /api/v1/problems?limit=20&cursor=eyJvZmZzZXQiOjIwfQ| HTTP | Error | Meaning |
|---|---|---|
| 400 | invalid_request | Invalid query shape or range |
| 400 | invalid_cursor | Invalid cursor |
| 404 | not_found | Missing or non-public resource |
| 429 | rate_limit_exceeded | Rate limit exceeded |
| 502/503 | api_unavailable | Temporary backend failure |
{ "error": "not_found" }Respect Cache-Control headers and avoid repeatedly requesting identical data. Breaking changes will use a new versioned path.
For the general DOJ guide, see DOJ Guide.