본문으로 건너뛰기

채팅 보내기

봇 계정 이름으로 방송에 채팅을 보내요. 스푼 앱 채팅창에 봇 계정의 닉네임으로 보여요.

메서드 · 경로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설명
messagestring아니오보낼 채팅 본문이에요. 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 을 확인하면 실패를 미리 피할 수 있어요.

스트림에 연결하지 않아도 보낼 수 있어요. 방에 들어가 있지 않으면 서버가 먼저 입장시켜요.

에러​

HTTPdetailCode무슨 일인가요어떻게 하나요
400OAPI_MNGR_0103요청이 잘못됐어요. 본문이 깨졌거나, 필수 필드·Content-Type 이 빠졌거나, 메서드가 잘못됐어요.요청 형식을 고쳐요. 같은 요청을 다시 보내도 결과가 같아요.
400OAPI_MNGR_0108message 가 비어 있거나 공백뿐이에요.보낼 내용을 확인해요.
400OAPI_MNGR_0109200자를 넘었어요.길이를 줄여요.
401없음토큰이 없거나 무효해요.DJ 에게 재연동을 안내해요.
403없음chat.send 권한이 없어요.권한을 추가해 재동의를 받아요.
403OAPI_MNGR_0208채팅이 얼었거나 봇이 채팅 금지 상태예요.두 경우가 구분되지 않아요. 잠시 뒤 재시도하고, 계속 막히면 DJ 에게 안내해요.
403OAPI_MNGR_0209방송에 입장할 수 없어요. DJ 가 봇을 차단했을 수 있어요.재시도로 안 풀려요. DJ 가 풀어줘야 해요.
404OAPI_MNGR_0301방송 중이 아니에요.방송이 시작될 때까지 기다려요.
429OAPI_MNGR_0302채팅 전송이 너무 잦아요.잠시 기다렸다 다시 보내요.
502OAPI_MNGR_2302방송 서버 오류예요. 전송 전 방송 확인·입장 단계에서 나요.백오프 후 재시도해요.
502OAPI_MNGR_2303채팅 서버 오류예요.백오프 후 재시도해요.

429 는 두 가지예요. 위 OAPI_MNGR_0302(채팅 전송 한도)는 본문이 있지만, API 호출 한도로 걸리면 본문도 detailCode 도 없어요. 본문을 파싱하기 전에 상태 코드로 먼저 갈라야 터지지 않아요 — 위 예제가 그렇게 짜여 있어요.

이 표에 없는 상태도 올 수 있어요. 잘못된 메서드·Content-Type(400 · 405 · 415, OAPI_MNGR_0103) · 호출 한도(429, 본문 없음) · 서버 오류(500, OAPI_MNGR_1002)는 모든 엔드포인트에 공통이에요 — 에러 코드에 있어요.

관련 문서​