채팅 보내기
봇 계정 이름으로 방송에 채팅을 보내요. 스푼 앱 채팅창에 봇 계정의 닉네임으로 보여요.
| 메서드 · 경로 | POST /v1/live/chat |
| 필요한 권한 | chat.send |
| 성공 응답 | 204 (본문 없음) |
| 방송 중이 아닐 때 | 404 (OAPI_MNGR_0301) |
export SPOON_BASE_URL="https://kr-openapi.spooncast.net"
export SPOON_ACCESS_TOKEN="{발급받은 access token}"
일본 지역이면 https://jp-openapi.spooncast.net 이에요 — 지역별 주소.
요청
POST /v1/live/chat
헤더
| 이름 | 필수 | 설명 |
|---|---|---|
Authorization | ✔ | Bearer {access_token} 형식이에요. |
Content-Type | ✔ | application/json 이에요. |
요청 바디
{
"message": "안녕하세요! 봇이 인사드려요"
}
| 필드 | 타입 | null | 설명 |
|---|---|---|---|
message | string | 아니오 | 보낼 채팅 본문이에요. 200자까지예요. 비어 있거나 공백뿐이면 400 이에요. |
어느 방송에 보낼지는 토큰이 정해요. 경로에도 본문에도 방송을 지목하는 값이 없어요.
요청 예시
curl -i -X POST "$SPOON_BASE_URL/v1/live/chat" \
-H "Authorization: Bearer $SPOON_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"message":"안녕하세요! 봇이 인사드려요"}'
응답
성공하면 본문 없이 204 예요. 파싱할 것이 없으니 상태 코드만 보세요.
HTTP/2 204
코드
// send.ts — node --experimental-strip-types send.ts "보낼 메시지"
interface ApiError {
detailCode: string;
message: string;
}
const res = await fetch(`${process.env.SPOON_BASE_URL}/v1/live/chat`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SPOON_ACCESS_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ message: process.argv[2] }),
});
if (res.status === 204) {
console.log('보냈어요.');
} else if (res.status === 404) {
console.log('방송 중이 아니에요.');
} else if (res.status === 429) {
console.log('지금은 채팅이 몰려요. 잠시 뒤 다시 보내요.');
} else if (res.status === 401) {
console.error('연동이 끊겼어요. DJ 에게 재연동을 안내해요.');
} else {
// 권한 부족 403 은 앞단에서 막혀 detailCode 가 없어요
const { detailCode, message } = (await res.json()) as Partial<ApiError>;
console.error(`전송 실패 ${res.status} ${detailCode ?? '권한 부족'}: ${message ?? ''}`);
}
node --experimental-strip-types send.ts "안녕하세요"
주의
보낸 메시지는 내 스트림으로 돌아오지 않아요. 이벤트 스트림은 봇 자신의 발화를 그 봇에게 돌려주지 않아요. 자기 인사말을 명령으로 다시 실행하는 사고를 막기 위해서예요. 같은 방송의 다른 봇 발화는 보여요.
200자를 넘으면 400 이에요. 글자 수는 UTF-16 code unit 기준이라 이모지 하나가 2자로
세어질 수 있어요.
429 는 봇이 과하게 보냈을 때만 오는 게 아니에요. 전송 한도를 방송 전체가 나눠 쓰기
때문에, 청취자들이 활발히 떠들면 봇이 아무것도 안 해도 걸려요. 봇 속도를 줄여도 바로
풀리지 않으니 잠시 기다렸다 다시 보내요.
DJ 가 막으면 봇도 막혀요. 채팅을 얼리거나(isChatFrozen) 봇을 채팅 금지하면 403 이고,
강퇴하면 입장 자체가 안 돼요. 발화 전에
현재 방송 조회 로 isChatFrozen 을 확인하면 실패를 미리 피할 수 있어요.
스트림에 연결하지 않아도 보낼 수 있어요. 방에 들어가 있지 않으면 서버가 먼저 입장시켜요.
에러
| HTTP | detailCode | 무슨 일인가요 | 어떻게 하나요 |
|---|---|---|---|
400 | OAPI_MNGR_0103 | 요청이 잘못됐어요. 본문이 깨졌거나, 필수 필드·Content-Type 이 빠졌거나, 메서드가 잘못됐어요. | 요청 형식을 고쳐요. 같은 요청을 다시 보내도 결과가 같아요. |
400 | OAPI_MNGR_0108 | message 가 비어 있거나 공백뿐이에요. | 보낼 내용을 확인해요. |
400 | OAPI_MNGR_0109 | 200자를 넘었어요. | 길이를 줄여요. |
401 | 없음 | 토큰이 없거나 무효해요. | DJ 에게 재연동을 안내해요. |
403 | 없음 | chat.send 권한이 없어요. | 권한을 추가해 재동의를 받아요. |
403 | OAPI_MNGR_0208 | 채팅이 얼었거나 봇이 채팅 금지 상태예요. | 두 경우가 구분되지 않아요. 잠시 뒤 재시도하고, 계속 막히면 DJ 에게 안내해요. |
403 | OAPI_MNGR_0209 | 방송에 입장할 수 없어요. DJ 가 봇을 차단했을 수 있어요. | 재시도로 안 풀려요. DJ 가 풀어줘야 해요. |
404 | OAPI_MNGR_0301 | 방송 중이 아니에요. | 방송이 시작될 때까지 기다려요. |
429 | OAPI_MNGR_0302 | 채팅 전송이 너무 잦아요. | 잠시 기다렸다 다시 보내요. |
502 | OAPI_MNGR_2302 | 방송 서버 오류예요. 전송 전 방송 확인·입장 단계에서 나요. | 백오프 후 재시도해요. |
502 | OAPI_MNGR_2303 | 채팅 서버 오류예요. | 백오프 후 재시도해요. |
429 는 두 가지예요. 위 OAPI_MNGR_0302(채팅 전송 한도)는 본문이 있지만, API 호출
한도로 걸리면 본문도 detailCode 도 없어요. 본문을 파싱하기 전에 상태 코드로 먼저
갈라야 터지지 않아요 — 위 예제가 그렇게 짜여 있어요.
이 표에 없는 상태도 올 수 있어요. 잘못된 메서드·Content-Type(400 · 405 · 415,
OAPI_MNGR_0103) · 호출 한도(429, 본문 없음) · 서버 오류(500, OAPI_MNGR_1002)는
모든 엔드포인트에 공통이에요 — 에러 코드에 있어요.