curl --request GET \
--url https://app.sajn.se/api/v1/documents/{id}/comments/{threadId} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.sajn.se/api/v1/documents/{id}/comments/{threadId}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.sajn.se/api/v1/documents/{id}/comments/{threadId}', 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://app.sajn.se/api/v1/documents/{id}/comments/{threadId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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://app.sajn.se/api/v1/documents/{id}/comments/{threadId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.sajn.se/api/v1/documents/{id}/comments/{threadId}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sajn.se/api/v1/documents/{id}/comments/{threadId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": "cm4k2x9p10018abcd1234efgh",
"documentId": "cm4k2x9p10003abcd1234efgh",
"status": "OPEN",
"visibility": "INTERNAL",
"excerpt": "Anställningen börjar den 1 november 2026",
"createdAt": "2026-09-28T09:12:00.000Z",
"updatedAt": "2026-09-28T09:15:00.000Z",
"resolvedAt": null,
"createdBy": {
"id": "cm4k2x9p10002abcd1234efgh",
"name": "Alex Berg",
"email": "[email protected]"
},
"resolvedBy": null,
"messages": [
{
"id": "cm4k2x9p10019abcd1234efgh",
"threadId": "cm4k2x9p10018abcd1234efgh",
"parentId": "cm4k2x9p10019abcd1234efgh",
"body": "Kan vi ändra startdatum till den 1 december?",
"mentions": [
"cm4k2x9p10002abcd1234efgh"
],
"createdAt": "2026-09-28T09:12:00.000Z",
"editedAt": null,
"deletedAt": null,
"author": {
"type": "USER",
"id": "cm4k2x9p10002abcd1234efgh",
"name": "Alex Berg",
"email": "[email protected]"
}
}
]
}{
"code": "INVALID_API_VERSION",
"message": "Unknown API version \"2026-13\". Supported versions: 2026-09, 2026-10.",
"userMessage": "API-versionen finns inte.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "UNAUTHORIZED",
"message": "Invalid API token",
"userMessage": "Ogiltig API-nyckel",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "INSUFFICIENT_SCOPE",
"message": "Insufficient OAuth scope: requires documents:read",
"userMessage": "Applikationen saknar behörighet (scope) för denna åtgärd.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2",
"requiredScopes": [
"documents:read"
],
"grantedScopes": [
"profile:read"
]
}{
"code": "NOT_FOUND",
"message": "Comment thread not found",
"userMessage": "Resursen hittades inte.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2",
"resource": "thread"
}{
"code": "INVALID_STATE",
"message": "The resource's current state doesn't allow the operation, such as editing a document that was already sent or downloading a file that isn't produced yet.",
"userMessage": "Åtgärden är inte möjlig i resursens nuvarande status.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "RATE_LIMITED",
"message": "API rate limit exceeded",
"userMessage": "För många förfrågningar. Försök igen om en stund.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "INTERNAL_ERROR",
"message": "Internal server error",
"userMessage": "Något gick fel.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "UPSTREAM_UNAVAILABLE",
"message": "A service the operation depends on, such as an eID provider or a connected integration, failed or is unavailable. Retry with exponential backoff.",
"userMessage": "En extern tjänst svarar inte just nu. Försök igen om en stund.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}Get a comment thread
Returns one comment thread on a document, with its messages oldest first.
curl --request GET \
--url https://app.sajn.se/api/v1/documents/{id}/comments/{threadId} \
--header 'Authorization: Bearer <token>'import requests
url = "https://app.sajn.se/api/v1/documents/{id}/comments/{threadId}"
headers = {"Authorization": "Bearer <token>"}
response = requests.get(url, headers=headers)
print(response.text)const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};
fetch('https://app.sajn.se/api/v1/documents/{id}/comments/{threadId}', 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://app.sajn.se/api/v1/documents/{id}/comments/{threadId}",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>"
],
]);
$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://app.sajn.se/api/v1/documents/{id}/comments/{threadId}"
req, _ := http.NewRequest("GET", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://app.sajn.se/api/v1/documents/{id}/comments/{threadId}")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.sajn.se/api/v1/documents/{id}/comments/{threadId}")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"id": "cm4k2x9p10018abcd1234efgh",
"documentId": "cm4k2x9p10003abcd1234efgh",
"status": "OPEN",
"visibility": "INTERNAL",
"excerpt": "Anställningen börjar den 1 november 2026",
"createdAt": "2026-09-28T09:12:00.000Z",
"updatedAt": "2026-09-28T09:15:00.000Z",
"resolvedAt": null,
"createdBy": {
"id": "cm4k2x9p10002abcd1234efgh",
"name": "Alex Berg",
"email": "[email protected]"
},
"resolvedBy": null,
"messages": [
{
"id": "cm4k2x9p10019abcd1234efgh",
"threadId": "cm4k2x9p10018abcd1234efgh",
"parentId": "cm4k2x9p10019abcd1234efgh",
"body": "Kan vi ändra startdatum till den 1 december?",
"mentions": [
"cm4k2x9p10002abcd1234efgh"
],
"createdAt": "2026-09-28T09:12:00.000Z",
"editedAt": null,
"deletedAt": null,
"author": {
"type": "USER",
"id": "cm4k2x9p10002abcd1234efgh",
"name": "Alex Berg",
"email": "[email protected]"
}
}
]
}{
"code": "INVALID_API_VERSION",
"message": "Unknown API version \"2026-13\". Supported versions: 2026-09, 2026-10.",
"userMessage": "API-versionen finns inte.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "UNAUTHORIZED",
"message": "Invalid API token",
"userMessage": "Ogiltig API-nyckel",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "INSUFFICIENT_SCOPE",
"message": "Insufficient OAuth scope: requires documents:read",
"userMessage": "Applikationen saknar behörighet (scope) för denna åtgärd.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2",
"requiredScopes": [
"documents:read"
],
"grantedScopes": [
"profile:read"
]
}{
"code": "NOT_FOUND",
"message": "Comment thread not found",
"userMessage": "Resursen hittades inte.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2",
"resource": "thread"
}{
"code": "INVALID_STATE",
"message": "The resource's current state doesn't allow the operation, such as editing a document that was already sent or downloading a file that isn't produced yet.",
"userMessage": "Åtgärden är inte möjlig i resursens nuvarande status.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "RATE_LIMITED",
"message": "API rate limit exceeded",
"userMessage": "För många förfrågningar. Försök igen om en stund.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "INTERNAL_ERROR",
"message": "Internal server error",
"userMessage": "Något gick fel.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}{
"code": "UPSTREAM_UNAVAILABLE",
"message": "A service the operation depends on, such as an eID provider or a connected integration, failed or is unavailable. Retry with exponential backoff.",
"userMessage": "En extern tjänst svarar inte just nu. Försök igen om en stund.",
"requestId": "req_V1StGXR8Z5jdHi6BmyT2"
}Authorizations
Personal API key, e.g. Authorization: Bearer sajn_sk_.... Not scope-limited — acts as the issuing user.
Headers
API version for this request. Without it, the request uses the organization's default version; an organization without a default is pinned to the latest version by its first request.
2026-09, 2026-10 Response
200
The comment thread ID.
The document ID.
Whether the thread is open or resolved.
OPEN, RESOLVED If SHARED, every party on the document sees the thread. If INTERNAL, only the workspace does.
INTERNAL, SHARED The document text the thread refers to.
When the comment thread was created.
When the comment thread was last updated.
When the thread was resolved. Null while it's open.
Who wrote it. Null when the author no longer exists.
Show child attributes
Show child attributes
Who wrote it. Null when the author no longer exists.
Show child attributes
Show child attributes
The thread's messages, oldest first.
Show child attributes
Show child attributes
Was this page helpful?

