curl --request POST \
--url https://api.protodesk.io/v1/attachments/uploads \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"filename": "<string>",
"sizeBytes": 8388608,
"sha256": "<string>"
}
'import requests
url = "https://api.protodesk.io/v1/attachments/uploads"
payload = {
"filename": "<string>",
"sizeBytes": 8388608,
"sha256": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({filename: '<string>', sizeBytes: 8388608, sha256: '<string>'})
};
fetch('https://api.protodesk.io/v1/attachments/uploads', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.protodesk.io/v1/attachments/uploads",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'filename' => '<string>',
'sizeBytes' => 8388608,
'sha256' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.protodesk.io/v1/attachments/uploads"
payload := strings.NewReader("{\n \"filename\": \"<string>\",\n \"sizeBytes\": 8388608,\n \"sha256\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.protodesk.io/v1/attachments/uploads")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"filename\": \"<string>\",\n \"sizeBytes\": 8388608,\n \"sha256\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.protodesk.io/v1/attachments/uploads")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"filename\": \"<string>\",\n \"sizeBytes\": 8388608,\n \"sha256\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"uploadId": "<string>",
"status": "pending",
"url": "<string>",
"method": "PUT",
"headers": {
"Content-Type": "<string>",
"Content-Length": "<string>"
},
"expiresAt": "2023-11-07T05:31:56Z",
"maxSizeBytes": 123,
"attachment": {
"url": "<string>",
"filename": "<string>",
"contentType": "<string>",
"sizeBytes": 123
}
}{
"uploadId": "<string>",
"status": "pending",
"url": "<string>",
"method": "PUT",
"headers": {
"Content-Type": "<string>",
"Content-Length": "<string>"
},
"expiresAt": "2023-11-07T05:31:56Z",
"maxSizeBytes": 123,
"attachment": {
"url": "<string>",
"filename": "<string>",
"contentType": "<string>",
"sizeBytes": 123
}
}{
"error": {
"code": "route.not_found",
"message": "Not found",
"requestId": "req_x6q5vl75f5d53m7oet2k4r5w6a"
}
}Start an upload
Creates a connection-owned upload with a ten-minute lifetime. Compute the file’s lowercase SHA-256 first, then PUT its raw bytes to the returned URL with the returned Content-Type and Content-Length headers. Do not forward your API key or OAuth token to that URL. Call complete_attachment_upload afterward. Requires a client capable of reading the local file and making an HTTP PUT; MCP does not transfer bytes inside tool arguments. Supports JPEG, PNG, WebP, GIF, MP3, Ogg, WAV, M4A, WebM, MP4, MOV, PDF, plain text and CSV up to 16 MiB. Office files and archives are not supported by this upload flow. The same idempotency key and file metadata reuse the upload without extending its expiry; changed metadata returns 409. A completed retry returns its ready attachment. Uploading never sends a message. Expired uploads require a new idempotency key.
curl --request POST \
--url https://api.protodesk.io/v1/attachments/uploads \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"filename": "<string>",
"sizeBytes": 8388608,
"sha256": "<string>"
}
'import requests
url = "https://api.protodesk.io/v1/attachments/uploads"
payload = {
"filename": "<string>",
"sizeBytes": 8388608,
"sha256": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({filename: '<string>', sizeBytes: 8388608, sha256: '<string>'})
};
fetch('https://api.protodesk.io/v1/attachments/uploads', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.protodesk.io/v1/attachments/uploads",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'filename' => '<string>',
'sizeBytes' => 8388608,
'sha256' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json",
"Idempotency-Key: <idempotency-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.protodesk.io/v1/attachments/uploads"
payload := strings.NewReader("{\n \"filename\": \"<string>\",\n \"sizeBytes\": 8388608,\n \"sha256\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Idempotency-Key", "<idempotency-key>")
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.protodesk.io/v1/attachments/uploads")
.header("Idempotency-Key", "<idempotency-key>")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"filename\": \"<string>\",\n \"sizeBytes\": 8388608,\n \"sha256\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.protodesk.io/v1/attachments/uploads")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Idempotency-Key"] = '<idempotency-key>'
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"filename\": \"<string>\",\n \"sizeBytes\": 8388608,\n \"sha256\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"uploadId": "<string>",
"status": "pending",
"url": "<string>",
"method": "PUT",
"headers": {
"Content-Type": "<string>",
"Content-Length": "<string>"
},
"expiresAt": "2023-11-07T05:31:56Z",
"maxSizeBytes": 123,
"attachment": {
"url": "<string>",
"filename": "<string>",
"contentType": "<string>",
"sizeBytes": 123
}
}{
"uploadId": "<string>",
"status": "pending",
"url": "<string>",
"method": "PUT",
"headers": {
"Content-Type": "<string>",
"Content-Length": "<string>"
},
"expiresAt": "2023-11-07T05:31:56Z",
"maxSizeBytes": 123,
"attachment": {
"url": "<string>",
"filename": "<string>",
"contentType": "<string>",
"sizeBytes": 123
}
}{
"error": {
"code": "route.not_found",
"message": "Not found",
"requestId": "req_x6q5vl75f5d53m7oet2k4r5w6a"
}
}Authorizations
Use a workspace API key in the Authorization header. Keys use pk_live_<key_id> for production and pk_test<key_id>_ for test mode.
Headers
8 - 128Body
1 - 255image/jpeg, image/png, image/webp, image/gif, audio/mpeg, audio/ogg, audio/wav, audio/mp4, audio/webm, video/mp4, video/webm, video/quicktime, application/pdf, text/plain, text/csv 1 <= x <= 16777216^[a-f0-9]{64}$Response
This upload already completed. Reuse the attachment.
pending, ready Temporary PUT URL, present only while pending.
PUT Show child attributes
Show child attributes
Present only when ready. Use this object in a message's attachments array.
Show child attributes
Show child attributes
