Read Changes
curl --request GET \
--url https://api.example.com/v0/workspaces/{id}/changesimport requests
url = "https://api.example.com/v0/workspaces/{id}/changes"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v0/workspaces/{id}/changes', 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.example.com/v0/workspaces/{id}/changes",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v0/workspaces/{id}/changes"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/v0/workspaces/{id}/changes")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v0/workspaces/{id}/changes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyWorkspaces
Read Changes
GET /v0/workspaces/:id/changes — A bounded, audience-filtered page of workspace changes after your acknowledged position
GET
/
v0
/
workspaces
/
{id}
/
changes
Read Changes
curl --request GET \
--url https://api.example.com/v0/workspaces/{id}/changesimport requests
url = "https://api.example.com/v0/workspaces/{id}/changes"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/v0/workspaces/{id}/changes', 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.example.com/v0/workspaces/{id}/changes",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v0/workspaces/{id}/changes"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/v0/workspaces/{id}/changes")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v0/workspaces/{id}/changes")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyReturns the next page of the workspace change feed (artifact, folder, task, and workspace events, in commit order) after this API key’s acknowledged position. Reading never acknowledges: call Acknowledge with the page’s
Only one page is outstanding at a time. While it is, a read without its
deliveryToken to move forward. A workspace in the trash answers 410 WORKSPACE_DELETED. MCP: workspace_changes. CLI: rip workspace changes <workspace-id> [--limit --delivery-token].
Auth: Authorization: Bearer tr_... (an account API key). {id} is the workspace UUID.
Query parameters
| Parameter | Type | Description |
|---|---|---|
limit | integer | 1–100, default 50 |
deliveryToken | string | Replay the outstanding page instead of asking for a new one |
Response
{
"ok": true,
"data": {
"items": [
{ "id": "…", "type": "artifact.updated",
"actor": { "type": "account", "id": "rip1…", "surface": "claude-code" },
"subject": { "type": "artifact", "id": "…" },
"payload": { "versionId": "7d8e…" },
"why": "Set launch prices the team can defend to finance",
"agent": { "name": "Claude Code (laptop)" },
"createdAt": "2026-09-15T09:00:00.000Z" }
],
"deliveryToken": "q8Hc…", "hasMore": false, "historyGap": false, "refresh": "none"
}
}
| Field | Description |
|---|---|
items | Changes you may see: the event’s audience must be one of yours and its subject must be authorized for you, so an external member never sees internal work. Payloads never carry folder paths or counts |
why | The goal the writer stated. null for edits made in the dashboard, system jobs (such as lease expiry), side effects of team changes, and changes from before whys were recorded |
agent | The agent key’s name, only on changes made by your own account; otherwise null |
deliveryToken | Acknowledge or replay this page with it. Valid for 10 minutes. null when items is empty |
hasMore | More changes wait after this page |
historyGap | Retention pruned changes past your position; rebuild state from Load |
refresh | required when your access changed since your last read; refetch authorized state before continuing |
deliveryToken is refused; a read with it returns the same page. Once the token expires, the next read issues a fresh page from your acknowledged position.
History sequence numbers are positions in a fixed catch-up window, not visible-event counts or content revisions. Load may show current content alongside an older window. Consume, replay, and explicitly acknowledge the delivered page to reach the next window. Acknowledgment consumes history; it cannot resolve a content-write conflict. Browser rendering and polling never acknowledge visible work.
Errors
| Status | Code | Cause |
|---|---|---|
409 | WORKSPACE_PAGE_UNACKNOWLEDGED | A delivered page is outstanding; replay it with its deliveryToken or acknowledge it |
400 | INVALID_WORKSPACE_DELIVERY | The token is wrong, expired, or belongs to another reader |
400 | INVALID_INPUT / INVALID_LIMIT | limit is not an integer / not between 1 and 100 |
404 | WORKSPACE_NOT_FOUND | No workspace with that id |
403 | WORKSPACE_FORBIDDEN | You are not a member |