You are connected to a Synap pod at {SYNAP_POD_URL}. You have sovereign,
structured, persistent memory backed by PostgreSQL, Typesense full-text search,
and pgvector semantic search. Your user ID is {SYNAP_AGENT_USER_ID} and your
workspace is {SYNAP_WORKSPACE_ID}.
You can do three things with Synap:
Every write goes through governance — some auto-approve, others create proposals for the user to review. You never lose data. You never need to organize it.
text
SYNAP_HUB_API_KEY = hub_xxxx
SYNAP_CONFIG_URL = https://pod.synap.live/trpc/intelligenceRegistry.getServiceConfig
Config is auto-fetched on startup. No restart needed.
text
SYNAP_HUB_API_KEY = hub_xxxx
SYNAP_POD_URL = https://pod.synap.live
SYNAP_WORKSPACE_ID = <uuid>
SYNAP_AGENT_USER_ID = <uuid>
All calls: Authorization: Bearer {SYNAP_HUB_API_KEY} + Content-Type: application/json.
Key must have hub-protocol.read AND hub-protocol.write scopes.
Typed objects with properties and relationships. The fundamental unit of knowledge.
ProfileUse forKey PropertiesnoteUnstructured knowledgecontent, tagstaskActionable work itemsstatus, priority, dueDateprojectGroupingsstatus, tagseventTime-bound occurrencesstartDate, endDate, locationpersonIndividualsemail, phonecontactBusiness contactsrole (extends person)companyOrganizationswebsite, industrydealSales opportunitiesstage, value, closeDatebookmarkWeb referencesurl, domainarticlePublished contentauthor, publishedAt
Extend profiles: a "lead" extends person, a "webinar" extends event.
Use GET /api/hub/profiles to discover types. Use POST /api/hub/profiles to create new ones.
Long-form Markdown. Reports, summaries, specs, meeting notes.
Atomic knowledge that persists across sessions. "Marc prefers email over Slack."
Typed connections between entities. Types: related, parent, child, belongs-to.
SituationActionPrimitive"Remember that Marc prefers email"POST /api/hub/memoryFact"Create a task to follow up"POST /api/hub/entitiesEntity"Write a meeting summary"POST /api/hub/documentsDocument"Marc works at Acme Corp"Create person + company, then POST /api/hub/relationsRelation"What do I know about Marc?"GET /api/hub/search?query=MarcSearch"Someone texted me on Telegram"POST /api/hub/threads + POST .../messagesRelay
ALWAYS search before creating to prevent duplicates.
{ "status": "approved" } — executed{ "status": "proposed", "proposalId": "..." } — queued for user approval (tell user, don't retry){ "status": "denied" } — blocked (respect, don't retry)Base URL: {SYNAP_POD_URL}/api/hub
Auth: Authorization: Bearer {SYNAP_HUB_API_KEY}
text
GET /api/hub/search?userId={UID}&workspaceId={WID}&query=Marc&limit=10
GET /api/hub/entities/<id>?userId={UID}&workspaceId={WID}
GET /api/hub/users/{UID}/entities?workspaceId={WID}&type=task&limit=50
GET /api/hub/documents/<id>?userId={UID}
GET /api/hub/profiles?userId={UID}&workspaceId={WID}
GET /api/hub/relations?userId={UID}&workspaceId={WID}&entityId=<id>
GET /api/hub/users/{UID}/context?workspaceId={WID}
GET /api/hub/graph/traverse?userId={UID}&startEntityId=<id>&maxDepth=2
text
POST /api/hub/memory
{ "userId": "{UID}", "fact": "Marc prefers email", "confidence": 0.9 }
# embedding is optional — server handles it
GET /api/hub/memory?userId={UID}&query=Marc+preferences&limit=10
DELETE /api/hub/memory/<fact-id>?userId={UID}
text
POST /api/hub/entities
{
"userId": "{UID}", "agentUserId": "{UID}", "workspaceId": "{WID}",
"profileSlug": "task", "title": "Follow up with Marc",
"properties": { "status": "todo", "priority": "high", "dueDate": "2026-04-10" },
"reasoning": "User asked to track follow-up"
}
PATCH /api/hub/entities/<id>
{ "userId": "{UID}", "agentUserId": "{UID}", "workspaceId": "{WID}",
"properties": { "status": "done" }, "reasoning": "Task completed" }
POST /api/hub/documents
{ "userId": "{UID}", "agentUserId": "{UID}", "workspaceId": "{WID}",
"title": "Meeting Notes", "content": "# Meeting\n\n...", "reasoning": "..." }
POST /api/hub/relations
{ "userId": "{UID}", "agentUserId": "{UID}", "workspaceId": "{WID}",
"sourceEntityId": "<id>", "targetEntityId": "<id>", "type": "related",
"reasoning": "Marc works at Acme Corp" }
DELETE /api/hub/relations/<id>
{ "userId": "{UID}", "agentUserId": "{UID}", "workspaceId": "{WID}" }
POST /api/hub/profiles
{ "userId": "{UID}", "workspaceId": "{WID}", "name": "Lead", "slug": "lead",
"parentProfileId": "<uuid>", "description": "Sales lead" }
POST /api/hub/property-defs
{ "userId": "{UID}", "workspaceId": "{WID}", "profileId": "<uuid>",
"name": "Company", "slug": "company", "valueType": "string" }
Property value types: string, number, boolean, date, entity_id, array, object, secret.
When a message arrives from Telegram, WhatsApp, Slack, or another platform:
Step 1: Create or reuse a thread:
text
POST /api/hub/threads
{ "userId": "{UID}", "workspaceId": "{WID}", "title": "Telegram: Alice" }
Step 2: Post the message (with autoRespond: true to trigger Synap AI):
text
POST /api/hub/threads/<thread-id>/messages
{ "role": "user", "content": "Hey are you free today?",
"userId": "{UID}", "autoRespond": true }
Step 3: Poll for AI response:
text
GET /api/hub/threads/<thread-id>/messages
Filter for role: "assistant" messages after your timestamp. Poll every 3s, max 45s.
Same thread/message endpoints. Post with autoRespond: true, poll for response.
text
GET /api/hub/threads?userId={UID}&workspaceId={WID}
POST /api/hub/threads/<id>/messages
GET /api/hub/threads/<id>/messages
StatusMeaningAction200SuccessProcess normally401Invalid API keyCheck SYNAP_HUB_API_KEY403Insufficient scopesKey needs read + write404Not foundEntity/document doesn't exist429Rate limitedWait 60 seconds500Server errorRetry once after 30s
"proposed" and "denied" in response body are NOT errors — they're governance.
person not note, company not bookmark."reasoning". Creates audit trail.person, "webinar" extends event.PathStatus~/openclaw/workspace/**Auto-approved~/projects/**Proposal required~/synap-backend/**, .envBLOCKED — never accessible/etc/**, /usr/**, /bin/**BLOCKED — system paths
synap v1.0.0 — github.com/synap-core/backend/tree/main/skills/synap