Back to Blog
Developers

Slack File Block: Post Remote and Uploaded Files in Block Kit

A Slack file block shows a file card inside a message. It takes source "remote" plus an external_id or file_id, and the file must exist first. We added remote files with files.remote.add, posted them in file blocks, and tried the mistakes, on 7 November 2026.

Slack Green Team
November 8, 2026
November 8, 2026
3 min read
Share:
slack
slack api
block kit

A Slack file block is a Block Kit block of "type": "file" that shows a file card inside a message. It does not upload anything. It points at a file Slack already knows about, so you first register the file with files.remote.add (a "remote file" that lives on your server) and then post a block with "source": "remote" and that file's external_id. On 7 November 2026 we did this with a bot token on a Free workspace, added a preview image, put three file blocks in one message, and sent the mistakes on purpose. The calls, the answers and a screenshot of the result are below.

Step 1: register the file with files.remote.add

The app needs the remote_files:write scope. This call registers a PDF that lives on another site:

curl -s https://slack.com/api/files.remote.add \
  -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  -d external_id=sg1107-report-1 \
  -d external_url=https://example.com/reports/q4.pdf \
  -d title="Q4 report (remote file)" \
  -d filetype=pdf

Slack answered ok: true with a file object: an ID starting with F, "mode": "external", "is_external": true, "size": 0 and our external_id. external_id is your own key for the file. You use it to update, share or remove the file later, so make it something you can look up.

Step 2: post it in a file block

{
  "channel": "C0123ABCD",
  "text": "Q4 report",
  "blocks": [
    { "type": "file", "source": "remote", "external_id": "sg1107-report-1" }
  ]
}

The post went through, and the block Slack stored had gained a file_id and the full file object. Using "file_id": "F0..." in place of external_id also worked.

Add a preview image

files.remote.add takes an optional preview_image, sent as a multipart upload. With one, the card shows the image under the file name. Without one, Slack shows only an icon and the file type. Here are both, plus an ordinary uploaded file, as three file blocks in one message:

A Slack message with three file cards: a remote PNG named Weekly signups dashboard with a green bar chart preview, a remote PDF named Q4 report with only a PDF icon, and an uploaded screenshot shown as an image
curl -s https://slack.com/api/files.remote.add \
  -H "Authorization: Bearer $SLACK_BOT_TOKEN" \
  -F external_id=sg1107-dash-2 \
  -F external_url=https://example.com/dashboards/signups \
  -F title="Weekly signups dashboard" \
  -F filetype=png \
  -F preview_image=@chart.png

Never appear "away" on Slack again

Cloud-based. No downloads. Works 24/7 even when your laptop is off.

Uploaded files work too

A file uploaded with the current two-step upload (files.getUploadURLExternal, then files.completeUploadExternal with no channel) can also go in a file block, but only with "source": "remote":

Block we sentResult
{"type":"file","source":"remote","file_id":"<uploaded file>"}Posted; the image showed as in the screenshot
{"type":"file","source":"local","file_id":"<uploaded file>"}must be a valid enum value [json-pointer:/blocks/0/source]
{"type":"file","source":"hosted","file_id":"<uploaded file>"}must be a valid enum value [json-pointer:/blocks/0/source]

So remote is the only value Slack accepts for source, whatever kind of file it is. If you are moving off the old upload call, our page on the files.upload retirement shows the two-step upload this relies on.

Errors we got

What we sentError
No sourcemissing required field: source [json-pointer:/blocks/0]
An external_id we never registeredfile not found [json-pointer:/blocks/0/file_id]
source set to local or hostedmust be a valid enum value [json-pointer:/blocks/0/source]

All three came back as invalid_blocks. Note the second one: the pointer says file_id even though we sent external_id, because Slack looks the file up first. Our guide to the invalid_blocks error has more of these.

File block or files.remote.share?

files.remote.share (scope remote_files:share) posts the remote file to a channel as its own message, with no text or other blocks around it. It answered ok, and files.remote.info then listed that message and our file-block message under the file's shares, so both count as places the file was shared. Use the file block when the file belongs inside a message you build, next to a section or a context block. For a plain image, an image block needs no file record at all.

FAQ

Can I upload a file inside the file block itself?

No. The block only references a file that exists. Upload or register it first, then post the block.

How do I remove a remote file?

Call files.remote.remove with the same external_id. It answered ok: true for our test file.

Does the file block open the file in Slack?

For a remote file, Slack set the file's url_private to the external_url we registered, so the card leads to your server, where the file stays.

Always Active

Stop Jiggling Your Mouse.

Join hundreds of remote workers who never worry about their Slack status. Set it up once, stay green forever.

Related Articles

Developers

Slack Video Block: Which URLs Work, Tested With Real Errors

A Block Kit video block needs video_url, thumbnail_url, title and alt_text, and its video_url must be an embeddable player URL on a domain your app claims. We made 26 posts with a bot token on 7 November 2026; a YouTube /embed/ URL worked with no setup, and every other host needed claimed unfurl domains plus a reinstall.

Slack Green Team
Developers

ngrok for a Slack Bot: What It Needs, and Two Free Alternatives Tested

A Slack bot on localhost needs a public HTTPS URL for events and slash commands, or Socket Mode. We tried ngrok 3.39.13 with no account (ERR_NGROK_4018), a Cloudflare quick tunnel and Socket Mode on 8 November 2026, timed the replies, and broke the tunnel URL on purpose.

Slack Green Team
Developers

Slack Java SDK: Post, Read History and Run a Bolt App (Tested 1.54.0)

The Slack Java SDK is com.slack.api:slack-api-client for Web API calls and com.slack.api:bolt for apps. We ran version 1.54.0 with Gradle on 8 November 2026: chat.postMessage, conversations.history with a cursor, a Socket Mode Bolt app and a Kotlin Block Kit post, plus the silent failure in ctx.say.

Slack Green Team