API v1

흐름

  1. API 키 Console › API 연동
  2. 프로필 Console › 프로필에서 평가 기준 저장
  3. 세션 보내기 POST /v1/sessions
  4. 결과 받기 웹훅 또는 GET /v1/reports/{id}
  5. 기간 리포트 주간 · 월간 자동, 직전 기간 대비
POST /v1/sessions ─► session: pending ─► completed ─► report: pending ─► completed ─► 웹훅
주·월 마감 + 3시간 ──────────────────────────────► report(period) ─► completed ─► 웹훅

인증

Authorization: Bearer ark_…
  • 키 하나 = 조직 전체 권한. 발급할 때 한 번만 표시
  • JSON. 시각은 오프셋이 있는 ISO 8601 (2026-11-09T10:00:00+09:00)
  • 목록: ?cursor=&limit= (1–100, 기본 20) → { data, next_cursor }
  • 오류: { "error": { "code", "message", "requestId" } }

상태

상태 session report
pending 가져오기 · 전사 중 평가 중
completed 대화록 준비됨 (평가는 report에서) 완료
failed error_code 참고 error_code 참고

엔드포인트

Method Path
POST /v1/uploads 업로드 주소
POST /v1/sessions 세션 보내기
GET /v1/sessions subject status profile external_id from to
GET /v1/sessions/{id} ?include=transcript
DELETE /v1/sessions/{id} 음성 · 대화록 · 세션 리포트 삭제
POST /v1/reports 다시 평가 · 기간 리포트
GET /v1/reports kind subject session_id profile period status from to
GET /v1/reports/{id} ?format=json|md|html|pdf

POST /v1/sessions

{
  "profile": "callcenter",
  "subject": "agent-1042",
  "external_id": "call-0001",
  "occurred_at": "2026-11-09T10:12:00+09:00",
  "metadata": { "name": "김상담" },
  "audio": { "url": "https://files.example.com/call.mp3", "headers": { "Authorization": "Bearer …" } }
}
필드
profile 필수 프로필 key. 받는 시점의 최신 버전으로 고정
subject 필수 평가 대상의 고유 아이디
external_id 같은 값이면 기존 세션 반환 (200)
occurred_at 기간 리포트 구간 기준. 기본값: 받은 시각
metadata ≤ 16KB. 리포트 작성에 참고
audio | transcript 하나 아래
소스 audio transcript
URL { "url" } { "url" }
URL + 헤더 { "url", "headers" } { "url", "headers" }
업로드 { "upload_id" } { "upload_id" }
본문 "문자열" 또는 [{ "speaker", "text" }]
  • URL: https, 공인 주소만. 헤더는 받은 직후 삭제
  • 음성 최대 20MB (Groq 25MB)
  • 대화록 파일: [{ "speaker", "text" }] JSON이면 그대로, 그 밖(txt · vtt · srt)은 글자 그대로. 최대 40만 자
  • 음성 · 대화록은 프로필의 retention_days가 지나면 삭제 (purged_at). 리포트는 남음

→ 202 세션 객체

POST /v1/uploads

{ "content_type": "audio/mpeg" }

→ 201 { "upload_id", "url", "method": "PUT", "headers", "expires_at" }

5분 안에 url로 PUT (headers의 content-type 그대로) → { "upload_id" }로 세션 생성

POST /v1/reports

{ "session_id": "…", "profile": "callcenter" }
{ "subject": "agent-1042", "profile": "callcenter", "from": "2026-10-01T00:00:00+09:00", "to": "2026-11-01T00:00:00+09:00" }
  • 위: 다시 평가. 프로필의 최신 버전 사용 (profile 생략 시 세션의 프로필)
  • 아래: 기간 리포트 [from, to), 최대 1년. 요청 시각까지 도착한 세션
  • 주간 · 월간은 자동 (프로필 period_report). 경계는 프로필 timezone의 자정
  • 마감 + 3시간까지 도착한 세션만 포함. 늦게 온 세션은 반영 안 됨
  • 그 프로필로 받아 그 프로필로 평가한 세션 리포트만 모음. 세션당 최신 1건

→ 202 리포트 객체

리포트 객체

{
  "object": "report",
  "id": "…",
  "kind": "period",
  "status": "completed",
  "error_code": null,
  "profile": { "key": "callcenter", "version": 3 },
  "subject": "agent-1042",
  "session_id": null,
  "period": { "type": "week", "key": "2026-W45", "start": "2026-11-01T15:00:00.000Z", "end": "2026-11-08T15:00:00.000Z" },
  "summary": "…",
  "scores": {
    "overall": 91.7, "prev": 47.9, "delta": 43.8,
    "items": [{ "key": "greeting", "label": "첫인사", "score": 100, "n": 2, "prev": 75, "delta": 25 }]
  },
  "stats": { "sessions": 2, "audio_seconds": 312.5, "prev_sessions": 2, "timezone": "Asia/Seoul" },
  "content_md": "## …",
  "links": { "md": "…", "html": "…", "pdf": "…" }
}
  • 점수 0–100. null = 관찰 안 됨 (평균에서 제외)
  • scale: (raw − min) / (max − min) × 100 · check: 통과 100, 미통과 0
  • overall = 항목 weight 가중 평균. 기간 리포트는 세션 overall의 평균
  • 세션 리포트 항목: raw, evidence(실제 발화 인용. 대화록에 없는 인용은 제거), comment
  • 기간 리포트 항목: n, prev, delta. 직전 = 지난주 · 지난달 · 같은 길이의 앞 구간. 항목은 key로 비교

웹훅

이벤트
report.completed
report.failed
session.failed
{ "id": "<webhook-id>", "type": "report.completed", "created_at": "…", "data": { "object": "report", … } }

data = 조회 API와 같은 객체. 서명: Standard Webhooks

webhook-id: 5ef8dc82-…
webhook-timestamp: 1794193483
webhook-signature: v1,base64(HMAC-SHA256(base64decode(secret − "whsec_"), "{id}.{timestamp}.{body}"))
  • 검증: 서명 일치 + webhook-timestamp가 현재 ±5분 이내
  • 2xx가 아니면 재시도: 1, 2, 4 … 60분, 8회. webhook-id 동일 → 중복 제거 키로 사용
  • 순서 보장 없음 → data.updated_at
  • 10초 안에 응답. 무거운 처리는 받은 뒤 비동기로
  • 서명 비밀(whsec_…): 웹훅 등록할 때 한 번만 표시

프로필 설정

Console → 프로필에서 JSON으로 편집. 저장할 때마다 새 버전 (이미 받은 세션은 받을 때의 버전으로 평가)

{
  "language": "ko",
  "roles": ["agent", "customer"],
  "evaluate": "agent",
  "stt": { "model": "groq/whisper-large-v3-turbo" },
  "llm": { "model": "google/gemini-3.6-flash" },
  "rubric": { "guidance": "…", "items": [ … ] },
  "session_report": { "instructions": "…", "sample": "## 요약\n…" },
  "period_report": { "periods": ["week", "month"], "timezone": "Asia/Seoul", "week_start": "mon", "instructions": "…", "sample": "…" },
  "retention_days": 90
}
필드 기본값
language ko 리포트 언어 · 전사 힌트
roles [] 화자 역할. 2개 이상이면 전사 후 화자 표시
evaluate 대화 전체 평가할 역할 (roles 중 하나)
stt.model groq/whisper-large-v3-turbo google/gemini-* · groq/whisper-large-v3(-turbo)
llm.model google/gemini-3.6-flash google/gemini-*
rubric rubric · session_report 중 하나는 필수
session_report 요약 · 잘한 점 · 개선할 점 instructions(지침), sample(이상적인 리포트 Markdown)
period_report 사용 안 함 periods, timezone, week_start(mon · sun)
retention_days 계속 보관 음성 · 대화록 보관 일수

루브릭 항목:

{ "key": "greeting", "label": "첫인사", "description": "…", "type": "scale", "min": 1, "max": 5, "anchors": { "1": "…", "5": "…" }, "weight": 2 }
{ "key": "disclosure", "label": "필수 고지", "type": "check" }
필드
key 소문자 · 숫자 · _. 기간 비교의 기준. 의미가 다른 항목은 새 key로
type scale(min ~ max 정수) · check(통과 / 미통과)
anchors 점수별 기준 (선택)
weight 가중치, 기본 1

리포트 본문(content_md) 위의 점수표는 자동으로 붙음 → sample에는 점수표를 넣지 않음

오류 코드

code HTTP
unauthorized 401
invalid_request invalid_json invalid_cursor invalid_time 400 · 422
profile_not_found session_not_found report_not_found 404
session_not_ready · session_purged 409 · 410
url_must_be_https url_not_public invalid_url invalid_window transcript_too_large 422

세션·리포트 error_code: source_401 source_too_large upload_not_found audio_too_large stt_429 transcript_empty llm_schema no_sessions …