Files

Sending a file takes two steps: upload it, then post a message that attaches it. Reading one is a single download call. Both work with personal tokens and app tokens.

Step Operation Scope
Upload POST /v1/orgs/{orgId}/files files:write
Attach POST /v1/channels/{channelId}/messages with attachment_ids messages:write
Download GET /v1/attachments/{attachmentId}/content messages:read

Upload a file

Send multipart/form-data with one part named file. Missived keeps the part's file name and content type.

curl -X POST https://api.missived.com/v1/orgs/<orgId>/files \
  -H "Authorization: Bearer $MISSIVED_TOKEN" \
  -F "[email protected];type=text/plain"

The answer is 201 with the stored file:

{
  "id": "…",
  "file_name": "build.log",
  "content_type": "text/plain",
  "size": 18234,
  "created_at": "2026-10-18T09:12:00.000Z",
  "download_url": "https://api.missived.com/v1/attachments/…/content"
}

The file is now pending: stored, but not in any channel yet.

Attach it to a message

Post a message with the upload's id in attachment_ids:

curl -X POST https://api.missived.com/v1/channels/<channelId>/messages \
  -H "Authorization: Bearer $MISSIVED_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: build-1234-log" \
  -d '{"content": "Build 1234 log", "attachment_ids": ["<fileId>"]}'

Download an attachment

Messages list their files in attachments. Each one has:

Field What it is
id, file_name, content_type, size The file. size is in bytes.
download_url The full URL of /v1/attachments/{id}/content, fetched with your own token. Apps download this way.
url A short-lived link signed for the person the token acts as (relative to the API host). null for apps.

Fetch the bytes with your token:

curl -L -o build.log \
  -H "Authorization: Bearer $MISSIVED_TOKEN" \
  https://api.missived.com/v1/attachments/<attachmentId>/content

The answer is the file, decrypted, with Content-Disposition: attachment and the file's name.

Who may download it:

With the TypeScript SDK

The @missived/bot SDK has helpers for both steps:

import { RestClient } from '@missived/bot';

const rest = new RestClient({ token: process.env.MISSIVED_TOKEN! });

// Upload, then attach.
const file = await rest.uploadFile('<orgId>', { name: 'build.log', type: 'text/plain', data: logBytes });
await rest.createMessage('<channelId>', { content: 'Build log', attachment_ids: [file.id] });

// Download a message's first attachment.
const { data, fileName, contentType } = await rest.downloadAttachment(message.attachments[0].id);

data accepts a Blob, an ArrayBuffer or a Uint8Array. downloadAttachment returns the bytes as a Uint8Array, with the content type and the file name from the response.