팬 랭킹 조회
지금 방에 있는 청취자들의, 이 방송 후원 랭킹 상위 30명이에요. 방송이 끝나면 초기화돼요.
| 메서드 · 경로 | GET /v1/live/fans |
| 필요한 권한 | fans.read |
| 성공 응답 | 200 |
| 방송 중이 아닐 때 | 404 (OAPI_MNGR_0301) |
export SPOON_BASE_URL="https://kr-openapi.spooncast.net"
export SPOON_ACCESS_TOKEN="{발급받은 access token}"
일본 지역이면 https://jp-openapi.spooncast.net 이에요 — 지역별 주소.
요청
GET /v1/live/fans
헤더
| 이름 | 필수 | 설명 |
|---|---|---|
Authorization | ✔ | Bearer {access_token} 형식이에요. |
경로 파라미터 · 쿼리 파라미터 · 요청 바디가 없어요. 페이징도 없어요 — 상위 30명이 한 번에 와요.
요청 예시
curl -H "Authorization: Bearer $SPOON_ACCESS_TOKEN" "$SPOON_BASE_URL/v1/live/fans"
응답
{
"totalCount": 2,
"fans": [
{ "id": "Ab1Cd2Ef3Gh4Ij5Kl6Mn7O", "nickname": "스푼청취자", "rank": 1, "spoonCount": 1200 },
{ "id": "Pq8Rs9Tu0Vw1Xy2Za3Bc4D", "nickname": "라디오팬", "rank": 2, "spoonCount": 300 }
]
}
| 필드 | 타입 | null | 설명 |
|---|---|---|---|
totalCount | number | 아니오 | 돌려준 목록의 크기예요. 최대 30이고, 전체 팬 수가 아니에요. |
fans | object[] | 아니오 | 누적 후원이 많은 순이에요. |
fans[].id | string | 아니오 | 청취자를 가리키는 값이에요. 암호화한 값이에요. |
fans[].nickname | string | 아니오 | 닉네임이에요. |
fans[].rank | number | 아니오 | 순위예요. 1부터 시작해요. |
fans[].spoonCount | number | 예 | 이 방송에서 그 청취자가 쓴 누적 스푼이에요. 값이 없을 수 있으니 null 을 처리해요. |
id 로 사람을 식별해요id 는 이 사람의 고유 식별자예요. 같은 사람이면 항상 같은 값이라 출석 · 누적 · 랭킹의 키로
쓰면 돼요. nickname 은 바뀌고 중복될 수 있으니 식별에 쓰지 마세요.
값의 범위는 내 봇과 그 DJ 조합이에요. DJ 가 연동을 끊었다 다시 동의해도 유지돼요.
코드
// fans.ts — node --experimental-strip-types fans.ts
interface Fan {
id: string;
nickname: string;
rank: number;
spoonCount: number | null;
}
interface Fans {
totalCount: number;
fans: Fan[];
}
const res = await fetch(`${process.env.SPOON_BASE_URL}/v1/live/fans`, {
headers: { Authorization: `Bearer ${process.env.SPOON_ACCESS_TOKEN}` },
});
if (!res.ok) throw new Error(`팬 랭킹 조회 실패: ${res.status}`);
const { totalCount, fans } = (await res.json()) as Fans;
console.log(`랭킹에 오른 ${totalCount}명 (최대 30)`);
for (const fan of fans.slice(0, 3)) {
const spoons = fan.spoonCount ?? 0; // null 이 올 수 있어요
console.log(`${fan.rank}위 ${fan.nickname} — ${spoons} 스푼`);
}
const top = fans.find((f) => f.rank === 1);
if (top) console.log(`오늘의 1등은 ${top.nickname} 님, ${top.spoonCount ?? 0} 스푼이에요!`);
node --experimental-strip-types fans.ts
주의
봇 계정도 이 방송에 후원 이력이 있으면 랭킹에 올라요. 봇의 id 를 걸러내야 할 수 있어요.
상위 30명까지만 와요. 페이징이 없어요 — 31등부터는 랭킹의 의미가 없어서 애초에 주지 않아요.
totalCount 도 전체 팬 수가 아니라 돌려준 목록의 크기(최대 30) 예요. 전체 청취자가 필요하면
청취자 목록 조회 를 쓰세요. 그쪽은 지금 방에 있는 사람 전부라 커서로 나눠 받아요.
지금 방에 있는 사람만 보여요. 후원하고 나간 사람은 랭킹에서 빠지고, 사람이 드나들 때마다 순위가 바뀌어요. 방송 내내의 누적이 필요하면 이벤트 스트림의 후원 이벤트로 직접 쌓아요.
랭킹은 이 방송 안에서의 누적이에요. DJ 의 전체 팬 순위가 아니에요.
입장 시점의 순위는 이벤트 스트림의 fanRank 로도 와요.
"1위 팬 입장!" 같은 인사를 만들 때는 이 API 를 따로 부르지 않아도 돼요.
에러
| HTTP | detailCode | 무슨 일인가요 | 어떻게 하나요 |
|---|---|---|---|
401 | 없음 | 토큰이 없거나 무효해요. | DJ 에게 재연동을 안내해요. |
403 | 없음 | fans.read 권한이 없어요. | 권한을 추가해 재동의를 받아요. |
404 | OAPI_MNGR_0301 | 방송 중이 아니에요. | 오류가 아니라 상태예요. 잠시 뒤 다시 불러요. |
502 | OAPI_MNGR_2302 | 방송 서버 오류예요. | 백오프 후 재시도해요. |
이 표에 없는 상태도 올 수 있어요. 잘못된 메서드·Content-Type(400 · 405 · 415,
OAPI_MNGR_0103) · 호출 한도(429, 본문 없음) · 서버 오류(500, OAPI_MNGR_1002)는
모든 엔드포인트에 공통이에요 — 에러 코드에 있어요.