curl --request POST \
--url https://app.sapientpriors.com/api/v1/agents/{agent_id}/threads/{thread_id}/observe \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"observations": [
{
"content": [
{
"type": "text",
"text": "The service keeps restarting after I build the image."
}
],
"timestamp": "2026-07-16T12:02:00Z",
"tags": [
"user"
]
},
{
"content": [
{
"type": "text",
"text": "docker compose ps shows api exited with code 1."
}
],
"timestamp": "2026-07-16T12:03:00Z",
"tags": [
"environment",
"terminal"
]
}
]
}
'import requests
url = "https://app.sapientpriors.com/api/v1/agents/{agent_id}/threads/{thread_id}/observe"
payload = { "observations": [
{
"content": [
{
"type": "text",
"text": "The service keeps restarting after I build the image."
}
],
"timestamp": "2026-07-16T12:02:00Z",
"tags": ["user"]
},
{
"content": [
{
"type": "text",
"text": "docker compose ps shows api exited with code 1."
}
],
"timestamp": "2026-07-16T12:03:00Z",
"tags": ["environment", "terminal"]
}
] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
observations: [
{
content: [{type: 'text', text: 'The service keeps restarting after I build the image.'}],
timestamp: '2026-07-16T12:02:00Z',
tags: ['user']
},
{
content: [{type: 'text', text: 'docker compose ps shows api exited with code 1.'}],
timestamp: '2026-07-16T12:03:00Z',
tags: ['environment', 'terminal']
}
]
})
};
fetch('https://app.sapientpriors.com/api/v1/agents/{agent_id}/threads/{thread_id}/observe', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"agent_id": "agent_01JZ8X9K6AS3V8SGP0Q9A2P4FH",
"thread_id": "thread_01JZ8XASKN4R1HXV4X19A3T02J",
"observation_id": "obs_01JZ8XQ8JQZNQDRG6EB7N1M3PV",
"accepted": true
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}Observe thread observations
Asynchronously observes one or more observations for this thread. Use the same endpoint for a single new observation or for bulk ingestion of existing thread history. Today every content block is text.
Ordering: observations are processed in per-thread FIFO order by the time Priors received them. Within a single request, the order of the observations array is preserved exactly. Two requests that are in flight concurrently to the same thread have undefined relative order — await the acknowledgement for one request before sending the next if strict ordering across requests matters. For bulk history, prefer a single request containing the ordered array, which is the only way to guarantee ordering deterministically.
This call is fire-and-forget: a 202 means the observations were accepted for processing, not that they are committed to memory. Poll the observation status endpoint to follow progress.
curl --request POST \
--url https://app.sapientpriors.com/api/v1/agents/{agent_id}/threads/{thread_id}/observe \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"observations": [
{
"content": [
{
"type": "text",
"text": "The service keeps restarting after I build the image."
}
],
"timestamp": "2026-07-16T12:02:00Z",
"tags": [
"user"
]
},
{
"content": [
{
"type": "text",
"text": "docker compose ps shows api exited with code 1."
}
],
"timestamp": "2026-07-16T12:03:00Z",
"tags": [
"environment",
"terminal"
]
}
]
}
'import requests
url = "https://app.sapientpriors.com/api/v1/agents/{agent_id}/threads/{thread_id}/observe"
payload = { "observations": [
{
"content": [
{
"type": "text",
"text": "The service keeps restarting after I build the image."
}
],
"timestamp": "2026-07-16T12:02:00Z",
"tags": ["user"]
},
{
"content": [
{
"type": "text",
"text": "docker compose ps shows api exited with code 1."
}
],
"timestamp": "2026-07-16T12:03:00Z",
"tags": ["environment", "terminal"]
}
] }
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
observations: [
{
content: [{type: 'text', text: 'The service keeps restarting after I build the image.'}],
timestamp: '2026-07-16T12:02:00Z',
tags: ['user']
},
{
content: [{type: 'text', text: 'docker compose ps shows api exited with code 1.'}],
timestamp: '2026-07-16T12:03:00Z',
tags: ['environment', 'terminal']
}
]
})
};
fetch('https://app.sapientpriors.com/api/v1/agents/{agent_id}/threads/{thread_id}/observe', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));{
"agent_id": "agent_01JZ8X9K6AS3V8SGP0Q9A2P4FH",
"thread_id": "thread_01JZ8XASKN4R1HXV4X19A3T02J",
"observation_id": "obs_01JZ8XQ8JQZNQDRG6EB7N1M3PV",
"accepted": true
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}{
"error": "<string>",
"code": "<string>",
"request_id": "<string>",
"details": "<string>"
}Authorizations
Your API key, shaped sp_<key_id>_<secret>, sent as Authorization: Bearer sp_.... It identifies your organization, not a person. Your organization owns the agents, holds the credit, and is billed. Every key your organization holds reaches the same things, so you rotate a key by minting the new one, deploying it, and revoking the old one.
Keep the key on your server. A request that carries a Sec-Fetch-Site header is refused with 400, because only a browser sets that header. Priors sends no CORS headers, so a browser blocks the call before it leaves the page. The secret is shown once when the key is minted and is stored only as a hash. A lost secret is replaced, never recovered.
An administrator of your organization mints and revokes keys in the Priors application, under Settings. There is no endpoint for it: a key reaches your whole organization, so issuing one is an act of administration.
Headers
Your own identifier for the person this request acts for: an account number, a row id, anything stable on your side. It works only with a partner API key. The value is not stored. Priors hashes it together with your organization id, so two clients that send the same string are still two different people.
With the header, you reach the threads that same person created and no others. A new thread is recorded against that person, and GET /v1/agents/{agent_id} returns that person's conversations only. Without the header, the key acts as the organization and reaches every thread on every agent it owns. Learned memory is shared across the agent either way. Only the thread list narrows.
Sent with anything that is not a partner API key, the header returns 400 instead of being ignored. Sent empty or as whitespace, it also returns 400, and it is never read as absent: absent means the whole organization, which is wider access than you asked for. Surrounding whitespace is removed. The 255-character limit is measured on the value as sent.
1 - 255\SPath Parameters
Unique managed memory-agent identifier.
32^agent_[0-9A-HJKMNP-TV-Z]{26}$Unique thread identifier scoped to the agent.
33^thread_[0-9A-HJKMNP-TV-Z]{26}$Body
One or more observations. A single item represents real-time observation; multiple observations represent history or bulk ingestion. Array order is preserved exactly and is the only deterministic way to order a batch.
1 - 100 elementsShow child attributes
Show child attributes
Response
Observation request accepted for asynchronous processing
Server-generated agent identifier.
^agent_[0-9A-HJKMNP-TV-Z]{26}$Server-generated thread identifier.
^thread_[0-9A-HJKMNP-TV-Z]{26}$Server-issued identifier for the asynchronous observation request. Pass it to the observation status endpoint to follow progress.
^obs_[0-9A-HJKMNP-TV-Z]{26}$