curl -X POST "https://api.shortkit.dev/v1/content/bulk-update" \
-H "Authorization: Bearer sk_live_your_secret_key" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"externalId": "recommendation-1803550",
"updates": {"author": "maya_chen"}
},
{
"externalId": "recommendation-1803551",
"updates": {"author": "jordan_lee"}
}
],
"onlyIfMissing": ["author"]
}'
import requests
response = requests.post(
"https://api.shortkit.dev/v1/content/bulk-update",
headers={
"Authorization": "Bearer sk_live_your_secret_key",
"Content-Type": "application/json",
},
json={
"items": [
{
"externalId": "recommendation-1803550",
"updates": {"author": "maya_chen"},
},
{
"externalId": "recommendation-1803551",
"updates": {"author": "jordan_lee"},
},
],
"onlyIfMissing": ["author"],
},
timeout=30,
)
response.raise_for_status()
result = response.json()["data"]
print(result["summary"])
const response = await fetch("https://api.shortkit.dev/v1/content/bulk-update", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_your_secret_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
items: [
{
externalId: "recommendation-1803550",
updates: { author: "maya_chen" },
},
{
externalId: "recommendation-1803551",
updates: { author: "jordan_lee" },
},
],
onlyIfMissing: ["author"],
}),
});
if (!response.ok) {
throw new Error(`Bulk update failed: ${response.status} ${await response.text()}`);
}
const { data } = await response.json();
console.log(data.summary);
{
"data": {
"results": [
{
"contentId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"externalId": "recommendation-1803550",
"status": "updated"
},
{
"contentId": "e3a1b2c3-d4e5-4f67-8901-23456789abcd",
"externalId": "recommendation-1803551",
"status": "skipped"
}
],
"summary": {
"total": 2,
"updated": 1,
"unchanged": 0,
"skipped": 1
}
},
"meta": {
"request_id": "req_01a2b3c4d5e6"
}
}
Content
Bulk update content metadata
Update metadata on up to 500 content items in one atomic request.
POST
/
v1
/
content
/
bulk-update
curl -X POST "https://api.shortkit.dev/v1/content/bulk-update" \
-H "Authorization: Bearer sk_live_your_secret_key" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"externalId": "recommendation-1803550",
"updates": {"author": "maya_chen"}
},
{
"externalId": "recommendation-1803551",
"updates": {"author": "jordan_lee"}
}
],
"onlyIfMissing": ["author"]
}'
import requests
response = requests.post(
"https://api.shortkit.dev/v1/content/bulk-update",
headers={
"Authorization": "Bearer sk_live_your_secret_key",
"Content-Type": "application/json",
},
json={
"items": [
{
"externalId": "recommendation-1803550",
"updates": {"author": "maya_chen"},
},
{
"externalId": "recommendation-1803551",
"updates": {"author": "jordan_lee"},
},
],
"onlyIfMissing": ["author"],
},
timeout=30,
)
response.raise_for_status()
result = response.json()["data"]
print(result["summary"])
const response = await fetch("https://api.shortkit.dev/v1/content/bulk-update", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_your_secret_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
items: [
{
externalId: "recommendation-1803550",
updates: { author: "maya_chen" },
},
{
externalId: "recommendation-1803551",
updates: { author: "jordan_lee" },
},
],
onlyIfMissing: ["author"],
}),
});
if (!response.ok) {
throw new Error(`Bulk update failed: ${response.status} ${await response.text()}`);
}
const { data } = await response.json();
console.log(data.summary);
{
"data": {
"results": [
{
"contentId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"externalId": "recommendation-1803550",
"status": "updated"
},
{
"contentId": "e3a1b2c3-d4e5-4f67-8901-23456789abcd",
"externalId": "recommendation-1803551",
"status": "skipped"
}
],
"summary": {
"total": 2,
"updated": 1,
"unchanged": 0,
"skipped": 1
}
},
"meta": {
"request_id": "req_01a2b3c4d5e6"
}
}
Select each content item by its ShortKit ID or your own external ID. ShortKit validates every item before changing anything. If any selector cannot be resolved, the complete request fails and no items are changed.
This endpoint requires a secret key. Publishable keys cannot call it.
The complete JSON request body cannot exceed 2 MiB. Unknown fields, non-finite numbers, and strings containing NUL characters are rejected.
Results appear in the same order as the request.
See Errors for the standard error envelope.
Request body
object[]
required
The content items to update. Include 1–500 items. Selectors cannot repeat, and two selectors cannot resolve to the same content item.
string
The ShortKit content UUID. Provide exactly one of
contentId or externalId for each item.string
Your non-empty identifier for the content item. ShortKit resolves it within your organization. Maximum 255 characters. Provide exactly one of
externalId or contentId for each item.object
required
The metadata fields to change. Include at least one supported field. Fields omitted from this object remain unchanged.
string
Replace the display title. Maximum 200 characters.
string | null
Replace the description, or set it to
null to clear it. Maximum 2,000 characters.string[]
Replace all tags. Include at most 100 tags, with up to 200 characters per tag.
string | null
Replace the editorial section, or set it to
null to clear it. Maximum 200 characters.string | null
Replace the content author, or set it to
null to clear it. Maximum 200 characters.object
Merge keys into the existing metadata. A
null value removes that key; omitted keys remain unchanged. Include at most 100 keys, with up to 200 characters per key and 32 KiB of JSON per item.string[]
Prevent overwriting existing values. Allowed values are
author, description, and section. List each guarded field at most once.Every guarded field must appear in every item’s updates. If any guarded field already contains a value, ShortKit skips that entire item. Only null counts as missing; an empty string is an existing value.Example
This request fills missing authors without replacing authors that are already set.curl -X POST "https://api.shortkit.dev/v1/content/bulk-update" \
-H "Authorization: Bearer sk_live_your_secret_key" \
-H "Content-Type: application/json" \
-d '{
"items": [
{
"externalId": "recommendation-1803550",
"updates": {"author": "maya_chen"}
},
{
"externalId": "recommendation-1803551",
"updates": {"author": "jordan_lee"}
}
],
"onlyIfMissing": ["author"]
}'
import requests
response = requests.post(
"https://api.shortkit.dev/v1/content/bulk-update",
headers={
"Authorization": "Bearer sk_live_your_secret_key",
"Content-Type": "application/json",
},
json={
"items": [
{
"externalId": "recommendation-1803550",
"updates": {"author": "maya_chen"},
},
{
"externalId": "recommendation-1803551",
"updates": {"author": "jordan_lee"},
},
],
"onlyIfMissing": ["author"],
},
timeout=30,
)
response.raise_for_status()
result = response.json()["data"]
print(result["summary"])
const response = await fetch("https://api.shortkit.dev/v1/content/bulk-update", {
method: "POST",
headers: {
Authorization: "Bearer sk_live_your_secret_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
items: [
{
externalId: "recommendation-1803550",
updates: { author: "maya_chen" },
},
{
externalId: "recommendation-1803551",
updates: { author: "jordan_lee" },
},
],
onlyIfMissing: ["author"],
}),
});
if (!response.ok) {
throw new Error(`Bulk update failed: ${response.status} ${await response.text()}`);
}
const { data } = await response.json();
console.log(data.summary);
{
"data": {
"results": [
{
"contentId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
"externalId": "recommendation-1803550",
"status": "updated"
},
{
"contentId": "e3a1b2c3-d4e5-4f67-8901-23456789abcd",
"externalId": "recommendation-1803551",
"status": "skipped"
}
],
"summary": {
"total": 2,
"updated": 1,
"unchanged": 0,
"skipped": 1
}
},
"meta": {
"request_id": "req_01a2b3c4d5e6"
}
}
Result statuses
| Status | Meaning |
|---|---|
updated | At least one supplied value changed. |
unchanged | The supplied values already matched the stored values. |
skipped | An onlyIfMissing safeguard prevented every change for that item. |
externalId is null when the content item does not have one.
Atomicity and retries
ShortKit commits all non-skipped changes in one transaction. A malformed item, an unknown or deleted item, or an item from another organization rejects the complete request without applying any changes. If no other request changes the same fields between attempts, you can retry after a network timeout. An identical unguarded retry returnsunchanged; an onlyIfMissing retry can return skipped after the first attempt fills the guarded field. If another request changes those fields before your retry, an unguarded retry reapplies its supplied values and can return updated. A guarded retry reevaluates onlyIfMissing against the current values and can instead return skipped.
For more than 500 items, split the update into batches of at most 500. Keep each batch below 2 MiB and inspect its summary before advancing.
Errors
| Status | Meaning |
|---|---|
400 | The body is malformed or fails field validation. |
401 | The secret key is missing or invalid. |
404 | At least one selector does not resolve in your organization. |
413 | The request body exceeds 2 MiB. |
422 | Two different selectors resolve to the same content item. |