Media Library
List media files, generate upload links, and request secure download links.
Media Library API
Strategy
For large files, use presigned direct upload:
- Request upload link from API.
- Upload file directly to storage with
PUT. - Use media list or download-link APIs for retrieval flow.
List Files
media_library:readPath, query, and header parameters
pageResponses
Media file list returned.
{
"entities": "MediaLibraryFile",
"count": 1,
"per_page": 60,
"pages": {
"current": 1,
"max": 1
},
"elements": [
{
"filename": "invoice-apr-2026.pdf",
"size": 58211,
"etag": "15d6a30e7a6f0d...",
"last_modified": "2026-04-20T08:55:10+00:00"
}
]
}Request examples
curl --request GET 'https://api.hub.donutwork.com/2026-02-01/media-library/files.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/media-library/files.json', {
method: 'GET',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
},
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/media-library/files.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
],
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.
Create Upload Link
media_library:writePath, query, and header parameters
No path, query, or additional header parameters.
Request Body
{
"file": {
"filename": "invoice-apr-2026.pdf",
"content_type": "application/pdf",
"size_bytes": 58211
}
}fileRequiredResponses
Presigned direct upload link generated.
{
"strategy": "direct_presigned_put",
"file": {
"filename": "invoice-apr-2026.pdf",
"content_type": "application/pdf",
"max_size_bytes": 524288000
},
"upload": {
"method": "PUT",
"url": "https://storage.example.com/prod-.../invoice-apr-2026.pdf?...",
"expires_in": 1200,
"headers": {
"Content-Type": "application/pdf"
}
}
}Request examples
curl --request POST 'https://api.hub.donutwork.com/2026-02-01/media-library/files/upload-link.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"file": {
"filename": "invoice-apr-2026.pdf",
"content_type": "application/pdf",
"size_bytes": 58211
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/media-library/files/upload-link.json', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"file": {
"filename": "invoice-apr-2026.pdf",
"content_type": "application/pdf",
"size_bytes": 58211
}
}),
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/media-library/files/upload-link.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{
"file": {
"filename": "invoice-apr-2026.pdf",
"content_type": "application/pdf",
"size_bytes": 58211
}
}',
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.
Upload File (Fallback)
media_library:writePath, query, and header parameters
No path, query, or additional header parameters.
Request Body
{
"file": {
"filename": "small-note.txt",
"content_type": "text/plain",
"content_base64": "U2NoZWR1bGVkIG5vdGUgZnJvbSBBUEk="
}
}fileRequiredResponses
File uploaded.
{
"filename": "small-note.txt",
"size": 24,
"uploaded": true
}Request examples
curl --request POST 'https://api.hub.donutwork.com/2026-02-01/media-library/files.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"file": {
"filename": "small-note.txt",
"content_type": "text/plain",
"content_base64": "U2NoZWR1bGVkIG5vdGUgZnJvbSBBUEk="
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/media-library/files.json', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"file": {
"filename": "small-note.txt",
"content_type": "text/plain",
"content_base64": "U2NoZWR1bGVkIG5vdGUgZnJvbSBBUEk="
}
}),
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/media-library/files.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{
"file": {
"filename": "small-note.txt",
"content_type": "text/plain",
"content_base64": "U2NoZWR1bGVkIG5vdGUgZnJvbSBBUEk="
}
}',
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.
Create Download Link
media_library:writePath, query, and header parameters
No path, query, or additional header parameters.
Request Body
{
"file": {
"filename": "invoice-apr-2026.pdf"
}
}fileRequiredResponses
Download link generated.
{
"filename": "invoice-apr-2026.pdf",
"url": "https://app.example.com/file-download/download?file=..."
}Request examples
curl --request POST 'https://api.hub.donutwork.com/2026-02-01/media-library/files/download-link.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"file": {
"filename": "invoice-apr-2026.pdf"
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/media-library/files/download-link.json', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"file": {
"filename": "invoice-apr-2026.pdf"
}
}),
});
const requestId = response.headers.get('x-request-id');
if (!response.ok) {
const error = await response.text();
throw new Error(`${response.status} ${error} [${requestId}]`);
}
const contentType = response.headers.get('content-type') ?? '';
const data = response.status === 204 ? null
: contentType.includes('application/json') ? await response.json()
: await response.text();$request = curl_init('https://api.hub.donutwork.com/2026-02-01/media-library/files/download-link.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{
"file": {
"filename": "invoice-apr-2026.pdf"
}
}',
]);
$response = curl_exec($request);
if ($response === false) {
$error = curl_error($request);
curl_close($request);
throw new RuntimeException($error);
}
$status = curl_getinfo($request, CURLINFO_RESPONSE_CODE);
$contentType = (string) curl_getinfo($request, CURLINFO_CONTENT_TYPE);
curl_close($request);
if ($status >= 400) { throw new RuntimeException($response); }
$data = $status === 204 ? null
: (str_contains($contentType, 'application/json')
? json_decode($response, true, flags: JSON_THROW_ON_ERROR) : $response);Replace uppercase placeholders and sample values with your own data and company resource IDs. Keep the API key on a trusted server. Reuse an idempotency key only for the same logical request and payload.