DOJ logoDOJ
문제
최근 추가된 문제들저장한 문제
카테고리DLC대회그룹팀게시판
랭킹
문제 풀이 랭킹스트릭 랭킹DOJ Power 랭킹
현황
문제 제안로그인회원가입
DOJ logoDOJ

OI 서브태스크 채점, Elo 레이팅, Discord 인증을 갖춘 커뮤니티 온라인 저지.

문제
문제 목록카테고리
커뮤니티
대회랭킹게시판공지사항외부 대회 개최이용 안내
계정
로그인회원가입채점 현황
정책
이용약관DLC 이용 규칙개인정보 처리방침API 사용 설명서언어별 채점 환경대회 순위 보상레이팅과 퍼포먼스
© 2026 DOJ
모든 권리 보유

정책

  • 이용약관
  • DLC 이용 규칙
  • 개인정보 처리방침
  • API 사용 설명서
  • 언어별 채점 환경
  • 대회 순위 보상
  • 레이팅과 퍼포먼스

DOJ PUBLIC API · V1

API 사용 설명서

DOJ의 공개 사용자, 문제, 대회, 레이팅 데이터를 읽기 전용 JSON으로 제공합니다. 문제 지문과 비공개 운영 데이터는 포함하지 않습니다.

기본 주소https://doj.kr/api/v1
빠른 시작공통 규칙엔드포인트사용자문제대회페이지네이션오류

빠른 시작

현재 v1 읽기 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 계정, 권한 정보, 제출 코드는 반환하지 않습니다. 프로필 이미지 URL은 공개 전달 경로만 반환하며 오래된 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에서 대소문자를 구분합니다. 검색어와 경로의 핸들을 실제 표기와 같은 대소문자로 입력해야 합니다.

GET/api/v1/users사용자 검색
이름형식기본값설명
qstring""핸들 일부(대소문자 구분)
limit1..10020한 페이지 결과 수
cursorstring-이전 응답의 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
}
GET/api/v1/users/{handle}사용자 공개 정보

검색 응답 필드에 자기소개, 가입 시각, 팔로워·팔로잉 수를 더해 반환합니다. 존재하지 않거나 공개할 수 없는 계정은 404입니다.

GET/api/v1/users/{handle}/contest-participations대회 참가 기록

종료된 공개·초대 전용 대회만 대회 시작 시각 내림차순으로 반환합니다. 진행 중인 대회와 비공개 대회는 제외합니다. limit과 cursor를 사용할 수 있습니다.

GET/api/v1/users/{handle}/virtual-participations버츄얼 참가 기록

공개 카테고리에서 종료된 버츄얼 참가 기록을 반환합니다. 팀 기록은 실제 팀원 기준으로 조회하며 문제별 점수와 제출은 포함하지 않습니다.

이름형식기본값설명
limit1..200100한 페이지 기록 수
cursorstring-이전 응답의 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
}
GET/api/v1/users/{handle}/rating-history레이팅 그래프 데이터

오래된 기록부터 반환합니다. x축에는 occurredAt, y축에는 newRating을 사용하면 됩니다. 비공개 대회에서 생긴 변화는 수치 연속성을 유지하되 contest를 null로 반환합니다.

이름형식기본값설명
limit1..200100한 페이지 기록 수
cursorstring-이전 응답의 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
}

문제

GET/api/v1/problems공개 문제 검색
이름형식기본값설명
qstring""번호, slug 또는 제목 검색
difficultyMininteger-최소 난이도 값
difficultyMaxinteger-최대 난이도 값
tagsCSV""모두 포함해야 할 태그, 최대 10개
sortenumdisplay_id_asc아래 정렬값 중 하나
limit1..10020한 페이지 결과 수
cursorstring-이전 응답의 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
}
GET/api/v1/problems/{displayId}공개 문제 정보

목록과 같은 메타데이터를 한 문제에 대해 반환합니다. 지문, 입출력 설명, 제한, 예제, 에디토리얼과 채점 데이터는 포함하지 않습니다.

대회

GET/api/v1/contests대회 검색
이름형식기본값설명
qstring""slug 또는 제목 검색
statusenumallall, upcoming, running, ended
limit1..10020한 페이지 결과 수
cursorstring-이전 응답의 nextCursor
GET/api/v1/contests/{slug}대회 정보

시작·종료 시각, window 설정, rated 여부, 문제 수와 함께 설명·규칙을 반환합니다. 비공개 대회는 404로 처리합니다.

페이지네이션

목록 응답의 nextCursor가 null이 아니면, 값을 해석하거나 수정하지 말고 다음 요청의 cursor에 그대로 전달하세요. 필터나 정렬을 바꾸면 기존 커서를 재사용하지 마세요.

GET /api/v1/problems?limit=20&cursor=eyJvZmZzZXQiOjIwfQ

오류와 캐시

HTTP오류의미
400invalid_request쿼리 형식이나 범위가 잘못됨
400invalid_cursor사용할 수 없는 커서
404not_found없거나 공개되지 않은 리소스
429rate_limit_exceeded요청 제한 초과
502/503api_unavailable일시적인 백엔드 오류
{ "error": "not_found" }

응답의 Cache-Control을 존중하고, 같은 데이터를 짧은 간격으로 반복 요청하지 마세요. v1에서 호환되지 않는 변경이 필요하면 새 버전 경로를 사용합니다.

일반 DOJ 이용 안내는 DOJ 안내를 참고하세요.