DonutworkHelp Center
Api ReferenceContent & Media
Donutwork documentation

Media Library

List media files, generate upload links, and request secure download links.

Media Library API

Strategy

For large files, use presigned direct upload:

  1. Request upload link from API.
  2. Upload file directly to storage with PUT.
  3. Use media list or download-link APIs for retrieval flow.

List Files

GET
/2026-02-01/media-library/files.json
Required permissionmedia_library:read

Path, query, and header parameters

pageinteger· query
Page number starting from 1.

Responses

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.

POST
/2026-02-01/media-library/files/upload-link.json
Required permissionmedia_library:write

Path, query, and header parameters

No path, query, or additional header parameters.

Request Body

JSON
{
  "file": {
    "filename": "invoice-apr-2026.pdf",
    "content_type": "application/pdf",
    "size_bytes": 58211
  }
}
fileobjectRequired
Upload target metadata (filename/content type/optional size).

Responses

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)

POST
/2026-02-01/media-library/files.json
Required permissionmedia_library:write

Path, query, and header parameters

No path, query, or additional header parameters.

Request Body

JSON
{
  "file": {
    "filename": "small-note.txt",
    "content_type": "text/plain",
    "content_base64": "U2NoZWR1bGVkIG5vdGUgZnJvbSBBUEk="
  }
}
fileobjectRequired
Fallback upload payload using base64 content.

Responses

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.

POST
/2026-02-01/media-library/files/download-link.json
Required permissionmedia_library:write

Path, query, and header parameters

No path, query, or additional header parameters.

Request Body

JSON
{
  "file": {
    "filename": "invoice-apr-2026.pdf"
  }
}
fileobjectRequired
Target file descriptor for secure download URL generation.

Responses

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.

On this page