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.
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. Omit for a draft entry.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 identifier you can use to correlate this entry with the artifact it was generated from (a workflow output, a CMS item, a build ID). Returned on subsequent reads from the dashboard.
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 event matched an existing entry (same URL on the same day, same update type) and was deduplicated rather than written as a new row. false if a new entry was created.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. Check deduped to see whether a new row was created. |
400 | Invalid request. url is missing, update_type is not publish or refresh, occurred_at is not ISO-8601, or metadata is not a JSON object. |
401 | Missing or invalid Bearer token. See Authentication. |
403 | API token context is invalid or scoped to a workspace the request cannot access. |
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 | true | Stored as a draft |
Deduplication
If you send a second request with the sameurl, same update_type, and an occurred_at on the same calendar day as an existing entry, the API returns the existing row with deduped: true instead of creating a duplicate. Use this to make your integration safe to retry.
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?