API 개요
Framedash REST API를 사용하여 텔레메트리 데이터의 조회 및 분석을 수행할 수 있습니다.
기본 URL
섹션 제목: “기본 URL”| 서비스 | URL |
|---|---|
| Web API (Projects, Maps, Content, Query, Analytics, Alerts, Data) | https://app.framedash.dev/api |
| Ingest API (Event Ingestion) | https://ingest.framedash.dev |
/api/v1 아래의 REST API는 API 키 또는 OAuth 2.1 Bearer 토큰 중 하나를 받습니다. 한 요청이 둘 다 보내면 X-API-Key 헤더가 우선합니다. 대부분의 통합에서는 API 키를 사용하며, X-API-Key 헤더로 전송합니다:
X-API-Key: fd_your_api_key_hereAPI 키는 대시보드에서 각 프로젝트의 “API 키” 페이지에서 생성할 수 있습니다. 새 키는 fd_ 접두사를 사용하며, 권한 부여는 접두사가 아니라 저장된 scope로 결정됩니다.
Free 플랜에서는 프로젝트당 활성 API 키를 최대 2개까지 가질 수 있으며, 키 값은 생성 시 한 번만 표시됩니다. 상한에 도달하면 사용하지 않는 키를 비활성화한 후 새 키를 생성하세요.
URL 경로가 프로젝트로 스코프되지 않은 엔드포인트(/v1/content 아래의 콘텐츠 레지스트리 등)에는 대상 프로젝트를 지정하는 X-Project-Id 헤더도 필요합니다:
X-Project-Id: your-project-uuidAPI 키 프리셋
섹션 제목: “API 키 프리셋”| 프리셋 | Scope | 용도 |
|---|---|---|
| Ingest | events:write | SDK 이벤트 수집 전용 |
| Read-only | analytics:read | 대시보드, 상태, 분석 읽기, CLI 읽기, raw SQL을 제외한 MCP 도구 |
| Read & Write | analytics:read, resources:write | 읽기와 맵, 콘텐츠, 알림 변경 |
| Full | analytics:read, resources:write, data:admin | raw SQL 쿼리, 데이터 내보내기, 플레이어 삭제 |
키 검증하기
섹션 제목: “키 검증하기”GET /v1/whoami는 유효한 API 키라면 scope와 무관하게 검증하고, 그 키에 관한 민감하지 않은 메타데이터를 반환합니다. events:write만 가진 Ingest 키처럼 어떤 읽기 엔드포인트에도 도달할 수 없는 키라도 이것으로 동작을 확인할 수 있습니다. 여기서는 X-API-Key 헤더만 받으며, OAuth Bearer 토큰은 받지 않습니다.
curl https://app.framedash.dev/api/v1/whoami \ -H "X-API-Key: fd_your_api_key_here"응답은 scope에 따라 단계적입니다. 읽기 또는 관리 계열 scope(analytics:read, resources:write, data:admin)를 가진 키는 완전한 메타데이터 { projectId, projectName, tenantId, planId, scopes }를 반환하고, 데이터 플레인 전용 키는 { projectId, scopes }만 반환합니다. 키의 원본 값은 절대 반환하지 않으며, 키가 없거나 유효하지 않으면 401을 반환합니다.
이 엔드포인트에는 플랜 할당량과 별개로, 테넌트당 시간당 60 요청의 전용 속도 제한이 있습니다. 초과하면 Retry-After 헤더가 붙은 429를 반환합니다.
OAuth 2.1
섹션 제목: “OAuth 2.1”REST API는 API 키 대신 OAuth 2.1 Bearer 토큰도 받습니다:
Authorization: Bearer <access-token>Framedash는 OAuth 2.1 인가 서버입니다. 클라이언트는 {origin}/.well-known/oauth-authorization-server에서 엔드포인트를 검색할 수 있습니다({origin}은 https://app.framedash.dev):
| 엔드포인트 | URL |
|---|---|
| 인가 | {origin}/oauth/authorize |
| 토큰 | {origin}/api/oauth/token |
| 동적 클라이언트 등록 (RFC 7591) | {origin}/api/oauth/register |
| 취소 | {origin}/api/oauth/revoke |
지원되는 것은 PKCE(S256)를 사용하는 인가 코드 플로우뿐이며, 퍼블릭 클라이언트(token_endpoint_auth_method가 none)를 대상으로 합니다. 그랜트 타입은 authorization_code와 refresh_token입니다.
OAuth 토큰이 가질 수 있는 scope는 analytics:read와 resources:write뿐입니다. 클라이언트가 scope를 지정하지 않으면 analytics:read가 부여됩니다. data:admin, events:write, events:synthetic scope는 OAuth로 절대 부여되지 않으므로, 이를 필요로 하는 작업은 API 키 전용으로 남습니다. 예를 들어 POST /v1/query는 data:admin이 필요하므로 OAuth 토큰으로 호출할 수 없습니다.
연결된 앱
섹션 제목: “연결된 앱”인가된 OAuth 앱은 대시보드의 “설정” → “연결된 앱”에 나열됩니다. 각 항목은 클라이언트 이름, 부여된 scope, 동의한 프로젝트, 생성 시각과 마지막 사용 시각을 표시하며, 개별적으로 취소할 수 있습니다.
텔레메트리 쿼리
섹션 제목: “텔레메트리 쿼리”취합된 이벤트는 SQL로 쿼리할 수 있습니다. project_id는 헤더가 아니라 JSON 본문에 담고, X-API-Key로 인증합니다. raw SQL에는 data:admin scope(Full 프리셋)가 필요합니다.
curl -X POST https://app.framedash.dev/api/v1/query \ -H "X-API-Key: fd_your_api_key_here" \ -H "Content-Type: application/json" \ -d '{ "project_id": "your-project-uuid", "sql": "SELECT event_name, count() AS events FROM events WHERE timestamp >= today() GROUP BY event_name ORDER BY events DESC", "limit": 100 }'응답은 { "success": true, "data": { "rows": [...], "rowCount": N } }입니다. 거부된 쿼리는 HTTP 400과 ClickHouse 진단 메시지(존재하지 않는 컬럼, 테이블, 함수, 구문 오류, 타입 불일치, 금지된 연산)를 반환하며, 인프라 장애만 500을 반환합니다. 컬럼과 검증기 규칙은 이벤트 스키마를, 이벤트 도달 확인은 문제 해결을 참고하세요.
이벤트 취합
섹션 제목: “이벤트 취합”취합 엔드포인트(POST /v1/events)는 application/x-protobuf만 받습니다(JSON 본문은 415를 반환). 이벤트는 공식 Unity, UE5, Godot SDK가 생성하며, protobuf TelemetryBatch를 인코딩하고 필요한 헤더를 자동으로 설정합니다. 이벤트를 수동으로 보내려면 그 protobuf 스키마를 직접 인코딩하고 X-API-Key(events:write scope), Content-Type: application/x-protobuf, Content-Length, X-SDK-Version을 보내야 합니다. 거의 모든 통합에서는 직접 전송 대신 SDK를 사용하세요.
속도 제한
섹션 제목: “속도 제한”API 속도 제한은 계정(테넌트) 단위로 적용되며, 시간당 요청 수로 셉니다. 같은 계정에 속한 모든 프로젝트와 API 키가 하나의 한도를 공유합니다. Free 플랜은 시간당 100 요청이고, 유료 플랜은 이보다 높습니다.
모든 응답에는 다음 세 헤더가 붙습니다:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 99X-RateLimit-Reset: 1782968400000X-RateLimit-Reset은 초가 아니라 밀리초 단위의 Unix 타임스탬프입니다.
한도에 도달하면 429를 반환합니다. 이때 X-RateLimit-Remaining은 0이 되고, 대기할 초를 나타내는 Retry-After 헤더가 추가됩니다:
X-RateLimit-Limit: 100X-RateLimit-Remaining: 0X-RateLimit-Reset: 1782968400000Retry-After: 3400이 제한은 슬라이딩 윈도우로 계산됩니다. 그래서 X-RateLimit-Reset이 가리키는 시각이 막 지난 직후에도 요청이 여전히 제한될 수 있고, Retry-After가 거의 한 시간까지 치솟을 수 있습니다. 리셋 시각을 노려 재전송하지 말고, 429 응답의 Retry-After에 따라 대기하세요. 정상 응답에서는 X-RateLimit-Remaining을 보고 한도에 도달하기 전에 요청 간격을 벌리세요.
응답 형식
섹션 제목: “응답 형식”Web API(app.framedash.dev/api)와 Ingest API(ingest.framedash.dev)는 오류 형태가 다릅니다. 하나의 파서로 둘 다 처리할 수 있다고 가정하지 말고, 엔드포인트별 형태를 나눠서 처리하세요.
Web API
섹션 제목: “Web API”성공 시:
{ "success": true, "data": { ... }}오류 시 API는 RFC 9457 Problem Details를 application/problem+json 형식으로 반환합니다:
{ "type": "about:blank", "title": "Forbidden", "status": 403, "detail": "Plan limit reached.", "error_category": "authorization", "retryable": false}| 멤버 | 설명 |
|---|---|
type | 문제 유형 URI. 특정 유형이 없으면 about:blank. |
title | HTTP 상태에 대한 짧고 사람이 읽을 수 있는 요약. |
status | HTTP 상태 코드. |
detail | 이 개별 오류에 대한 사람이 읽을 수 있는 설명. |
error_category | authentication, authorization, validation, rate_limit, not_found, conflict, payload, internal 중 하나. |
retryable | 재시도로 성공할 수 있는지 여부(429 및 503에서 true). |
retry_after | 선택. 권장 재시도 대기 시간(초). |
Ingest API
섹션 제목: “Ingest API”성공 시:
{ "status": "accepted"}오류 시:
{ "error": "Error message"}OpenAPI 스펙
섹션 제목: “OpenAPI 스펙”API 스펙은 OpenAPI 3.1 형식으로 다운로드할 수 있습니다.
엔드포인트
섹션 제목: “엔드포인트”상세 정보는 사이드바의 자동 생성 API 레퍼런스를 참조하세요.
Projects
섹션 제목: “Projects”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/projects | GET | API 키에 연결된 프로젝트 |
/v1/projects/{id}/status | GET | 프로젝트 상태 |
키 검증
섹션 제목: “키 검증”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/whoami | GET | API 키를 검증하고 민감하지 않은 키 메타데이터를 반환 |
Analytics
섹션 제목: “Analytics”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/projects/{id}/dashboard | GET | 대시보드 지표 (DAU, MAU, 세션, 이벤트) |
/v1/projects/{id}/builds | GET | 퍼포먼스 데이터가 있는 빌드 ID 목록 |
/v1/projects/{id}/builds/compare | GET | 두 빌드의 퍼포먼스 비교 |
/v1/projects/{id}/heatmap | GET | 맵 히트맵 데이터 |
/v1/projects/{id}/retention | GET | 플레이어 리텐션 코호트 |
/v1/projects/{id}/funnels | GET | 퍼널 전환 분석 |
/v1/projects/{id}/insights | GET | 차원별 집계 분석 |
Alerts
섹션 제목: “Alerts”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/projects/{id}/alerts | GET | 알림 규칙 목록 |
/v1/projects/{id}/alerts | POST | 알림 규칙 생성 |
/v1/projects/{id}/alerts/{alertId} | GET | 알림 규칙 조회 |
/v1/projects/{id}/alerts/{alertId} | PATCH | 알림 규칙 업데이트 |
/v1/projects/{id}/alerts/{alertId} | DELETE | 알림 규칙 비활성화 |
/v1/projects/{id}/alerts/history | GET | 알림 평가 이력 |
/v1/projects/{id}/threshold-profiles | GET | 임계값 프로필 목록 |
Maps
섹션 제목: “Maps”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/projects/{id}/maps | GET | 맵 목록 |
/v1/projects/{id}/maps/{mapId} | DELETE | 맵 삭제 |
/v1/maps/upload | POST | 맵 업로드 |
Content Registry
섹션 제목: “Content Registry”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/content | GET | 콘텐츠 항목 목록 |
/v1/content | POST | 콘텐츠 항목 생성/업데이트 |
/v1/content | DELETE | 콘텐츠 항목 삭제 |
Query
섹션 제목: “Query”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/query | POST | 분석 쿼리 실행 |
Data
섹션 제목: “Data”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/data/export | GET | 접근 가능한 프로젝트 데이터 내보내기 |
/v1/data/erase | POST | 지정한 플레이어의 텔레메트리 삭제 |
Event Ingestion
섹션 제목: “Event Ingestion”| 엔드포인트 | 메서드 | 설명 |
|---|---|---|
/v1/events | POST | 텔레메트리 이벤트 수집 |