공개 API v1
외부 시스템에서 QA Note 프로젝트·이슈를 조회·조작하는 REST API v1 레퍼런스
목차
- 버전 정책
- 인증
- Base URL · 요청 형식
- 엔드포인트 (v1)
- `GET /api/v1/projects`
- `GET /api/v1/projects/{projectId}/issues`
- `GET /api/v1/projects/{projectId}/issues/{issueNumber}`
- `PATCH /api/v1/projects/{projectId}/issues/{issueNumber}`
- `POST /api/v1/projects/{projectId}/issues/{issueNumber}/comments`
- 에러 응답
- Rate Limit
- Webhook vs API
- 변경 로그
- SDK · 코드 샘플
- curl
- JavaScript (`fetch`)
- Node.js (오류 처리 포함)
공개 API v1
QA Note 공개 API v1 은 외부 시스템에서 프로젝트와 이슈를 안정적으로 다루기 위한 REST API 입니다. 모든 경로는 /api/v1/ 접두사를 가지며, 호환성을 깨는 변경은 새 버전(v2)으로만 발행됩니다.
내부에서 쓰이는 Extension·Widget 전용 엔드포인트(예: /api/extension/...)는 이 문서의 범위가 아닙니다. 전체 엔드포인트 목록은 엔드포인트 레퍼런스를, API Key 발급은 인증 페이지를 참고하세요.
버전 정책
- 안정성 보증: v1 의 응답 스키마와 경로는 호환성을 깨지 않는 한 유지됩니다. 필드 추가는 호환 변경으로 간주합니다.
- 파괴적 변경: 응답 필드 제거·타입 변경·경로 변경은 v2 발행 시점부터 적용되며, v1 은 최소 6개월 동안 병행 지원됩니다.
- 변경 알림: 호환성 영향이 있는 변경은 Changelog 와 대시보드 공지로 사전 안내합니다.
인증
공개 API v1 은 API Key 또는 MCP OAuth 액세스 토큰을 받습니다. CI/CD · 헤드리스 서버 · 외부 자동화에는 API Key 가 권장됩니다.
curl https://qanote.app/api/v1/projects \
-H "Authorization: Bearer qn_YOUR_API_KEY"
| 항목 | 값 |
|---|---|
| 헤더 | Authorization: Bearer qn_... |
| Scope (조회) | projects:read · issues:read |
| Scope (변경) | issues:write |
| 발급 위치 | 대시보드 → 조직 설정 → API Keys |
발급된 API Key 는 단일 조직에 묶입니다. 여러 조직을 다루려면 조직별로 키를 발급하세요. 더 자세한 내용은 인증 가이드에 있습니다.
Base URL · 요청 형식
https://qanote.app/api/v1
- 모든 요청과 응답은 UTF-8 JSON 입니다.
POST·PATCH요청 본문에는Content-Type: application/json헤더가 필요합니다.- 시간 값은 ISO 8601 (
2025-03-15T14:30:00.000Z) 형식으로 반환됩니다.
엔드포인트 (v1)
전체 엔드포인트 스펙은 엔드포인트 레퍼런스에 있습니다. 아래는 외부 통합에서 가장 자주 쓰이는 핵심 엔드포인트입니다.
GET /api/v1/projects
API Key 가 발급된 조직에 속한 프로젝트 목록을 반환합니다.
필요 Scope: projects:read
Query 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
organizationSlug | string | No | 조직 slug 필터 (/dashboard/<slug>/... 의 slug) |
organizationId | string (uuid) | No | 조직 ID 필터 (organizationSlug 와 택일) |
요청
curl https://qanote.app/api/v1/projects \
-H "Authorization: Bearer qn_YOUR_API_KEY"
응답
{
"data": [
{
"id": "project_abc123",
"name": "웹 서비스",
"slug": "web-service",
"description": null,
"organizationId": "2a3f7b04-6e91-4c2d-9f77-3d6c9a1e4b58",
"organizationSlug": "acme",
"organizationName": "Acme Inc.",
"createdAt": "2025-01-15T09:00:00.000Z"
}
]
}
GET /api/v1/projects/{projectId}/issues
프로젝트의 이슈 목록을 조회합니다. 페이지네이션과 필터링을 지원하며, LLM 토큰 절약을 위해 본문은 핵심 필드만 반환합니다.
필요 Scope: issues:read
Query 파라미터
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
status | string | No | open · in_progress · resolved · closed |
priority | string | No | low · medium · high · critical |
q | string | No | 제목·설명 검색어 |
label | string | No | 라벨 이름 |
page | number | No | 페이지 번호 (기본 1) |
limit | number | No | 페이지당 항목 수 (기본 20, 최대 100) |
요청
curl "https://qanote.app/api/v1/projects/PROJECT_ID/issues?status=open&limit=20" \
-H "Authorization: Bearer qn_YOUR_API_KEY"
응답
{
"data": [
{
"id": "issue_xyz",
"issueNumber": 42,
"title": "로그인 페이지에서 비밀번호 입력 시 오류 발생",
"status": "open",
"priority": "high",
"labels": ["bug", "auth"],
"assignees": ["이검수"],
"createdAt": "2025-03-15T14:30:00.000Z",
"updatedAt": "2025-03-15T14:30:00.000Z"
}
],
"total": 42,
"page": 1,
"totalPages": 3
}
GET /api/v1/projects/{projectId}/issues/{issueNumber}
이슈 상세를 조회합니다. 메타데이터 요약(콘솔 오류·네트워크 오류·JS 에러 카운트)이 포함되며, 개별 메타데이터 본문은 별도 엔드포인트(예: console-logs, network-logs)에서 조회합니다.
필요 Scope: issues:read
curl https://qanote.app/api/v1/projects/PROJECT_ID/issues/42 \
-H "Authorization: Bearer qn_YOUR_API_KEY"
PATCH /api/v1/projects/{projectId}/issues/{issueNumber}
이슈의 상태 또는 우선순위를 업데이트합니다. 외부 자동화(예: GitHub Actions 워크플로 → 머지 시 resolved 처리)에 사용합니다.
필요 Scope: issues:write
Request Body
| 이름 | 타입 | 필수 | 설명 |
|---|---|---|---|
status | string | No | 변경할 상태 |
priority | string | No | 변경할 우선순위 |
curl -X PATCH https://qanote.app/api/v1/projects/PROJECT_ID/issues/42 \
-H "Authorization: Bearer qn_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"status": "in_progress"}'
POST /api/v1/projects/{projectId}/issues/{issueNumber}/comments
이슈에 코멘트를 추가합니다. 외부 봇(예: 배포 알림 → 관련 이슈에 코멘트)에 사용합니다.
필요 Scope: issues:write
curl -X POST https://qanote.app/api/v1/projects/PROJECT_ID/issues/42/comments \
-H "Authorization: Bearer qn_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"content": "Preview 배포에서 재현 확인했습니다."}'
이슈 신규 생성은 공개 API v1 의 범위가 아닙니다. Extension·Widget 또는 대시보드를 통해 등록된 이슈만 본 API 로 조회·갱신할 수 있습니다.
에러 응답
모든 에러는 표준 HTTP 상태 코드와 JSON 본문을 반환합니다. 본문 형식과 코드별 의미는 에러 처리 페이지에 정리돼 있습니다.
{
"error": "Insufficient scope"
}
요청 본문 유효성 검사 실패 시 details 배열이 포함됩니다.
{
"error": "Invalid input",
"details": [
{ "field": "status", "message": "Invalid enum value." }
]
}
| 상태 코드 | 의미 |
|---|---|
200 · 201 | 성공 |
400 | 입력 형식·값 오류 |
401 | 인증 실패 (API Key 누락·만료) |
403 | Scope 부족 |
404 | 리소스 없음 또는 다른 조직 |
429 | Rate Limit 초과 |
500 | 서버 내부 오류 |
Rate Limit
| 제한 | 값 |
|---|---|
| 분당 요청 | 100 req/min (API Key 1개 기준, 슬라이딩 윈도우) |
| 인증 시도 | 15분당 5회 |
초과 시 429 Too Many Requests 응답이 반환됩니다. 응답 헤더의 Retry-After (초) 값을 따르거나, 지수 백오프(exponential backoff)로 재시도하세요.
# 응답 헤더 예시
HTTP/2 429
Retry-After: 32
Webhook vs API
Webhook 은 QA Note 가 외부 시스템으로 보내는 단방향 이벤트입니다. 외부 시스템이 능동적으로 데이터를 가져오거나 갱신해야 한다면 본 API 를 사용하세요.
변경 로그
| 버전 | 날짜 | 변경 |
|---|---|---|
v1.0 | 2026-04 | 최초 공개 — /projects · /issues · /comments · 메타데이터 13종 |
호환성 영향이 있는 변경 발생 시 이 표에 추가됩니다.
SDK · 코드 샘플
curl
curl https://qanote.app/api/v1/projects \
-H "Authorization: Bearer qn_YOUR_API_KEY"
JavaScript (fetch)
const res = await fetch("https://qanote.app/api/v1/projects", {
headers: { Authorization: `Bearer ${process.env.QANOTE_API_KEY}` },
});
const { data } = await res.json();
Node.js (오류 처리 포함)
async function listOpenIssues(projectId: string) {
const res = await fetch(
`https://qanote.app/api/v1/projects/${projectId}/issues?status=open`,
{ headers: { Authorization: `Bearer ${process.env.QANOTE_API_KEY}` } },
);
if (res.status === 429) {
const retryAfter = Number(res.headers.get("retry-after") ?? 30);
throw new Error(`Rate limited. Retry after ${retryAfter}s`);
}
if (!res.ok) {
const body = await res.json().catch(() => ({}));
throw new Error(body.error ?? `HTTP ${res.status}`);
}
const { data } = await res.json();
return data;
}
전체 엔드포인트 명세는 엔드포인트 레퍼런스에서 이어집니다.