Uploading Files
Use POST /v3/Files to upload a file and attach it to a client record or work item. Every upload must be linked to exactly one entity at the time of upload — there is no way to attach a file to multiple records in a single request.
Overview
/v3/Files is the only Karbon endpoint that does not accept JSON. Instead, it takes a multipart/form-data body: the binary file as one part, plus a single form field naming the target record. On success it returns the created file’s identifier and metadata.
Authentication uses the same Authorization and AccessKey headers as every other endpoint — see the Authentication guide if you don’t have these set up yet.
POST https://api.karbonhq.com/v3/Files
Authorization: Bearer {token}
AccessKey: {key}
Content-Type: multipart/form-data
Supported file types
The endpoint accepts most everyday document and media formats — PDFs, plain text, CSV, Word and Excel files, images, and similar. Executables, scripts, raw HTML and a handful of other unsafe formats are rejected. If you need to upload a file in a blocked format, add it to a .zip archive and upload that instead.
Request body
| Form field | Type | Required | Notes |
|---|---|---|---|
file | binary | yes | The file to upload, attached as a multipart file part. |
contact_keys | string | * | A single Contact key. |
organization_keys | string | * | A single Organization key. |
client_group_keys | string | * | A single Client Group key. |
workitem_keys | string | * | A single Work Item key. |
integration_task_key | string | * | A single Integration Task key. |
* Exactly one link field must be supplied. Despite the plural names, each link field accepts only one key.
Filename and MIME type
You do not need to send the filename or MIME type as separate form fields. Karbon reads both from the file part itself:
- Filename — the
filename="…"parameter on the file part’sContent-Dispositionheader (set automatically by every standard HTTP client when you attach a file from disk). - MIME type — the file part’s own
Content-Typeheader. If absent, Karbon infers the MIME type from the filename extension; if that also fails, the file is stored asapplication/octet-stream.
Example
curl -X POST https://api.karbonhq.com/v3/Files \
-H "Authorization: Bearer {token}" \
-H "AccessKey: {key}" \
-F "file=@./proposal.pdf;type=application/pdf" \
-F "workitem_keys=RXq4mD62PXg"
This uploads proposal.pdf and links it to a single work item.
Response
201 Created
{
"@odata.context": "https://api.karbonhq.com/v3/$metadata#Files/$entity",
"Id": "2S3RNjkR66Ln",
"Name": "proposal.pdf",
"MimeType": "application/pdf",
"Size": "334565"
}
Errors
| Status | Meaning | Common cause |
|---|---|---|
400 Bad Request | No file was included | The request was missing a multipart part named file, or the part had no filename= on its Content-Disposition header. |
400 Bad Request | No entity keys were provided | None of the link fields were populated. Exactly one is required. |
400 Bad Request | Cannot link to more than one entity | More than one link field was populated, or a link field contained more than one key. Only one entity may be linked per upload. |
401 Unauthorized | Missing or invalid bearer token | See Authentication. |
429 Too Many Requests | Rate limit exceeded | See Rate limits. |
500 Internal Server Error | Unsupported file type, or an unexpected server error | Retry once; if it persists, contact support with the response body. |
Attaching to multiple records
To link the same file to several records, upload it once per record — each request returns its own Id. There is no endpoint for adding a link to an existing file after the fact.
Downloading files
This guide covers the upload path only. To download a previously uploaded file, see GET /v3/Files with a download token issued by GET /v3/FileList/{EntityType}.
Overriding filename or MIME type
If the file on disk has a misleading name or its detected MIME type is wrong, most HTTP clients let you override what’s sent on the file part. In curl, append filename= and type= to the -F value:
curl -F "file=@./report.bin;filename=q4-summary.pdf;type=application/pdf" ...
The same controls exist in most HTTP client libraries. In Python requests, pass a tuple: files={"file": ("q4-summary.pdf", open(path, "rb"), "application/pdf")}. In JavaScript fetch, construct a File or Blob with the desired name and MIME type.