curl --request POST \
--url https://{your-subdomain}.neetodesk.com/api/external/v2/attachments \
--header 'Content-Type: multipart/form-data' \
--header 'X-Api-Key: <x-api-key>' \
--form file=@example-fileconst form = new FormData();
form.append('file', '<string>');
const options = {method: 'POST', headers: {'X-Api-Key': '<x-api-key>'}};
options.body = form;
fetch('https://{your-subdomain}.neetodesk.com/api/external/v2/attachments', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://{your-subdomain}.neetodesk.com/api/external/v2/attachments"
files = { "file": ("example-file", open("example-file", "rb")) }
headers = {"X-Api-Key": "<x-api-key>"}
response = requests.post(url, files=files, headers=headers)
print(response.text){
"id": "aaaabbbb-cccc-dddd-eeee-ffff00004444",
"signed_id": "eyJfcmFpbHMiOnsiZGF0YSI6IjEyMyJ9fQ==",
"filename": "report.pdf",
"content_type": "application/pdf",
"byte_size": 20481,
"checksum": "Y2hlY2tzdW1leGFtcGxl",
"blob_url": "https://spinkart.neetodesk.com/rails/active_storage/blobs/report.pdf",
"created_at": "2025-12-01T10:15:00Z"
}Upload attachment
Uploads a file and returns a signed_id for it. Pass that id in attachments on
Create ticket or
Create comment to attach the file.
The upload is a two-step flow because a file has no home until the record it belongs to exists. An uploaded file that is never attached is cleaned up automatically.
A signed_id can only be attached in the workspace that uploaded it.
Two different size limits apply, so it is worth knowing both. This endpoint accepts a file up to the workspace upload limit, 50 MB by default. Attaching it to a ticket or comment applies the smaller attachment limit, 10 MB by default, and a file over that is rejected at attach time rather than silently dropped.
curl --request POST \
--url https://{your-subdomain}.neetodesk.com/api/external/v2/attachments \
--header 'Content-Type: multipart/form-data' \
--header 'X-Api-Key: <x-api-key>' \
--form file=@example-fileconst form = new FormData();
form.append('file', '<string>');
const options = {method: 'POST', headers: {'X-Api-Key': '<x-api-key>'}};
options.body = form;
fetch('https://{your-subdomain}.neetodesk.com/api/external/v2/attachments', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://{your-subdomain}.neetodesk.com/api/external/v2/attachments"
files = { "file": ("example-file", open("example-file", "rb")) }
headers = {"X-Api-Key": "<x-api-key>"}
response = requests.post(url, files=files, headers=headers)
print(response.text){
"id": "aaaabbbb-cccc-dddd-eeee-ffff00004444",
"signed_id": "eyJfcmFpbHMiOnsiZGF0YSI6IjEyMyJ9fQ==",
"filename": "report.pdf",
"content_type": "application/pdf",
"byte_size": 20481,
"checksum": "Y2hlY2tzdW1leGFtcGxl",
"blob_url": "https://spinkart.neetodesk.com/rails/active_storage/blobs/report.pdf",
"created_at": "2025-12-01T10:15:00Z"
}{your-subdomain} with your workspace’s subdomain. Learn how to find your subdomain in Workspace subdomain.
Headers
Use the X-Api-Key header to provide your workspace API key. Refer to Authentication for more information.
Body
The file to upload. Sent as multipart/form-data.
Response
Created - File uploaded successfully
"aaaabbbb-cccc-dddd-eeee-ffff00004444"
Pass this to attachments on ticket or comment create to attach the file.
It is only accepted in the workspace that uploaded it.
"eyJfcmFpbHMiOnsiZGF0YSI6IjEyMyJ9fQ=="
"report.pdf"
"application/pdf"
20481
"Y2hlY2tzdW1leGFtcGxl"
URL the uploaded file can be fetched from.
"https://spinkart.neetodesk.com/rails/active_storage/blobs/report.pdf"
"2025-12-01T10:15:00Z"