Content Box
Manage content types and content entities with scalable custom schemas.
Content Box API
The Content Box system provides a schematized storage layer for unstructured or custom-structured data. It allows organizations to define complex data models (Types) and instantiate them as managed content entities (Contents), suitable for blogs, product catalogs, and internal metadata repositories.
Content Entity Management
Manage the lifecycle of data entries within your defined content structures.
List Content Entities
Retrieve a paginated collection of content entities. Results can be filtered by state, content type, or via a full-text search query.
contentbox_contents:readPath, query, and header parameters
sizepagetype_idstatesearchResponses
Collection of content entities retrieved.
{
"entities": "Contents",
"count": 12,
"per_page": 50,
"elements": [
{
"id": "6768...",
"type_id": "6751...",
"title": "Q1 Product Launch",
"state": "public",
"data": {
"headline": "Introducing the 2026 Fleet",
"hero_image": "https://cdn.acme.com/img/l1.jpg",
"featured": true
}
}
]
}Request examples
curl --request GET 'https://api.hub.donutwork.com/2026-02-01/contentbox/contents.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/contents.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/contentbox/contents.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 Content Entity
Provision a new content entry. The data payload must adhere to the requirements of the associated type_id.
contentbox_contents:writePath, query, and header parameters
No path, query, or additional header parameters.
Request Body
{
"content": {
"title": "Annual Sustainability Report",
"type_id": "675112233b498f30",
"state": "draft",
"data": {
"period": "2025",
"impact_score": 92
}
}
}content.titleRequiredcontent.type_idRequiredcontent.statecontent.dataResponses
Content entity successfully provisioned.
{
"id": "6768..."
}Request examples
curl --request POST 'https://api.hub.donutwork.com/2026-02-01/contentbox/contents.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"content": {
"title": "Annual Sustainability Report",
"type_id": "675112233b498f30",
"state": "draft",
"data": {
"period": "2025",
"impact_score": 92
}
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/contents.json', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": {
"title": "Annual Sustainability Report",
"type_id": "675112233b498f30",
"state": "draft",
"data": {
"period": "2025",
"impact_score": 92
}
}
}),
});
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/contentbox/contents.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 => '{
"content": {
"title": "Annual Sustainability Report",
"type_id": "675112233b498f30",
"state": "draft",
"data": {
"period": "2025",
"impact_score": 92
}
}
}',
]);
$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.
Update Content Entity
Modify an existing content entry. This endpoint supports partial updates; only the fields provided in the content object will be modified.
contentbox_contents:writePath, query, and header parameters
contentIdRequiredRequest Body
{
"content": {
"state": "public",
"data": {
"revised_at": "2026-03-01T10:00:00Z"
}
}
}content.titlecontent.statecontent.dataResponses
Content entity successfully updated.
{
"id": "6768...",
"updated": true
}Request examples
curl --request PUT 'https://api.hub.donutwork.com/2026-02-01/contentbox/contents/CONTENTID.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"content": {
"state": "public",
"data": {
"revised_at": "2026-03-01T10:00:00Z"
}
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/contents/CONTENTID.json', {
method: 'PUT',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"content": {
"state": "public",
"data": {
"revised_at": "2026-03-01T10:00:00Z"
}
}
}),
});
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/contentbox/contents/CONTENTID.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{
"content": {
"state": "public",
"data": {
"revised_at": "2026-03-01T10:00:00Z"
}
}
}',
]);
$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.
Retrieve Content Entity
Fetch the full payload for a single content entry.
contentbox_contents:readPath, query, and header parameters
contentIdRequiredResponses
Content entity retrieved.
{
"id": "6768...",
"title": "Q1 Product Launch",
"state": "public",
"data": {}
}Content entry does not exist.
{
"error": "Content Box not found"
}Request examples
curl --request GET 'https://api.hub.donutwork.com/2026-02-01/contentbox/contents/CONTENTID.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/contents/CONTENTID.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/contentbox/contents/CONTENTID.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.
Decommission Content Entity
Permanently delete a content entry. This action is irreversible.
contentbox_contents:writePath, query, and header parameters
contentIdRequiredResponses
Deletion request processed.
{
"id": "6768...",
"deleted": true
}Request examples
curl --request DELETE 'https://api.hub.donutwork.com/2026-02-01/contentbox/contents/CONTENTID.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/contents/CONTENTID.json', {
method: 'DELETE',
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/contentbox/contents/CONTENTID.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'DELETE',
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.
Content Type Modeling (Schema Definition)
Define and manage the structural blueprints that govern how content is stored and validated.
List Content Types
Retrieve the catalog of all defined content schemas for your organization.
contentbox_types:readPath, query, and header parameters
sizepageResponses
Collection of content type definitions.
{
"entities": "Types",
"count": 1,
"elements": [
{
"id": "6751...",
"title": "Corporate Blog",
"description": "Schema for official news",
"fields": {
"author": {
"label": "Author",
"type": "string"
}
}
}
]
}Request examples
curl --request GET 'https://api.hub.donutwork.com/2026-02-01/contentbox/types.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/types.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/contentbox/types.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 Content Type
Define a new organizational schema. Specify the attributes and UI input types for each field in the model.
contentbox_types:writePath, query, and header parameters
No path, query, or additional header parameters.
Request Body
{
"type": {
"title": "E-Commerce Product",
"description": "Standardized schema for catalog items.",
"fields": {
"sku": {
"label": "SKU",
"type": "string"
},
"price": {
"label": "Unit Price",
"type": "string"
},
"in_stock": {
"label": "Inventory Status",
"type": "checkbox"
}
}
}
}type.titleRequiredtype.descriptiontype.fieldsRequiredResponses
Content type definition created.
{
"id": "6751...",
"title": "E-Commerce Product"
}Request examples
curl --request POST 'https://api.hub.donutwork.com/2026-02-01/contentbox/types.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"type": {
"title": "E-Commerce Product",
"description": "Standardized schema for catalog items.",
"fields": {
"sku": {
"label": "SKU",
"type": "string"
},
"price": {
"label": "Unit Price",
"type": "string"
},
"in_stock": {
"label": "Inventory Status",
"type": "checkbox"
}
}
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/types.json', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"type": {
"title": "E-Commerce Product",
"description": "Standardized schema for catalog items.",
"fields": {
"sku": {
"label": "SKU",
"type": "string"
},
"price": {
"label": "Unit Price",
"type": "string"
},
"in_stock": {
"label": "Inventory Status",
"type": "checkbox"
}
}
}
}),
});
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/contentbox/types.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 => '{
"type": {
"title": "E-Commerce Product",
"description": "Standardized schema for catalog items.",
"fields": {
"sku": {
"label": "SKU",
"type": "string"
},
"price": {
"label": "Unit Price",
"type": "string"
},
"in_stock": {
"label": "Inventory Status",
"type": "checkbox"
}
}
}
}',
]);
$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.
Retrieve Type Definition
Fetch the precise structural definition for a specific content type.
contentbox_types:readPath, query, and header parameters
typeIdRequiredResponses
Full schema definition retrieved.
{
"id": "6751...",
"title": "Corporate Blog",
"fields": {}
}Request examples
curl --request GET 'https://api.hub.donutwork.com/2026-02-01/contentbox/types/TYPEID.json' \
--header 'Authorization: Bearer YOUR_API_KEY'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/types/TYPEID.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/contentbox/types/TYPEID.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.
Update Type Definition
Update metadata or fields for a specific content schema. When fields is provided, each field must include both label and type and use allowed input types.
contentbox_types:writePath, query, and header parameters
typeIdRequiredRequest Body
{
"type": {
"title": "Corporate Blog",
"description": "Schema for official company news",
"fields": {
"author": {
"label": "Author",
"type": "string"
},
"hero_image": {
"label": "Hero Image",
"type": "url"
}
}
}
}type.titletype.descriptiontype.fieldsResponses
Content type updated.
{
"id": "6751...",
"title": "Corporate Blog",
"description": "Schema for official company news",
"fields": {}
}Invalid fields payload or field type.
{
"error": "Fields must be an associative array"
}Request examples
curl --request PUT 'https://api.hub.donutwork.com/2026-02-01/contentbox/types/TYPEID.json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data '{
"type": {
"title": "Corporate Blog",
"description": "Schema for official company news",
"fields": {
"author": {
"label": "Author",
"type": "string"
},
"hero_image": {
"label": "Hero Image",
"type": "url"
}
}
}
}'const response = await fetch('https://api.hub.donutwork.com/2026-02-01/contentbox/types/TYPEID.json', {
method: 'PUT',
headers: {
Authorization: 'Bearer ' + process.env.DONUTWORK_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
"type": {
"title": "Corporate Blog",
"description": "Schema for official company news",
"fields": {
"author": {
"label": "Author",
"type": "string"
},
"hero_image": {
"label": "Hero Image",
"type": "url"
}
}
}
}),
});
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/contentbox/types/TYPEID.json');
curl_setopt_array($request, [
CURLOPT_CUSTOMREQUEST => 'PUT',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('DONUTWORK_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => '{
"type": {
"title": "Corporate Blog",
"description": "Schema for official company news",
"fields": {
"author": {
"label": "Author",
"type": "string"
},
"hero_image": {
"label": "Hero Image",
"type": "url"
}
}
}
}',
]);
$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.