curl --request POST \
--url https://scribe.skeptrune.com/api/docs/{id}/threads \
--header 'Content-Type: application/json' \
--cookie scribe_session= \
--data '
{
"kind": "comment",
"anchorJson": "{\"from\":{\"type\":\"relative\",\"item\":10},\"to\":{\"type\":\"relative\",\"item\":24}}",
"quotedText": "ship in Q2",
"body": "Should this say Q3 instead?"
}
'import requests
url = "https://scribe.skeptrune.com/api/docs/{id}/threads"
payload = {
"kind": "comment",
"anchorJson": "{\"from\":{\"type\":\"relative\",\"item\":10},\"to\":{\"type\":\"relative\",\"item\":24}}",
"quotedText": "ship in Q2",
"body": "Should this say Q3 instead?"
}
headers = {
"cookie": "scribe_session=",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {cookie: 'scribe_session=', 'Content-Type': 'application/json'},
body: JSON.stringify({
kind: 'comment',
anchorJson: '{"from":{"type":"relative","item":10},"to":{"type":"relative","item":24}}',
quotedText: 'ship in Q2',
body: JSON.stringify('Should this say Q3 instead?')
})
};
fetch('https://scribe.skeptrune.com/api/docs/{id}/threads', 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://scribe.skeptrune.com/api/docs/{id}/threads",
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([
'kind' => 'comment',
'anchorJson' => '{"from":{"type":"relative","item":10},"to":{"type":"relative","item":24}}',
'quotedText' => 'ship in Q2',
'body' => 'Should this say Q3 instead?'
]),
CURLOPT_COOKIE => "scribe_session=",
CURLOPT_HTTPHEADER => [
"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://scribe.skeptrune.com/api/docs/{id}/threads"
payload := strings.NewReader("{\n \"kind\": \"comment\",\n \"anchorJson\": \"{\\\"from\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":10},\\\"to\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":24}}\",\n \"quotedText\": \"ship in Q2\",\n \"body\": \"Should this say Q3 instead?\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("cookie", "scribe_session=")
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://scribe.skeptrune.com/api/docs/{id}/threads")
.header("cookie", "scribe_session=")
.header("Content-Type", "application/json")
.body("{\n \"kind\": \"comment\",\n \"anchorJson\": \"{\\\"from\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":10},\\\"to\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":24}}\",\n \"quotedText\": \"ship in Q2\",\n \"body\": \"Should this say Q3 instead?\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://scribe.skeptrune.com/api/docs/{id}/threads")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["cookie"] = 'scribe_session='
request["Content-Type"] = 'application/json'
request.body = "{\n \"kind\": \"comment\",\n \"anchorJson\": \"{\\\"from\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":10},\\\"to\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":24}}\",\n \"quotedText\": \"ship in Q2\",\n \"body\": \"Should this say Q3 instead?\"\n}"
response = http.request(request)
puts response.read_body{
"id": "thr_5aBcDeFgHiJkLmNoPq6r",
"docId": "doc_S9tUvWxYzAbCdEfGh12i",
"kind": "comment",
"anchorJson": "{\"from\":{\"type\":\"relative\",\"item\":10},\"to\":{\"type\":\"relative\",\"item\":24}}",
"quotedText": "ship in Q2",
"proposedText": null,
"sid": null,
"status": "open",
"createdBy": "usr_V1StGXR8_Z5jdHi6BmyT",
"createdByName": "Ada Lovelace",
"createdByKind": "human",
"createdAt": 1752624000000,
"updatedAt": 1752624000000,
"resolvedBy": null,
"resolvedAt": null,
"messages": [
{
"id": "msg_6bCdEfGhIjKlMnOpQr7s",
"threadId": "thr_5aBcDeFgHiJkLmNoPq6r",
"authorUserId": "usr_V1StGXR8_Z5jdHi6BmyT",
"authorName": "Ada Lovelace",
"authorKind": "human",
"body": "Should this say Q3 instead of Q2?",
"createdAt": 1752624000000
}
]
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}Start a thread
Starts a comment or suggestion thread anchored to a document range. Anchor the thread either with anchorJson (Yjs relative positions, produced by the editor) or with quotedText — when anchorJson is omitted, the server locates that exact text in the live document (first occurrence) and computes the anchor, so an API caller/agent can comment on a quote without computing positions. Suggestions come in two forms: suggesting-mode suggestions reference an existing tracked-change mark burst via sid (the editor auto-creates these; body is optional), while legacy replacement suggestions carry proposedText to splice over the anchored range (agents can keep creating these). Comments and legacy suggestions require a body. Requires comment access on the document; API keys with edit OR comment access author the thread as their agent identity (read-only keys are rejected).
curl --request POST \
--url https://scribe.skeptrune.com/api/docs/{id}/threads \
--header 'Content-Type: application/json' \
--cookie scribe_session= \
--data '
{
"kind": "comment",
"anchorJson": "{\"from\":{\"type\":\"relative\",\"item\":10},\"to\":{\"type\":\"relative\",\"item\":24}}",
"quotedText": "ship in Q2",
"body": "Should this say Q3 instead?"
}
'import requests
url = "https://scribe.skeptrune.com/api/docs/{id}/threads"
payload = {
"kind": "comment",
"anchorJson": "{\"from\":{\"type\":\"relative\",\"item\":10},\"to\":{\"type\":\"relative\",\"item\":24}}",
"quotedText": "ship in Q2",
"body": "Should this say Q3 instead?"
}
headers = {
"cookie": "scribe_session=",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {cookie: 'scribe_session=', 'Content-Type': 'application/json'},
body: JSON.stringify({
kind: 'comment',
anchorJson: '{"from":{"type":"relative","item":10},"to":{"type":"relative","item":24}}',
quotedText: 'ship in Q2',
body: JSON.stringify('Should this say Q3 instead?')
})
};
fetch('https://scribe.skeptrune.com/api/docs/{id}/threads', 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://scribe.skeptrune.com/api/docs/{id}/threads",
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([
'kind' => 'comment',
'anchorJson' => '{"from":{"type":"relative","item":10},"to":{"type":"relative","item":24}}',
'quotedText' => 'ship in Q2',
'body' => 'Should this say Q3 instead?'
]),
CURLOPT_COOKIE => "scribe_session=",
CURLOPT_HTTPHEADER => [
"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://scribe.skeptrune.com/api/docs/{id}/threads"
payload := strings.NewReader("{\n \"kind\": \"comment\",\n \"anchorJson\": \"{\\\"from\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":10},\\\"to\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":24}}\",\n \"quotedText\": \"ship in Q2\",\n \"body\": \"Should this say Q3 instead?\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("cookie", "scribe_session=")
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://scribe.skeptrune.com/api/docs/{id}/threads")
.header("cookie", "scribe_session=")
.header("Content-Type", "application/json")
.body("{\n \"kind\": \"comment\",\n \"anchorJson\": \"{\\\"from\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":10},\\\"to\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":24}}\",\n \"quotedText\": \"ship in Q2\",\n \"body\": \"Should this say Q3 instead?\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://scribe.skeptrune.com/api/docs/{id}/threads")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["cookie"] = 'scribe_session='
request["Content-Type"] = 'application/json'
request.body = "{\n \"kind\": \"comment\",\n \"anchorJson\": \"{\\\"from\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":10},\\\"to\\\":{\\\"type\\\":\\\"relative\\\",\\\"item\\\":24}}\",\n \"quotedText\": \"ship in Q2\",\n \"body\": \"Should this say Q3 instead?\"\n}"
response = http.request(request)
puts response.read_body{
"id": "thr_5aBcDeFgHiJkLmNoPq6r",
"docId": "doc_S9tUvWxYzAbCdEfGh12i",
"kind": "comment",
"anchorJson": "{\"from\":{\"type\":\"relative\",\"item\":10},\"to\":{\"type\":\"relative\",\"item\":24}}",
"quotedText": "ship in Q2",
"proposedText": null,
"sid": null,
"status": "open",
"createdBy": "usr_V1StGXR8_Z5jdHi6BmyT",
"createdByName": "Ada Lovelace",
"createdByKind": "human",
"createdAt": 1752624000000,
"updatedAt": 1752624000000,
"resolvedBy": null,
"resolvedAt": null,
"messages": [
{
"id": "msg_6bCdEfGhIjKlMnOpQr7s",
"threadId": "thr_5aBcDeFgHiJkLmNoPq6r",
"authorUserId": "usr_V1StGXR8_Z5jdHi6BmyT",
"authorName": "Ada Lovelace",
"authorKind": "human",
"body": "Should this say Q3 instead of Q2?",
"createdAt": 1752624000000
}
]
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}{
"error": {
"code": "not_found",
"message": "No such document."
}
}Authorizations
Browser session cookie set by the WorkOS sign-in flow.
Path Parameters
Id of the document to start the thread on.
Body
The thread kind, anchor (anchorJson or quotedText), and first message.
Start a new comment or suggestion thread.
Kind of thread to start: comment or suggestion.
comment, suggestion "comment"
Serialized Yjs relative positions ({from,to}) for the selection. Produced by the editor; API callers that cannot compute relative positions should instead anchor by quotedText and omit this. Provide anchorJson or quotedText (anchorJson wins when both are given).
1"{\"from\":{\"type\":\"relative\",\"item\":10},\"to\":{\"type\":\"relative\",\"item\":24}}"
Text selected when creating the thread. When anchorJson is omitted, the server locates this exact text in the current document (first occurrence) and computes the anchor for you — the way an API caller or agent anchors a comment without a live editor. 422 quote_not_found when the text is not present.
1"ship in Q2"
Replacement text for a legacy replacement suggestion. Required when kind is suggestion and no sid is given; must be omitted for sid (suggesting-mode) suggestions.
"ship in Q3"
Suggesting-mode suggestion id: ties the thread to an existing suggestion_insert/suggestion_delete mark burst in the collaborative document (created by the editor). Suggestions only.
1"sug_lx2c1a9k3f0d"
First message of the thread. Required for comments and legacy replacement suggestions; optional for suggesting-mode (sid) suggestions, which are auto-created without a note.
1 - 10000"Should this say Q3 instead of Q2?"
Response
The created thread with its first message.
A thread including its messages.
Thread id.
"thr_5aBcDeFgHiJkLmNoPq6r"
Document the thread is anchored to.
"doc_S9tUvWxYzAbCdEfGh12i"
Kind of discussion thread.
comment, suggestion "comment"
Serialized Yjs relative positions ({from,to}) anchoring the thread.
"{\"from\":{\"type\":\"relative\",\"item\":10},\"to\":{\"type\":\"relative\",\"item\":24}}"
Text that was selected when the thread was created.
"ship in Q2"
Replacement text (legacy API-created replacement suggestions only). Accepting such a thread splices this text over the anchored range. Null for comments and suggesting-mode suggestions.
"ship in Q3"
Suggesting-mode suggestion id (editor tracked changes only): identifies the suggestion_insert/suggestion_delete mark burst in the collaborative document. Accepting/rejecting such a thread resolves those marks. Null for comments and legacy replacement suggestions.
null
Current lifecycle status of the thread.
open, resolved, accepted, rejected "open"
User id of the thread creator.
"usr_V1StGXR8_Z5jdHi6BmyT"
Display name of the thread creator — the creator's name or handle (agent creators carry the name of their API key). Null when the creator row no longer exists.
"Ada Lovelace"
Whether the thread creator is a person ('human') or an API-key agent identity ('agent'). Null when the creator row no longer exists.
human, agent, null "human"
When the thread was started (epoch milliseconds).
1752624000000
When the thread last changed (epoch milliseconds).
1752624000000
User id who resolved/accepted/rejected the thread, or null.
"usr_V1StGXR8_Z5jdHi6BmyT"
When the thread left the open state, or null.
1752624000000
Messages, oldest first.
Show child attributes
Show child attributes
[
{
"id": "msg_6bCdEfGhIjKlMnOpQr7s",
"threadId": "thr_5aBcDeFgHiJkLmNoPq6r",
"authorUserId": "usr_V1StGXR8_Z5jdHi6BmyT",
"authorName": "Ada Lovelace",
"authorKind": "human",
"body": "Should this say Q3 instead of Q2?",
"createdAt": 1752624000000
}
]