Skip to content

Uploads

Upload a file attachment that can then be referenced in a thread or comment.

Upload File

POST /api/v1/upload

Uploads a file to Pulse storage. Returns an attachment record with a URL that can be passed as an attachmentId when creating threads or comments.

Authentication

This endpoint uses publishable key + user JWT (the same credentials as the WebSocket connection), not the secret key. It is intended to be called from the browser via the Client SDK. For server-side usage, pass the user's JWT and publishable key directly.

X-Pulse-Key: pk_your_publishable_key
X-Pulse-Token: <user JWT>

Request

Content-Type: multipart/form-data

FieldTypeRequiredDescription
fileFileYesThe file to upload
bash
curl -X POST https://pulse.hire.rest/api/v1/upload \
  -H "X-Pulse-Key: pk_your_publishable_key" \
  -H "X-Pulse-Token: eyJhbGci..." \
  -F "file=@/path/to/image.png"

Response 200

json
{
  "id": "a1b2c3d4-...",
  "type": "image",
  "filename": "image.png",
  "mimeType": "image/png",
  "sizeBytes": 204800,
  "url": "https://pulse.hire.rest/files/env_abc/a1b2c3d4-...",
  "thumbnailUrl": "https://pulse.hire.rest/files/env_abc/a1b2c3d4-...?thumb=1",
  "width": 1920,
  "height": 1080
}
FieldTypeDescription
idstringAttachment ID — pass this as an attachmentId
type"image" | "audio" | "video"Detected media type
filenamestringOriginal filename
mimeTypestringMIME type of the file
sizeBytesnumberFile size in bytes
urlstringDirect URL to serve the file
thumbnailUrlstring?Thumbnail URL (images only, 200×200 JPEG)
durationMsnumber?Duration in milliseconds (audio/video)
widthnumber?Width in pixels (images only)
heightnumber?Height in pixels (images only)

Supported MIME Types

TypeMIME Types
imageimage/jpeg, image/png, image/gif, image/webp
audioaudio/webm, audio/ogg, audio/mp4, audio/mpeg, audio/wav
videovideo/webm, video/mp4

Error Responses

StatusCondition
400No file provided, or unsupported MIME type
401Missing or invalid X-Pulse-Key / X-Pulse-Token
403The media type is disabled for this environment (see Environment Config)
413File exceeds maxFileSizeMb for this environment (default 10 MB)
json
{ "error": "Image uploads are disabled for this environment" }
{ "error": "File too large (max 10MB)" }

Serving Files

Files are served at:

GET /files/:envId/:fileId

This endpoint requires the same authentication as the upload endpoint (X-Pulse-Key and X-Pulse-Token headers). The authenticated environment must match the :envId in the URL.

Query parameters:

  • thumb=1 — Returns a thumbnail version (JPEG, 200x200)

Response headers include Cache-Control: public, max-age=31536000, immutable.

Error Responses

StatusCondition
403Authenticated environment does not match the requested :envId
404File not found

Using Attachment IDs

After uploading, pass the returned id when creating a thread or comment so the attachment is linked to that content:

typescript
// Upload first
const attachment = await client.uploadFile(file);

// Then create a thread with the attachment
client.createThread('Check out this screenshot', {
  attachmentIds: [attachment.id],
});

// Or reply with an attachment
client.reply('thread-id', 'Here is the updated version', [], [attachment.id]);

Widget handles this automatically

When using <pulse-widget>, file selection, upload, and attachment linking all happen automatically. You only need this API if you're building a custom comment UI.

Pulse Collaboration SDK