Upload a file
Stores a file in the workspace, the way the Upload button on the Files page does. The body is the file itself, not JSON and not multipart, with its type in `Content-Type`.
Runs the real call against your workspace, with your own key.
POST /files
Stores a file in the workspace, the way the Upload button on the Files page does. The body is the file itself, not JSON and not multipart, with its type in Content-Type.
Example
Needs threads:write. Name the file with the filename query parameter, or with an X-Filename header, URI-encoded. The answer is a 201 with the file, and its id can be attached to a send as { fileId }.
curl -X POST "$OE/files?filename=price-list.pdf" -H "$AUTH" -H 'content-type: application/pdf' --data-binary @price-list.pdf{ "object": "file", "id": "file_0c4e7a91d2b84f63a5e19b7d", "filename": "price-list.pdf", "mimeType": "application/pdf", "sizeBytes": 248112, "direction": "uploaded", "threadId": null, "messageId": null, "deliveredTo": null, "usage": null, "deletable": true, "createdAt": "2026-09-24T09:12:40.000Z"}A name is cleaned rather than refused: characters a file name cannot hold become _, and a name longer than 255 characters is cut, keeping its extension. A Content-Type that is not a MIME type is stored as application/octet-stream.
No name is a 400 upload_no_name, a program or a script a 400 upload_dangerous, an empty body a 400 upload_empty, and a file over 100 MB a 413 upload_too_large.
A workspace takes 500 uploads an hour, deleted ones included, and holds 10 GB of uploads at a time. Past those the answer is a 429 upload_rate_limited or a 507 upload_storage_full. A 502 upload_failed means storage failed, and is worth retrying.
A key that reaches every address uploads to the whole workspace, with deliveredTo null. A key limited to particular addresses or domains uploads to the first address it holds, and one that holds none is a 403 upload_no_address.