Uploads

Get a presigned URL for an email attachment

Step 1 of 3 for sending an attachment. Returns a short-lived presigned URL plus the key you pass back to the send endpoint.

The full flow is:

  1. POST /v1/upload/presign with the filename, MIME type and byte size.
  2. PUT the raw file bytes to the returned upload_url. The Content-Type header on that PUT must exactly match the content_type you presigned with — it is part of the signature, so any difference returns 403 from storage.
  3. POST /v1/email-users/{user_id}/inbox/send with attachments: [{key, filename, content_type}].

There is no base64 content field on the send endpoint; an attachment without a key is rejected. Keys are also scoped to your account, so a key that does not begin with attachments/{your_account_id}/ is refused.

Keys are single use. The stored file is deleted after a successful send, so sending the same document to several recipients means presigning and uploading once per send.

Allowed types: PDF, Word, Excel, PowerPoint, plain text, CSV, JPEG, PNG, GIF, WebP and ZIP. text/calendar is not accepted, so .ics calendar invites cannot be sent as attachments today.

post/v1/upload/presign

Request

  • Base URL: https://api.winnr.app
  • URL: https://api.winnr.app/v1/upload/presign
  • Auth: HTTP bearer

Request body

filenamestring required

Original file name. Certain executable extensions are rejected.

content_typestring required

MIME type. Must be on the allowed list above.

sizeinteger required

File size in bytes. Must be greater than 0 and at most 10485760 (10MB).

Example request

{
  "filename": "proposal.pdf",
  "content_type": "application/pdf",
  "size": 248192
}

Response

Presigned upload URL

Example response

{
  "data": {
    "key": "attachments/acct123/6f1e.../proposal.pdf",
    "expires_in": 300,
    "max_attachments": 3,
    "max_file_size": 10485760
  }
}

Changes

No recorded changes to this operation across all 1 revision of this API.