1. 시작하기
- 연동 앱 등록을 요청해 주세요([email protected]) — 서비스 이름, 로그인 후 돌아올 주소(
redirect_uri, https)를 알려 주시면 client_id·client_secret을 테스트용·운영용 두 쌍으로 따로 전달해요. - 테스트용과 운영용은 같은 주소(https://extv.co.kr/api/openapi/v1)를 쓰고 키만 달라요. 테스트 키로 연결하면 동의 화면에 ‘테스트’ 표시가 붙어요.
- client_secret 은 서버에만 두고 로그·화면·저장소에 남기지 마세요. 새어 나갔으면 바로 알려 주세요(다시 발급).
| 권한(scope) | 내용 |
|---|---|
donation.read | 내 채널로 들어온 EX 후원 받기(후원자 닉네임·금액·메시지) |
catalog.write | 후원 창에 보일 시그니처·BJ 목록 올리기 |
2. 방송자 동의(OAuth 2.0 Authorization Code)
방송자를 아래 주소로 보내면 ExTV 로그인 → 동의 화면을 거쳐 redirect_uri?code=…&state=… 로 돌아와요(거부하면 error=access_denied). 승인된 채널이 있는 회원만 연결할 수 있고, 채널 하나에 앱마다 연결 하나예요(다시 동의하면 예전 연결은 끝나요).
GET https://extv.co.kr/api/openapi/v1/oauth/authorize?response_type=code
&client_id={client_id}&redirect_uri={등록한 주소}&state={임의 값}
&scope=donation.read%20catalog.write받은 code(10분, 1회용)를 서버에서 토큰으로 바꿔요. 본문은 JSON 또는 form-urlencoded 둘 다 받아요.
POST https://extv.co.kr/api/openapi/v1/oauth/token
{ "grant_type": "authorization_code", "code": "exc_…", "client_id": "…", "client_secret": "…", "redirect_uri": "…" }
→ 200 { "access_token": "exa_…", "token_type": "Bearer", "expires_in": 3600,
"refresh_token": "exr_…", "scope": "donation.read catalog.write" }- access_token 은 60분, refresh_token 은 60일 —
{"grant_type":"refresh_token","refresh_token":"exr_…",client_id,client_secret}로 새로 받아요. - refresh 는 쓸 때마다 새로 발급되고 이전 것은 바로 무효예요. 받은 쌍으로 반드시 교체 저장하세요(이전 access_token 도 무효).
- 오류:
400 {"error":"invalid_grant"}= 연동 만료·해제(다시 동의 필요),401 invalid_client= 키 틀림,invalid_request= 형식 오류. - 해제:
POST /oauth/revoke{token, client_id, client_secret}— 항상 200. 방송자도 ‘방송하기 → 외부 연동’에서 끊을 수 있어요.
3. API (Authorization: Bearer {access_token})
| 요청 | 권한 | 내용 |
|---|---|---|
GET /me | - | 채널 정보 {apiVersion, channelId, handle, name, profileImage, isLive, broadcastId, exWon, scope} |
PUT /catalog | catalog.write | 시그니처·BJ 목록 전체 교체(아래 4장) |
GET /socket-info | donation.read | 실시간 소켓 주소 + 1회용 ticket(60초) {onAir, broadcastId, socketUrl, ticket, exWon} |
GET /donations?after={cursor}&limit= | donation.read | 놓친 후원 다시 받기 — {items:[…], hasMore}, limit 최대 100. 연결(동의)한 뒤의 후원만 |
POST /donations/{id}/ack | donation.read | 받아서 처리했다고 알림(선택, 여러 번 와도 됨) |
오류 응답은 {error, message} — 401 invalid_token(만료면 refresh 로 새로), 403 insufficient_scope, 429 요청이 너무 잦음.
4. 시그니처·BJ 목록 (PUT /catalog)
시청자가 ExTV 후원 창에서 고를 목록이에요. 받은 그대로 교체하니 항상 전체를 보내 주세요(바뀔 때마다, 몇 초 모아서).
{
"version": "2026-10-30T12:00:00Z",
"signatures": [
{ "id": "sig_1", "title": "두산아웃송", "amount": 20100, "imageUrl": "https://…" | null, "sort": 1 },
{ "id": "random_3000", "title": "랜덤시그", "amount": 3000, "isRandom": true }
],
"bjs": [ { "id": "b12", "name": "BJ 하나", "imageUrl": null, "sort": 1 } ],
"excelOn": true
}amount는 원 단위 — 1 EX = 1원이라 같은 숫자가 EX 로 보여요. 이미지가 없으면 기본 그림으로 보여요.isRandom항목을 고른 후원은signatureId없이 금액만 와요(랜덤 규칙은 연동 서비스 쪽).excelOn: false면 BJ 지정 칸이 숨겨져요.
5. 실시간 소켓
socketUrl 에 ?ticket=… 을 붙여 WebSocket 으로 연결해요(JSON 텍스트 1건씩). 같은 채널에 여러 개 붙어도 모두 같은 이벤트를 받아요 — 같은 후원을 두 번 처리하지 않게 id 로 거르세요.
→ { "type": "hello", "apiVersion": 1, "channelId": 31, "onAir": true, "broadcastId": 812, "exWon": 1 }
→ { "type": "ping" } // 약 5초마다 — {"type":"pong"} 또는 아무 메시지로 답
→ { "type": "donation",
"id": "exd_123", "cursor": 123, "at": "2026-10-30T21:03:11.000Z",
"channelId": 31, "broadcastId": 812,
"donor": { "id": "공개 id" | null, "nickname": "홍길동" },
"ex": 22200, "won": 22200, "exWon": 1,
"message": "화이팅", "signatureId": "sig_1" | null, "bjId": "b12" | null, "anonymous": false }- 금액 = ex × exWon 으로 계산하고
won과 맞춰 보세요. exWon(1 EX 가 몇 원인지)이 바뀌면 ExTV 가 연결된 소켓에 새 hello 를 먼저 보내요. - 30초 동안 아무 메시지가 없으면 서버가 끊어요. 끊기면
socket-info부터 다시(티켓은 1회용) — 붙은 뒤GET /donations?after=마지막 cursor로 놓친 후원을 먼저 받으세요. - 닫힘 코드
4001= 티켓 틀림·만료(새로 받기),4013= 연결 해제됨(다시 동의 전까지 재연결 금지). 모르는type은 무시하세요. - 후원 취소 이벤트는 없어요(EX 는 쓰기 전에만 환불돼요).
6. 지켜 주세요
- 후원자 닉네임·메시지는 방송 연출에만 쓰고 다른 목적으로 모으거나 넘기지 마세요.
- 요청은 1분에 1,200번(토큰 120번)까지 — 넘으면 429. /me 는 1분에 한 번이면 충분해요.
- 응답에 새 필드가 늘 수 있어요. 모르는 필드는 무시하세요(v1 안에서 기존 필드의 뜻은 바뀌지 않아요).