curl --request POST \
--url https://app.octavehq.com/api/v2/resource/check-drift \
--header 'Content-Type: application/json' \
--header 'api_key: <api-key>' \
--data '
{
"resourceOId": "rs_1234567890",
"propose": false
}
'import requests
url = "https://app.octavehq.com/api/v2/resource/check-drift"
payload = {
"resourceOId": "rs_1234567890",
"propose": False
}
headers = {
"api_key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {api_key: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({resourceOId: 'rs_1234567890', propose: false})
};
fetch('https://app.octavehq.com/api/v2/resource/check-drift', 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.octavehq.com/api/v2/resource/check-drift",
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([
'resourceOId' => 'rs_1234567890',
'propose' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"api_key: <api-key>"
],
]);
$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://app.octavehq.com/api/v2/resource/check-drift"
payload := strings.NewReader("{\n \"resourceOId\": \"rs_1234567890\",\n \"propose\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("api_key", "<api-key>")
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://app.octavehq.com/api/v2/resource/check-drift")
.header("api_key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"resourceOId\": \"rs_1234567890\",\n \"propose\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.octavehq.com/api/v2/resource/check-drift")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["api_key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"resourceOId\": \"rs_1234567890\",\n \"propose\": false\n}"
response = http.request(request)
puts response.read_body{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"material": true,
"skippedReason": "<string>",
"assessments": [
{
"entityType": "Product",
"entityOId": "<string>",
"entityName": "<string>",
"classification": "contradicts",
"warrantsDocUpdate": true,
"rationale": "<string>",
"changeKinds": [
"positioning_change"
],
"direction": "entity_moved"
}
],
"proposal": {
"summary": "<string>",
"insight": "<string>",
"recommendedAction": "<string>",
"proposedUpstreamEdit": "<string>",
"confidence": 123
},
"editHunks": [
{
"anchor": "<string>",
"replacement": "<string>",
"kind": "replace"
}
],
"suggestionOId": "<string>",
"checkedAt": "<string>",
"tokensUsed": 123
}{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"message": "<string>"
}Check Resource Drift
Check whether a source doc (Google Doc, Notion page, Linear doc, watched URL) has drifted from the library entities linked to it. Returns a per-entity verdict (contradicts / invalidates / strengthens / validates / immaterial, with change kinds and which side moved) and, when material, a consolidated doc-update proposal. Set propose: true to persist that proposal as a real suggestion for human review — then /suggestion/accept posts the attributed comment upstream. The doc must have linked entities (see /resource/link-entities).
curl --request POST \
--url https://app.octavehq.com/api/v2/resource/check-drift \
--header 'Content-Type: application/json' \
--header 'api_key: <api-key>' \
--data '
{
"resourceOId": "rs_1234567890",
"propose": false
}
'import requests
url = "https://app.octavehq.com/api/v2/resource/check-drift"
payload = {
"resourceOId": "rs_1234567890",
"propose": False
}
headers = {
"api_key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {api_key: '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({resourceOId: 'rs_1234567890', propose: false})
};
fetch('https://app.octavehq.com/api/v2/resource/check-drift', 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.octavehq.com/api/v2/resource/check-drift",
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([
'resourceOId' => 'rs_1234567890',
'propose' => false
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"api_key: <api-key>"
],
]);
$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://app.octavehq.com/api/v2/resource/check-drift"
payload := strings.NewReader("{\n \"resourceOId\": \"rs_1234567890\",\n \"propose\": false\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("api_key", "<api-key>")
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://app.octavehq.com/api/v2/resource/check-drift")
.header("api_key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"resourceOId\": \"rs_1234567890\",\n \"propose\": false\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.octavehq.com/api/v2/resource/check-drift")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["api_key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"resourceOId\": \"rs_1234567890\",\n \"propose\": false\n}"
response = http.request(request)
puts response.read_body{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"material": true,
"skippedReason": "<string>",
"assessments": [
{
"entityType": "Product",
"entityOId": "<string>",
"entityName": "<string>",
"classification": "contradicts",
"warrantsDocUpdate": true,
"rationale": "<string>",
"changeKinds": [
"positioning_change"
],
"direction": "entity_moved"
}
],
"proposal": {
"summary": "<string>",
"insight": "<string>",
"recommendedAction": "<string>",
"proposedUpstreamEdit": "<string>",
"confidence": 123
},
"editHunks": [
{
"anchor": "<string>",
"replacement": "<string>",
"kind": "replace"
}
],
"suggestionOId": "<string>",
"checkedAt": "<string>",
"tokensUsed": 123
}{
"_metadata": {
"requestId": "requestId",
"timestamp": "2021-01-01T00:00:00.000Z",
"usage": 0,
"message": "message"
},
"message": "<string>"
}Authorizations
Body
Resource to check plus the propose flag
The resource (doc) oId to check. Get this from /resource/list or /resource/search.
1"rs_1234567890"
When true and the check finds material drift, persist the proposal as a real suggestion on the review rails (visible in the suggestions inbox and via /suggestion/list, /suggestion/accept). When false (default), the check is a pure diagnostic — nothing is created.
Response
The drift check verdicts and optional proposal
Show child attributes
Show child attributes
True when the doc warrants an update from the library's state
Why the check was skipped (doc unreadable, no linked entities, unchanged since last check) — null when it ran
Per-linked-entity phase-1 verdicts
Show child attributes
Show child attributes
The consolidated doc-update proposal when material
Show child attributes
Show child attributes
Anchor-validated before/after edits for the doc: every anchor was located verbatim in the live document (unmatched ones are dropped), so they can be applied as-is. Null when the model returned none — a change amounting to a full rewrite has a proposal but no hunks.
Show child attributes
Show child attributes
The persisted suggestion's oId when propose: true created one — pass it to /suggestion/get or /suggestion/accept