Upload File to Slack
Upload files to Slack channels using the three-step upload process
Source Code
import fs from 'fs';
import path from 'path';
/**
* Upload a file to a Slack channel using the three-step upload process
* @param {string} channelId - The channel ID to upload to (e.g., 'C09R5QUC527')
* @param {string} filePath - Path to the file to upload
* @param {string} slackToken - Slack API token
* @param {Object} options - Optional parameters
* @param {string} options.title - Title for the file
* @param {string} options.initialComment - Optional comment to add with the file
* @returns {Promise<Object>} Upload result with file ID, name, and permalink
*/
async function uploadFileToSlack(channelId, filePath, slackToken, options = {}) {
// Read the file
const fileBuffer = fs.readFileSync(filePath);
const fileName = path.basename(filePath);
const fileSize = fileBuffer.length;
// Step 1: Get upload URL from Slack
const uploadUrlFormData = new FormData();
uploadUrlFormData.append('filename', fileName);
uploadUrlFormData.append('length', fileSize.toString());
const uploadUrlResponse = await fetch('https://slack.com/api/files.getUploadURLExternal', {
method: 'POST',
headers: {
'Authorization': `Bearer ${slackToken}`
},
body: uploadUrlFormData
});
const uploadUrlData = await uploadUrlResponse.json();
if (!uploadUrlData.ok) {
throw new Error(`Failed to get upload URL: ${uploadUrlData.error}`);
}
const { upload_url, file_id } = uploadUrlData;
// Step 2: Upload file contents to the provided URL
const uploadResponse = await fetch(upload_url, {
method: 'POST',
headers: {
'Content-Type': 'application/octet-stream'
},
body: fileBuffer
});
if (!uploadResponse.ok) {
throw new Error(`Failed to upload file contents: ${uploadResponse.statusText}`);
}
// Step 3: Complete the upload and share to channel
const completeFormData = new FormData();
const fileData = {
id: file_id
};
if (options.title) {
fileData.title = options.title;
}
completeFormData.append('files', JSON.stringify([fileData]));
completeFormData.append('channel_id', channelId);
if (options.initialComment) {
completeFormData.append('initial_comment', options.initialComment);
}
const completeResponse = await fetch('https://slack.com/api/files.completeUploadExternal', {
method: 'POST',
headers: {
'Authorization': `Bearer ${slackToken}`
},
body: completeFormData
});
const completeData = await completeResponse.json();
if (!completeData.ok) {
throw new Error(`Failed to complete upload: ${completeData.error}`);
}
const uploadedFile = completeData.files?.[0];
console.log(`[DEBUG] Successfully uploaded file: ${uploadedFile?.name} (ID: ${uploadedFile?.id})`);
return {
success: true,
fileId: uploadedFile?.id,
fileName: uploadedFile?.name,
permalink: uploadedFile?.permalink
};
}
export { uploadFileToSlack };
/**
* Run this script directly from the command line:
* bun send_file.js <channelId> <filePath> <slackToken> [title] [initialComment]
*
* Example:
* bun send_file.js C09R5QUC527 ./document.pdf xoxb-your-token "My Document" "Here is the file"
*/
if (import.meta.main) {
const args = process.argv.slice(2);
if (args.length < 3) {
console.error('Usage: bun send_file.js <channelId> <filePath> <slackToken> [title] [initialComment]');
console.error('Example: bun send_file.js C09R5QUC527 ./document.pdf xoxb-your-token "My Document" "Here is the file"');
process.exit(1);
}
const [channelId, filePath, slackToken, title, initialComment] = args;
const options = {};
if (title) options.title = title;
if (initialComment) options.initialComment = initialComment;
uploadFileToSlack(channelId, filePath, slackToken, options)
.then(result => {
console.log('Upload successful!');
console.log(`File ID: ${result.fileId}`);
console.log(`File Name: ${result.fileName}`);
console.log(`Permalink: ${result.permalink}`);
})
.catch(error => {
console.error('Upload failed:', error.message);
process.exit(1);
});
}