Create Content Update
curl --request POST \
--url https://api.slatehq.ai/slate-core/api/public/v1/content-updates \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"url": "<string>",
"update_type": "<string>",
"occurred_at": "<string>",
"is_draft": true,
"content_artifact_uid": "<string>",
"metadata": {}
}
'import requests
url = "https://api.slatehq.ai/slate-core/api/public/v1/content-updates"
payload = {
"url": "<string>",
"update_type": "<string>",
"occurred_at": "<string>",
"is_draft": True,
"content_artifact_uid": "<string>",
"metadata": {}
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({
url: '<string>',
update_type: '<string>',
occurred_at: '<string>',
is_draft: true,
content_artifact_uid: '<string>',
metadata: {}
})
};
fetch('https://api.slatehq.ai/slate-core/api/public/v1/content-updates', 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.slatehq.ai/slate-core/api/public/v1/content-updates",
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([
'url' => '<string>',
'update_type' => '<string>',
'occurred_at' => '<string>',
'is_draft' => true,
'content_artifact_uid' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$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.slatehq.ai/slate-core/api/public/v1/content-updates"
payload := strings.NewReader("{\n \"url\": \"<string>\",\n \"update_type\": \"<string>\",\n \"occurred_at\": \"<string>\",\n \"is_draft\": true,\n \"content_artifact_uid\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
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.slatehq.ai/slate-core/api/public/v1/content-updates")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"url\": \"<string>\",\n \"update_type\": \"<string>\",\n \"occurred_at\": \"<string>\",\n \"is_draft\": true,\n \"content_artifact_uid\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.slatehq.ai/slate-core/api/public/v1/content-updates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"url\": \"<string>\",\n \"update_type\": \"<string>\",\n \"occurred_at\": \"<string>\",\n \"is_draft\": true,\n \"content_artifact_uid\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"event_id": 123,
"daily_update_id": 123,
"deduped": true
}Content Updates
Create Content Update
Record a page publish, refresh, or draft event in Slate’s Content Updates ledger.
POST
/
slate-core
/
api
/
public
/
v1
/
content-updates
Create Content Update
curl --request POST \
--url https://api.slatehq.ai/slate-core/api/public/v1/content-updates \
--header 'Authorization: <authorization>' \
--header 'Content-Type: application/json' \
--data '
{
"url": "<string>",
"update_type": "<string>",
"occurred_at": "<string>",
"is_draft": true,
"content_artifact_uid": "<string>",
"metadata": {}
}
'import requests
url = "https://api.slatehq.ai/slate-core/api/public/v1/content-updates"
payload = {
"url": "<string>",
"update_type": "<string>",
"occurred_at": "<string>",
"is_draft": True,
"content_artifact_uid": "<string>",
"metadata": {}
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': 'application/json'},
body: JSON.stringify({
url: '<string>',
update_type: '<string>',
occurred_at: '<string>',
is_draft: true,
content_artifact_uid: '<string>',
metadata: {}
})
};
fetch('https://api.slatehq.ai/slate-core/api/public/v1/content-updates', 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.slatehq.ai/slate-core/api/public/v1/content-updates",
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([
'url' => '<string>',
'update_type' => '<string>',
'occurred_at' => '<string>',
'is_draft' => true,
'content_artifact_uid' => '<string>',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: application/json"
],
]);
$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.slatehq.ai/slate-core/api/public/v1/content-updates"
payload := strings.NewReader("{\n \"url\": \"<string>\",\n \"update_type\": \"<string>\",\n \"occurred_at\": \"<string>\",\n \"is_draft\": true,\n \"content_artifact_uid\": \"<string>\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
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.slatehq.ai/slate-core/api/public/v1/content-updates")
.header("Authorization", "<authorization>")
.header("Content-Type", "application/json")
.body("{\n \"url\": \"<string>\",\n \"update_type\": \"<string>\",\n \"occurred_at\": \"<string>\",\n \"is_draft\": true,\n \"content_artifact_uid\": \"<string>\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.slatehq.ai/slate-core/api/public/v1/content-updates")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"url\": \"<string>\",\n \"update_type\": \"<string>\",\n \"occurred_at\": \"<string>\",\n \"is_draft\": true,\n \"content_artifact_uid\": \"<string>\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"event_id": 123,
"daily_update_id": 123,
"deduped": true
}Records an entry in your workspace’s Content Updates ledger. Use this to log publishes, refreshes, or drafts from any system outside of Slate — a custom CMS, a static site generator, a deploy pipeline, or your own internal tooling — so the entry shows up in the Update History and Performance tabs alongside workflow- and manually-logged updates.
Entries created through this endpoint appear with the source label API.
See Errors for error response formats.
This is the only Content Updates endpoint accessible via API tokens. To list, edit, or delete entries, use the Slate dashboard.
Parameters
string
required
Bearer token. Format:
Bearer slat_<your-token>. See Authentication.string
required
Canonical URL of the page being recorded. Use the full URL including the protocol (for example,
https://example.com/blog/post). To get accurate matching across runs, drop tracking parameters and use the same canonical form everywhere.string
The kind of event to record. One of:
publish, refresh. If you omit it, Slate uses refresh when the page already has update entries and publish otherwise. To record a draft, set is_draft to true.string
ISO-8601 timestamp for when the update happened (for example,
2026-05-06T14:30:00Z). Defaults to the time the request is received.boolean
default:"false"
Set to
true to record the entry as a draft. Drafts stay in the ledger but do not count toward Published or Refreshed totals on the Performance tab.string
Optional UID of the Slate artifact this update came from. The artifact must exist in the token’s workspace. Otherwise the request fails with
400 and unknown content_artifact_uid. To store your own IDs, such as a build ID, use metadata instead.object
Optional JSON object stored alongside the entry. Use it for context fields your reporting may need later — for example, the deploy ID, the author, the model that generated the content. Must be a JSON object; arrays and primitives are rejected.
Response
Returns201 Created with the recorded event details.
integer
required
Unique identifier for the recorded event.
integer
Identifier for the daily rollup row this event belongs to.
null for draft entries, since drafts do not roll up into daily counts.boolean
required
true if the page already had another update event on the same day. Slate still records this event, and both events roll into the same daily entry. false otherwise.Example
curl -s -X POST "https://api.slatehq.ai/slate-core/api/public/v1/content-updates" \
-H "Authorization: Bearer slat_YOUR_TOKEN" \
-H "Content-Type: application/json" \
--data-raw '{
"url": "https://example.com/blog/seo-guide-2026",
"update_type": "refresh",
"occurred_at": "2026-05-06T14:30:00Z",
"is_draft": false,
"metadata": {
"deploy_id": "dep_9f2a",
"author": "marketing-bot"
}
}'
import requests
response = requests.post(
"https://api.slatehq.ai/slate-core/api/public/v1/content-updates",
headers={
"Authorization": "Bearer slat_YOUR_TOKEN",
"Content-Type": "application/json",
},
json={
"url": "https://example.com/blog/seo-guide-2026",
"update_type": "refresh",
"occurred_at": "2026-05-06T14:30:00Z",
"is_draft": False,
"metadata": {
"deploy_id": "dep_9f2a",
"author": "marketing-bot",
},
},
)
event = response.json()
print(event["event_id"], event["deduped"])
const response = await fetch(
"https://api.slatehq.ai/slate-core/api/public/v1/content-updates",
{
method: "POST",
headers: {
"Authorization": "Bearer slat_YOUR_TOKEN",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://example.com/blog/seo-guide-2026",
update_type: "refresh",
occurred_at: "2026-05-06T14:30:00Z",
is_draft: false,
metadata: {
deploy_id: "dep_9f2a",
author: "marketing-bot",
},
}),
}
);
const event = await response.json();
console.log(event.event_id, event.deduped);
Response
{
"event_id": 184237,
"daily_update_id": 9412,
"deduped": false
}
Status codes
| Status | Description |
|---|---|
201 | Event recorded. |
400 | update_type is not publish or refresh, or content_artifact_uid doesn’t match an artifact in the workspace. |
401 | Missing or invalid Bearer token, or an invalid API token context. See Authentication. |
422 | url is missing, occurred_at is not a valid timestamp, or metadata is not a JSON object. |
500 | Internal server error. |
Update types and drafts
The combination ofupdate_type and is_draft decides how the entry shows up in reporting:
update_type | is_draft | Result |
|---|---|---|
publish | false | Counts toward Published on the Performance tab |
refresh | false | Counts toward Refreshed on the Performance tab |
publish or refresh | true | Stored as a draft. Counts toward Drafts in flight, not Published or Refreshed |
| omitted | false | Recorded as refresh if the page already has entries, otherwise publish |
| omitted | true | Stored as a draft |
Same-day events and retries
Every request records a new event, even if the page already has an event that day. When it does, the response hasdeduped: true, and the events share one daily entry in reporting.
Retrying a request that already succeeded records another event. Only retry when the first request failed.
What’s next
- Content Updates — view, edit, and analyze the entries you create here.
- Track Content Update block — log updates from inside a Slate workflow instead of an external system.
- Authentication — create and manage API tokens.
Was this page helpful?