Create or replay a portable memory candidate
curl --request POST \
--url https://api.praxa.io/v1/memory/records \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"apiVersion": {},
"providerId": {},
"sourceId": "<string>",
"externalRecordId": "<string>",
"revision": "<string>",
"kind": {},
"subject": "<string>",
"visibility": {},
"content": "<string>",
"provenance.origin": {},
"provenance.confidence": 123,
"provenance.capturedAt": "<string>",
"occurredAt": "<string>",
"observedAt": "<string>"
}
'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
apiVersion: {},
providerId: {},
sourceId: '<string>',
externalRecordId: '<string>',
revision: '<string>',
kind: {},
subject: '<string>',
visibility: {},
content: '<string>',
'provenance.origin': {},
'provenance.confidence': 123,
'provenance.capturedAt': '<string>',
occurredAt: '<string>',
observedAt: '<string>'
})
};
fetch('https://api.praxa.io/v1/memory/records', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.praxa.io/v1/memory/records"
payload = {
"apiVersion": {},
"providerId": {},
"sourceId": "<string>",
"externalRecordId": "<string>",
"revision": "<string>",
"kind": {},
"subject": "<string>",
"visibility": {},
"content": "<string>",
"provenance.origin": {},
"provenance.confidence": 123,
"provenance.capturedAt": "<string>",
"occurredAt": "<string>",
"observedAt": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"apiVersion": "v1",
"replayed": false,
"candidate": {
"id": "018f0000-0000-7000-8000-000000000001",
"state": "candidate",
"contentDigest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"createdAt": "2026-08-13T12:00:00.000Z",
"record": {
"apiVersion": "v1",
"providerId": "custom",
"sourceId": "customer-profile",
"externalRecordId": "preference-42",
"revision": "revision-1",
"kind": "fact",
"subject": "customer-42",
"visibility": "subject",
"content": "Prefers concise weekly summaries.",
"metadata": {
"category": "communication-preference"
},
"provenance": {
"origin": "explicit",
"confidence": 1,
"capturedAt": "2026-08-13T12:00:00.000Z",
"evidenceIds": [],
"metadata": {}
},
"occurredAt": "2026-08-13T12:00:00.000Z",
"observedAt": "2026-08-13T12:00:00.000Z",
"originChain": []
}
}
}
Memory candidates
Create or replay a portable memory candidate
Create or exactly replay one isolated, subject-scoped Praxa memory candidate with portable provenance and no first-party memory promotion.
POST
/
v1
/
memory
/
records
Create or replay a portable memory candidate
curl --request POST \
--url https://api.praxa.io/v1/memory/records \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--header 'Idempotency-Key: <idempotency-key>' \
--data '
{
"apiVersion": {},
"providerId": {},
"sourceId": "<string>",
"externalRecordId": "<string>",
"revision": "<string>",
"kind": {},
"subject": "<string>",
"visibility": {},
"content": "<string>",
"provenance.origin": {},
"provenance.confidence": 123,
"provenance.capturedAt": "<string>",
"occurredAt": "<string>",
"observedAt": "<string>"
}
'const options = {
method: 'POST',
headers: {
'Idempotency-Key': '<idempotency-key>',
Authorization: 'Bearer <token>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
apiVersion: {},
providerId: {},
sourceId: '<string>',
externalRecordId: '<string>',
revision: '<string>',
kind: {},
subject: '<string>',
visibility: {},
content: '<string>',
'provenance.origin': {},
'provenance.confidence': 123,
'provenance.capturedAt': '<string>',
occurredAt: '<string>',
observedAt: '<string>'
})
};
fetch('https://api.praxa.io/v1/memory/records', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://api.praxa.io/v1/memory/records"
payload = {
"apiVersion": {},
"providerId": {},
"sourceId": "<string>",
"externalRecordId": "<string>",
"revision": "<string>",
"kind": {},
"subject": "<string>",
"visibility": {},
"content": "<string>",
"provenance.origin": {},
"provenance.confidence": 123,
"provenance.capturedAt": "<string>",
"occurredAt": "<string>",
"observedAt": "<string>"
}
headers = {
"Idempotency-Key": "<idempotency-key>",
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"apiVersion": "v1",
"replayed": false,
"candidate": {
"id": "018f0000-0000-7000-8000-000000000001",
"state": "candidate",
"contentDigest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"createdAt": "2026-08-13T12:00:00.000Z",
"record": {
"apiVersion": "v1",
"providerId": "custom",
"sourceId": "customer-profile",
"externalRecordId": "preference-42",
"revision": "revision-1",
"kind": "fact",
"subject": "customer-42",
"visibility": "subject",
"content": "Prefers concise weekly summaries.",
"metadata": {
"category": "communication-preference"
},
"provenance": {
"origin": "explicit",
"confidence": 1,
"capturedAt": "2026-08-13T12:00:00.000Z",
"evidenceIds": [],
"metadata": {}
},
"occurredAt": "2026-08-13T12:00:00.000Z",
"observedAt": "2026-08-13T12:00:00.000Z",
"originChain": []
}
}
}
Create or exactly replay one isolated, subject-scoped Praxa memory candidate with portable provenance and no first-party memory promotion.
Availability: Qualification preview. Required scope:
memory:write.Authenticate safely
Create a disposable personal workspace API key with exactlymemory:write. Send it as Authorization: Bearer $PRAXA_API_KEY. A Gateway OAuth token, Supabase JWT, provider credential, or organization memory key is not interchangeable with this key.
The hosted playground sends the credential from your browser session to the documented API through the configured playground proxy. Use test data, never share the key, and revoke it when the check ends.
Request fields
string
required
Stable key for one logical mutation. Reuse only with the exact same request; changed input under the same key returns a conflict.
v1
required
apiVersion request field.
mem0 | zep | graphiti | langgraph | letta | openai_agents | custom
required
providerId request field.
string
required
sourceId request field.
string
required
externalRecordId request field.
string
required
revision request field.
message | fact | summary | episode | pinned_context | document | entity | edge
required
kind request field.
string
required
subject request field.
subject
required
visibility request field.
string
required
content request field.
string
agentId request field.
string
threadId request field.
string
workspaceId request field.
string
purpose request field.
object
metadata request field.
explicit | observed | inferred | imported
required
provenance.origin request field.
number
required
provenance.confidence request field.
string
required
provenance.capturedAt request field.
string
provenance.sourceUrl request field.
array<string>
provenance.evidenceIds request field.
object
provenance.metadata request field.
string
required
occurredAt request field.
string
required
observedAt request field.
string
expiresAt request field.
array<string>
originChain request field.
Runnable request examples
curl --fail-with-body -X POST 'https://api.praxa.io/v1/memory/records' \
-H "Authorization: Bearer $PRAXA_API_KEY" \
-H "Idempotency-Key: playground-create-memory-candidate-0001" \
-H "Content-Type: application/json" \
--data '{
"apiVersion": "v1",
"providerId": "custom",
"sourceId": "customer-profile",
"externalRecordId": "preference-42",
"revision": "revision-1",
"kind": "fact",
"subject": "customer-42",
"visibility": "subject",
"content": "Prefers concise weekly summaries.",
"metadata": {
"category": "communication-preference"
},
"provenance": {
"origin": "explicit",
"confidence": 1,
"capturedAt": "2026-08-13T12:00:00.000Z",
"evidenceIds": [],
"metadata": {}
},
"occurredAt": "2026-08-13T12:00:00.000Z",
"observedAt": "2026-08-13T12:00:00.000Z",
"originChain": []
}'
const response = await fetch("https://api.praxa.io/v1/memory/records", {
"method": "POST",
"headers": {
"Authorization": `Bearer ${process.env.PRAXA_API_KEY}`,
"Idempotency-Key": "playground-create-memory-candidate-0001",
"Content-Type": "application/json"
},
"body": JSON.stringify({
"apiVersion": "v1",
"providerId": "custom",
"sourceId": "customer-profile",
"externalRecordId": "preference-42",
"revision": "revision-1",
"kind": "fact",
"subject": "customer-42",
"visibility": "subject",
"content": "Prefers concise weekly summaries.",
"metadata": {
"category": "communication-preference"
},
"provenance": {
"origin": "explicit",
"confidence": 1,
"capturedAt": "2026-08-13T12:00:00.000Z",
"evidenceIds": [],
"metadata": {}
},
"occurredAt": "2026-08-13T12:00:00.000Z",
"observedAt": "2026-08-13T12:00:00.000Z",
"originChain": []
})
});
const text = await response.text();
if (!response.ok) throw new Error(`${response.status}: ${text}`);
console.log(text ? JSON.parse(text) : { status: response.status });
import json
import os
from urllib import error, request
payload = json.dumps({
"apiVersion": "v1",
"providerId": "custom",
"sourceId": "customer-profile",
"externalRecordId": "preference-42",
"revision": "revision-1",
"kind": "fact",
"subject": "customer-42",
"visibility": "subject",
"content": "Prefers concise weekly summaries.",
"metadata": {
"category": "communication-preference"
},
"provenance": {
"origin": "explicit",
"confidence": 1,
"capturedAt": "2026-08-13T12:00:00.000Z",
"evidenceIds": [],
"metadata": {}
},
"occurredAt": "2026-08-13T12:00:00.000Z",
"observedAt": "2026-08-13T12:00:00.000Z",
"originChain": []
}).encode()
req = request.Request(
"https://api.praxa.io/v1/memory/records",
method="POST",
headers={
"Authorization": f"Bearer {os.environ['PRAXA_API_KEY']}",
"Idempotency-Key": "playground-create-memory-candidate-0001",
"Content-Type": "application/json"
},
data=payload,
)
try:
with request.urlopen(req, timeout=30) as response:
text = response.read().decode()
print(json.loads(text) if text else {"status": response.status})
except error.HTTPError as exc:
raise RuntimeError(f"{exc.code}: {exc.read().decode()}") from exc
What success means
A201 response created a candidate; 200 means the same idempotent request was replayed. Neither promotes content into Praxa personal memory.
Successful response
201 — A new candidate was created.v1
required
apiVersion response field.
boolean
required
replayed response field.
object
required
candidate response field.
{
"apiVersion": "v1",
"replayed": false,
"candidate": {
"id": "018f0000-0000-7000-8000-000000000001",
"state": "candidate",
"contentDigest": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
"createdAt": "2026-08-13T12:00:00.000Z",
"record": {
"apiVersion": "v1",
"providerId": "custom",
"sourceId": "customer-profile",
"externalRecordId": "preference-42",
"revision": "revision-1",
"kind": "fact",
"subject": "customer-42",
"visibility": "subject",
"content": "Prefers concise weekly summaries.",
"metadata": {
"category": "communication-preference"
},
"provenance": {
"origin": "explicit",
"confidence": 1,
"capturedAt": "2026-08-13T12:00:00.000Z",
"evidenceIds": [],
"metadata": {}
},
"occurredAt": "2026-08-13T12:00:00.000Z",
"observedAt": "2026-08-13T12:00:00.000Z",
"originChain": []
}
}
}
Handle failures
| Response | Meaning | Safe action |
|---|---|---|
400 invalid_request | The method, path, headers, query, or body failed strict validation. | Correct the request; do not retry unchanged input. |
401 authentication_failed | The bearer key is missing, malformed, expired, or revoked. | Stop and replace the key through the authenticated console. |
403 authorization_failed | The authenticated key lacks scope or tenant authority. | Request only the missing least-privilege scope; never substitute another tenant ID. |
409 conflict | The same idempotency key was paired with different logical input or state. | Restore the original body or create a key for a genuinely new operation. |
429 rate_limited | The principal exceeded a bounded rate. | Honor retryAfterMs or Retry-After, add jitter, and cap attempts. |
retryable 5xx | The server could not confirm a final response. | Reconcile reads or replay the exact keyed mutation before creating new work. |
Example problem
{
"type": "https://docs.praxa.io/problems/authorization-failed",
"title": "Authorization failed",
"status": 403,
"code": "authorization_failed",
"detail": "The API key does not grant the required scope.",
"retryable": false
}
Verify the result
- Save the candidate ID and require
replayed: falseon first create. - Query the exact subject and require lexical retrieval only.
- Replay the exact body/key and require the same candidate with
replayed: true.
Retry, cleanup, and production use
- Treat
401,403, and409as authority or state signals, not generic retry prompts. - Reuse the idempotency key only for an exact retry of the same logical mutation.
- For
429or retryable 5xx responses, follow server retry guidance and keep a bounded attempt budget. - Move the request into a trusted application backend before production; never ship the Praxa key in browser or mobile code.
- Revoke the disposable key, disable test webhooks, and erase disposable candidate data after validation.
Last modified on August 14, 2026