개발자 문서
파트너 데이터 API 는 통합 파트너가 우리 분석 데이터를 프로그래밍으로 가져가 자체 어드민·제품에 렌더하는 독립 상품입니다. 웹 대시보드가 아니며, 어떤 웹 구독으로도 열리지 않습니다. 베이스 경로는 POST /partner/v1/… — API 는 POST 전용입니다.
두 개의 별개 축
축1 — SaaS 대시보드 티어: 사람이 우리 UI 에 로그인, per-tenant 월정액, JWT 인증. 축2 — API 토큰(이 문서): 기계가 우리 데이터를 HTTP 로 가져감, 테넌트리스 크리덴셜, 호출당 토큰 미터링.
웹 구독은 API 토큰 0개를, API 크리덴셜은 대시보드 접근 0을 포함합니다 — 두 축은 서로 교차하지 않습니다. (ChatGPT Plus 웹 vs OpenAI API 관계.)
인증 — 공유 시크릿
스킴은 공유 시크릿 크리덴셜입니다 — HMAC 요청 서명이 아닙니다. 타임스탬프도, 정규화 문자열도, base64(HMAC-SHA256(…)) 서명도 없습니다. 클라이언트가 TLS 위로 시크릿을 직접 보내면 서버는 해시(SHA-256 + pepper)해서 상수시간 비교합니다.
| 헤더 | 필수 | 값 |
|---|---|---|
| X-Partner-Client | 필수 | 프로비저닝 시 발급된 클라이언트 UUID |
| X-Partner-Secret | 필수 | 원시 시크릿, 형식 plk_ + 48 hex |
| Idempotency-Key | 선택 | 클라이언트 지정 중복제거 키 (서버에서 "{clientId}:{key}" 스코프) |
| Content-Type | 필수 | application/json |
- 테넌트리스 크리덴셜. 크리덴셜(PartnerClient)에는 tenant_key 컬럼이 없습니다 — 마스터 키가 될 수 없습니다. 테넌트 귀속은 오직 인가 엣지(PartnerGrant = client × tenant × site × scope)를 통해서만 이뤄집니다.
- Authorization·X-API-Key 헤더는 다운스트림 도달 전 제거됩니다 — 파트너 인증 호출이 JWT/개인 토큰 필터를 건드릴 수 없습니다. (X-API-Key 는 별개 축 = 로그인 사용자 개인 토큰으로, 이 API 를 인증하지 않습니다.)
- 모든 요청 본문은 siteId (UUID) 를 반드시 포함해야 합니다 — grant 핀 키입니다. 누락 시 400 PARTNER_SITE_REQUIRED.
엔드포인트 — 6 스코프 · 8 엔드포인트
모든 엔드포인트는 POST, application/json. 모든 응답은 non-null 정직성 라벨(label)과 선택적 notice 를 담습니다. 필드는 camelCase, enum 값은 소문자입니다. 토큰 비용은 상품 리치니스 사다리를 따릅니다.
공개 상승 키워드·커머스 카테고리 (전역 시장 데이터, 상대 지수)
- POST /partner/v1/market/trends
채널 단위 광고 롤업 (계정 전체, k-익명·버킷 반올림)
- POST /partner/v1/ads/summary
오디언스 핏 사분면 요약 (자사 스코프 · 처방은 봉인, 집계만)
- POST /partner/v1/audience-fit/summary
1st-party 이벤트 피드·활동 요약 (마스킹·가명화, 원시 식별자 없음)
- POST /partner/v1/behavior/events
- POST /partner/v1/behavior/summary
전환/구매 귀속·order_id 멱등 매출 집계 · 퍼널 (집계만, k-익명 봉인)
- POST /partner/v1/conversions/summary
- POST /partner/v1/conversions/funnel
키워드 예산 처방 요약 — savings·scaleUp·untapped·counts (우리 조인 + 예측, 최상위 상품)
- POST /partner/v1/keyword-budget/summary
기간 제한(요청별): audience-fit·conversions/summary·ads ≤ 180일, behavior ≤ 31일, conversions/funnel ≤ 92일, market lookback 1–365일. 응답에는 k-익명 봉인(고유 구매자·세션 임계 미만 시 해당 블록 null + notice)이 적용됩니다.
요청 · 응답 예시
요청 (conversions/summary · 토큰 8):
curl -X POST https://api.statlane.kr/partner/v1/conversions/summary \
-H "X-Partner-Client: 3f2a…-uuid" \
-H "X-Partner-Secret: plk_1a2b3c…(48 hex)" \
-H "Idempotency-Key: 2026-08-15-summary-01" \
-H "Content-Type: application/json" \
-d '{
"siteId": "b91c…-uuid",
"from": "2026-07-01",
"to": "2026-07-31"
}'응답 — 전역 envelope { success, data, error }. 도메인 결과는 항상 HTTP 200 (과금 확정은 내부 도메인-성공 플래그로 구동, HTTP 상태 아님):
{
"success": true,
"data": {
"from": "2026-07-01",
"to": "2026-07-31",
"visitors": 4820,
"conversions": 214,
"conversionRate": 0.0444,
"orders": 231,
"revenueTotal": 18734000,
"aov": 81099,
"currency": "KRW",
"notice": null,
"label": {
"estimated": false,
"observational": true,
"isRelativeIndex": false,
"methodVersion": "conv-1",
"dataBasis": "order_id-idempotent first-party",
"caveats": ["고유 구매자 5 미만 구간은 k-익명 봉인"]
}
},
"error": null
}응답 (keyword-budget/summary · 토큰 13) — 최상위 상품. 우리 조인(광고비 ↔ 키워드 실적)에 예측 처방을 얹어 절감·증액·미개척 4블록을 반환합니다. 필드는 camelCase, 추정 블록은 estimated: true 라벨로 정직하게 표기됩니다:
{
"success": true,
"data": {
"from": "2026-07-01",
"to": "2026-07-31",
"savings": { "keywords": 12, "wastedSpend": 1840000, "currency": "KRW" },
"scaleUp": { "keywords": 7, "headroomSpend": 2600000, "currency": "KRW" },
"untapped": { "keywords": 23, "estImpressions": 41200 },
"counts": { "analyzed": 318, "converting": 96 },
"notice": null,
"label": {
"estimated": true,
"observational": false,
"isRelativeIndex": false,
"methodVersion": "kwbudget-1",
"dataBasis": "ad-spend ↔ keyword conversions join + forecast",
"caveats": ["증액·미개척 추정은 예측치 — 실집행 후 실측으로 갱신"]
}
},
"error": null
}토큰 · 과금
- 1 토큰 = 1 cost_unit. 호출 비용은 상품의 cost_units (append-only 이력, 리프라이스는 UPDATE 가 아닌 새 INSERT). v1 은 call-flat — 서빙 전에 비용이 확정됩니다.
- 2단계 미터링: reserve → settle. 서빙 전 api_usage_month 에 원자적 조건부 증가(used + cost ≤ limit)로 예약, 초과 시 402. 서빙 후 도메인-성공 플래그로 정산 — 성공 시 멱등 원장 INSERT, 실패·취소 시 예약 해제(과금 안 됨).
- 월 쿼터는 fail-CLOSED. plan_limit_units 미설정(=0)이면 즉시 402 — 전역 기본 시드 없음. 월 키는 KST 기준 yyyyMM.
- API 과금 테이블은 웹 티어와 물리적으로 분리. api_usage_month · api_usage_ledger 에는 tenant_key 컬럼이 없습니다 — client_id 축 과금이며, 웹 구독(테넌트 축)과 공유 카운터·행·스필오버가 없습니다.
배선됨 · 기본 비활성 (INERT)
₩ 토큰 단가(partner_token_price 돈다리), 선불 지갑(partner_token_wallet), 과금 모드 스위치(partner_client.billing_mode: monthly / prepaid), 버스트 리미터(초당 429 PARTNER_RATE_LIMITED)는 모두 빌드·배선되어 있으나 기본값은 비활성입니다. partner_token_price 의 ₩ 값은 전부 NULL(INERT)이라 CEO GO 게이트 전까지 실청구는 0입니다. 429 는 클라이언트에 burst_rps 가 설정된 경우에만 발생합니다 — 미설정이면 버스트 게이트를 건너뜁니다(무제한). 선불 지갑·prepaid 모드는 지갑 충전 후 billing_mode 전환 시 동작합니다.
에러 코드
auth 필터는 표준 ApiResponse 에러 envelope 를 직접 기록합니다(전역 예외 핸들러 밖에서 실행). 본문 검증 오류(기간 초과· 잘못된 steps 등)는 서빙 전 bean validation 으로 표준 검증 envelope 로 반환됩니다.
| 코드 | 이름 | HTTP | 의미 |
|---|---|---|---|
| PT001 | PARTNER_UNAUTHENTICATED | 401 | 인증 실패 — 알 수 없거나 정지·만료된 클라이언트, 시크릿 불일치 |
| PT002 | PARTNER_GRANT_DENIED | 403 | 권한 없음 — grant 0건 / 스코프 불일치 / 대상 테넌트 비활성 |
| PT003 | PARTNER_QUOTA_EXCEEDED | 402 | 월 토큰 한도 초과 — reserve 하드 컷 (used + cost > limit) |
| PT004 | PARTNER_METERING_UNAVAILABLE | 503 | 일시 오류 — 미터링 결함 또는 상품 가격 행 없음 |
| PT005 | PARTNER_SITE_REQUIRED | 400 | siteId 누락·무효 — grant 핀 키 필요 |
| PT009 | PARTNER_RATE_LIMITED | 429 | 요청 과다 — 초당 버스트 상한 초과 (client 에 burst_rps 설정 시에만, reserve 前 게이트·fail-OPEN). 미설정=무제한. |
키 발급
파트너는 크리덴셜을 셀프서비스로 발급하지 않습니다. 현재는 Statlane 플랫폼 팀이 클라이언트와 grant(테넌트 × 사이트 × 스코프)·월 쿼터를 발급합니다. 셀프 발급 개발자 콘솔은 준비 중입니다.