Slack API 파일 업로드: files.upload 대신 세 번 호출

files.upload 지원 중단 뒤에는 files.getUploadURLExternal, upload_url에 바이트 POST, channel_id와 files.completeUploadExternal 순입니다.

읽는 시간 5분Sume
전체 글

Slack API로 파일을 업로드하려면 세 번 호출하세요. 파일의 filename과 바이트 단위 length로 files.getUploadURLExternal을 호출하고, 반환된 upload_url로 원본 바이트를 POST한 뒤, 반환된 파일 ID와 파일을 공유할 채널의 channel_id로 files.completeUploadExternal을 호출하면 그 채널에 파일이 공유됩니다. 호출 한 번으로 끝나던 예전 files.upload는 지원 중단(deprecated)되었습니다. Slack 레퍼런스 페이지에는 이 메서드가 November 12, 2025에 동작을 멈추고 종료(sunset)된다고 나와 있습니다.

Slack 관련 내용은 files.upload, files.getUploadURLExternal, files.completeUploadExternal, Working with files 페이지에서, Sume 관련 내용은 Run 웹훅 (영문)과 실행과 결과 (영문)에서 가져왔습니다. 모두 2026-09-28에 확인했습니다. Sume에는 Slack 앱이나 커넥터가 없습니다. 완성된 영상에 대한 Sume 웹훅은 여러분의 서버가 받고, Slack 호출도 그 서버가 합니다. 링크만으로 충분하다면, Slack 영상 생성 봇은 업로드 대신 URL을 게시하는 방식입니다.

files.upload는 지원 중단되었나요?

네. Slack 변경 로그에 따르면 May 16, 2024부터 새로 만든 앱은 files.upload를 호출할 수 없고, 이를 대체하는 두 메서드는 "more reliable, especially when uploading large files."(특히 큰 파일을 업로드할 때 더 안정적)라고 합니다. files.upload 레퍼런스 페이지에는 이 변경 로그를 가리키는 method_deprecated 오류가 나와 있습니다.

Slack SDK는 새 절차를 호출 하나로 감싸 줍니다. Node용 @slack/web-api 패키지에서는 uploadV2, python-slack-sdk에서는 files_upload_v2, Java SDK에서는 FilesUploadV2Request입니다. SDK 없이 하면 이 절차는 HTTP 요청 세 번입니다.

API로 채널에 파일을 어떻게 업로드하나요?

Web API 호출 두 번은 Authorization 헤더에 토큰을 담아 보내세요. 가운데 요청은 Slack이 알려 준 URL로 보냅니다.

  • files.completeUploadExternal은 정확히 한 번 호출하세요. 이 메서드를 끝내 호출하지 않으면 Slack은 그 업로드를 버리며, 호출하기 전에 Slack이 파일 처리를 마칠 때까지 기다릴 필요는 없습니다.
  • 두 Web API 메서드 모두 폼 인코딩된 본문을 받습니다. Slack의 예제는 files를 폼 안에 JSON 문자열로 넣어 보내고, 바이트는 application/octet-stream으로 보냅니다.
Slack의 files.getUploadURLExternal과 files.completeUploadExternal 레퍼런스 기준, 2026-09-28 확인.
단계보내는 것돌려받는 것
1. files.getUploadURLExternalfilename, 그리고 파일의 바이트 크기인 lengthupload_url과 file_id
2. upload_url로 POST원본 바이트 또는 multipart 폼으로 보낸 파일성공하면 HTTP 200, 그 밖의 상태는 모두 실패
3. files.completeUploadExternal파일 ID 배열인 files(제목은 선택), 그리고 channel_id와 선택 항목인 initial_comment공유된 파일 객체. channel_id가 없으면 파일은 비공개로 남음
// Node 18+. SLACK_BOT_TOKEN needs the files:write scope.
async function slack(method, params) {
  const res = await fetch(`https://slack.com/api/${method}`, {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.SLACK_BOT_TOKEN}` },
    body: new URLSearchParams(params), // form-encoded
  });
  const json = await res.json();
  if (!json.ok) throw new Error(`${method}: ${json.error}`);
  return json;
}

async function uploadToChannel(fileUrl, filename, channelId) {
  const src = await fetch(fileUrl); // a public media.sume.com URL
  if (!src.ok) throw new Error(`download answered ${src.status}`);
  const bytes = Buffer.from(await src.arrayBuffer());
  const { upload_url, file_id } = await slack("files.getUploadURLExternal", {
    filename, length: String(bytes.length), // exact size in bytes
  });
  const sent = await fetch(upload_url, { method: "POST", body: bytes,
    headers: { "Content-Type": "application/octet-stream" } });
  if (sent.status !== 200) throw new Error(`upload_url answered ${sent.status}`);
  await slack("files.completeUploadExternal", {
    files: JSON.stringify([{ id: file_id, title: filename }]),
    channel_id: channelId, initial_comment: "Your video is ready",
  });
}

어떤 스코프와 한도가 적용되나요?

  • 새 메서드 두 개 모두 봇 토큰이나 사용자 토큰에 files:write 스코프가 필요하며, Slack은 두 메서드를 Tier 4(분당 100회 이상 호출)로 분류합니다.
  • 봇이 채널 멤버여야 합니다. 그렇지 않으면 files.completeUploadExternal이 not_in_channel로 응답합니다.
  • Slack 도움말 센터에 따르면 최대 1GB 크기의 파일을 추가할 수 있습니다. 이 페이지는 Slack 안에서 직접 파일을 추가하는 경우를 다루며, 두 메서드 레퍼런스에는 일반적인 파일 크기 상한이 나와 있지 않습니다. 워크스페이스가 큰 파일 업로드를 제한할 수도 있으며, 이때 files.getUploadURLExternal은 file_upload_size_restricted를 반환합니다.
  • length가 0이면 missing_argument로 거부되므로, 실제로 가진 바이트 수를 재서 넣으세요.

백엔드에서 생성한 영상은 어떻게 게시하나요?

완성된 영상의 웹훅을 받는 서버에서 업로드하고, 브라우저에서는 절대 업로드하지 마세요. 그래야 Slack 토큰과 Sume API 키가 모두 서버에만 남습니다. Sume Format 실행이라면 흐름은 다음과 같습니다.

  • 실행이 완료되거나 실패하면 Sume는 여러분의 communication.webhook_url로 서명된 POST를 한 번 보냅니다. 원본 본문에 대한 HMAC-SHA256 서명을 검증하고, 이벤트를 기록하고, 10초 시도 시간 안에 2xx로 응답하세요. 검증 방법은 Sume 영상 실행용 서명된 웹훅에서 다룹니다. 느린 엔드포인트는 재시도를 받으므로 업로드는 응답한 다음에 하세요.
  • 봉투의 request_id로 중복을 제거하세요. 이 값은 재시도마다 같으므로, 재시도된 전달이 영상을 두 번 게시하지 않습니다.
  • 보여 줄 결과물 하나인 payload.primary_output_url이나, url, content_type, size_bytes가 담긴 payload.artifacts[] 항목을 가져오세요. 이 media.sume.com URL은 내구성 있고 URL을 가진 누구에게나 공개되므로, 다운로드에 API 키가 필요 없습니다.
  • Slack URL을 Sume의 webhook_url로 등록하지 마세요. Sume의 POST에는 Slack 메시지가 아니라 Sume 자체의 실행 영수증이 담깁니다.

출처

관련 글

연동 카테고리의 다른 글

연동 글 전체 보기

작성자 Sume