Entities
The Entities operations of the Hub REST API (17 operations).
bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
userId*stringThe caller's own user id, or me.
profileSlug?stringtype?stringDeprecated alias for profileSlug.
workspaceId?stringprojectId?stringProject lens: only the project and what is filed into it.
facetSlug?stringOnly entities carrying a live facet of this role (e.g. client).
limit?stringArray of entities
application/json- response
[index: integer]?curl -X GET 'https://pod.example.com/api/hub/users/string/entities'[ { "property1": null, "property2": null }]bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
Counts by kind
application/json- response
total*integerbyProfile*array<>curl -X GET 'https://pod.example.com/api/hub/entities/without-project/counts'{ "total": 0, "byProfile": [ { "profileSlug": "string", "count": 0 } ]}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
q?stringFree-text search query. Refused (403 GRANT_DOOR_UNSUPPORTED) for a scoped key: search is not bounded by a grant. List without q instead.
profileSlug?stringworkspaceId?stringprojectId?stringProject lens — narrows results to a single project's data (the project entity + everything that belongs_to it). Pure-narrowing; cannot widen access past the user floor.
withoutProject?stringtrue = only the things filed into NO project (the 'Not in a project' list). 400 with projectId or q. Counts by kind: GET /entities/without-project/counts.
"true""false"limit?stringoffset?stringZero-based offset for cursor-free pagination (default 0).
sort?stringe.g. updatedAt:desc.
scope?stringpod = pod-wide entities only (null workspaceId); workspace = single workspace (requires workspaceId); all = merge across all accessible workspaces.
"pod""workspace""all"includePodWide?stringWhen a workspaceId is supplied, include pod-wide (null workspaceId) globals in the result. Defaults to true so a workspace lens returns 'that workspace + pod-wide globals' — the behavior agents and the CRM expect. Set false to return only the exact workspace's rows.
facetSlug?stringKind + Facets filter — only return entities carrying a live facet of this role-profile slug (e.g. investor).
facetProfileId?stringSame as facetSlug but by profile id. Wins if both are set.
createdAfter?stringCreation-date window, INCLUSIVE lower bound (ISO-8601). Together with createdBefore forms the half-open interval [createdAfter, createdBefore), so consecutive windows tile. Rejected with 400 when combined with q — see createdBefore.
createdBefore?stringCreation-date window, EXCLUSIVE upper bound (ISO-8601). NOT combinable with q: the q branch is a relevance-ranked top-N served by Typesense, and a date window is an exhaustive question, so silently truncating one to the other would under-report. Ask for the window without q.
Array of entities
application/json- response
[index: integer]?curl -X GET 'https://pod.example.com/api/hub/entities'[ { "id": "string", "profileSlug": "string", "type": "string", "title": "string", "preview": "string", "description": "string", "properties": { "property1": null, "property2": null }, "systemData": { "property1": null, "property2": null }, "userId": "string", "workspaceId": "string", "documentId": "string", "version": 0, "createdAt": "string", "updatedAt": "string" }]bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
application/json- body
userId?stringOwner of the entity. Defaults to the authenticated user.
agentUserId?stringAgent user that performed the write. Used for proposal authorship.
workspaceId?stringTarget workspace. Falls back to profile.entityScope and the user's first accessible workspace.
projectId?stringFile the new entity into a project (its entity id). Stamps a belongs_to_project edge at materialization, so project-scoped recall (ask with projectId) finds it. Orthogonal to workspaceId.
profileSlug?stringProfile slug. Provide profileSlug, profileId, or the deprecated type alias.
profileId?stringProfile UUID. Resolved to the profile's slug server-side; takes precedence over profileSlug/type.
uuidtype?stringDeprecated alias for profileSlug. Prefer profileSlug.
title*stringdescription?stringproperties?content?stringLong-form markdown body. When set, a linked, versioned document is created (MinIO-stored) instead of inlining into properties.
reasoning?stringThe proposing agent's rationale for this action, surfaced in the proposal inbox.
source?stringOrigin signal for downstream attribution.
"intelligence""agent""openwebui-pipeline""extension""cli""n8n""raycast"sourceMessageId?stringOptional message ID that triggered this write (for event chain causality).
sessionId?stringOptional session ID to link proposals created by this write to an active focus session.
facets?array<>Kind + Facets: role-profiles to attach to the new entity in the same call (each via the governed attachFacet door). Applied only when the entity materializes. slug is canonical; profileSlug is accepted as an alias for parity with the /structure and tRPC facet shapes.
forceCreate?booleanBypass the weak same-name create gate when a same-profile entity with this title already exists. Prefer reusing the existing id. Does not bypass strong-signal auto-merge (email/phone/url).
externalId?stringStrong cross-source identity anchor for this subject, as provider:id (e.g. discord:123456789012345678). Registered as an external_id identity signal so a later create with the SAME value auto-resolves to the same entity (dedup) instead of minting a duplicate — the strong atom that the weak email/phone/url auto-extraction cannot express for opaque connector ids. Opaque and case-sensitive; the provider prefix namespaces the id.
expectedLabel?stringThe declared session-output slot this entity fulfils, exactly as declared on the session's expected outputs. Left unset when the create doesn't fulfil a specific declared slot.
Created entity (with effectiveWorkspaceId echo)
application/json- response
status*stringe.g. 'created' or 'proposed'.
message?stringid?stringproposalId?string|nullproposedEntityId?string|nullworkspaceId?string|nulleffectiveWorkspaceId*|Workspace the entity actually landed in. May be null for pod-wide profiles.
proposalType?stringPresent when status is "proposed". "join" for a workspace-join gate, else "." (e.g. "entity.create").
reviewUrl?stringPresent when status is "proposed". Absolute URL to review the proposal in the Studio.
deferred?trueWorkspace-join gate only (proposalType "join"): this write was KEPT on the join request and is replayed for you once the join is approved — do not resend it.
trueref?stringWith deferred: the kept write's ref on the join proposal.
facets?array<>Kind + Facets: per-role attach outcome for any facets passed in the request (status attached/proposed/error).
writeReceipt?curl -X POST 'https://pod.example.com/api/hub/entities' \ -H 'Content-Type: application/json' \ -d '{ "title": "string"}'{ "status": "string", "message": "string", "id": "string", "proposalId": "string", "proposedEntityId": "string", "workspaceId": "string", "effectiveWorkspaceId": "string", "proposalType": "string", "reviewUrl": "string", "deferred": true, "ref": "string", "facets": [ { "slug": "string", "status": "string", "facetId": "string", "proposalId": "string", "error": "string" } ], "writeReceipt": { "state": "pending", "proposalId": "string", "reviewUrl": "string", "entityId": "string", "proposedEntityId": "string", "profileSlug": "string", "effectiveWorkspaceId": "string", "projectId": "string", "source": "string", "facets": [ { "slug": "string", "outcome": "string", "facetId": "string", "proposalId": "string", "error": "string" } ], "warnings": [ "string" ], "properties": { "unmodeled": [ { "key": "string", "didYouMean": "string" } ] } }}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
id*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuiduserId?stringworkspaceId?stringlimit?stringRelations list with summary counts
application/json- response
[key: string]?unknowncurl -X GET 'https://pod.example.com/api/hub/entities/497f6eca-6276-4993-bfeb-53cbbbba6f08/connections'{ "property1": null, "property2": null}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
id*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuiduserId?stringCanonical entity wire record
application/json- response
id*stringprofileSlug*stringtype*stringtitle?string|nullpreview?string|nulldescription?string|nullproperties*systemData?userId*stringworkspaceId?string|nulldocumentId?string|nullversion?numbercreatedAt?string|updatedAt?string|curl -X GET 'https://pod.example.com/api/hub/entities/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "id": "string", "profileSlug": "string", "type": "string", "title": "string", "preview": "string", "description": "string", "properties": { "property1": null, "property2": null }, "systemData": { "property1": null, "property2": null }, "userId": "string", "workspaceId": "string", "documentId": "string", "version": 0, "createdAt": "string", "updatedAt": "string"}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
application/json- body
query*string1 <= lengthprofileSlug?stringworkspaceId?stringlimit?integer1 <= value <= 100Merged entity results
application/json- response
entities*array<>source*string"hybrid""typesense"curl -X POST 'https://pod.example.com/api/hub/entities/recall' \ -H 'Content-Type: application/json' \ -d '{ "query": "string"}'{ "entities": [ { "property1": null, "property2": null } ], "source": "hybrid"}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
application/json- body
query*string1 <= lengthworkspaceId?stringlimit?integer1 <= value <= 100Ranked entities + retrieval understanding
application/json- response
entities*array<>understanding*source*string"hybrid""typesense"verdict*string"confident""ambiguous""empty"curl -X POST 'https://pod.example.com/api/hub/entities/retrieve' \ -H 'Content-Type: application/json' \ -d '{ "query": "string"}'{ "entities": [ { "property1": null, "property2": null } ], "understanding": { "property1": null, "property2": null }, "source": "hybrid", "verdict": "confident"}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
entityId*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuidapplication/json- body
userId?stringworkspaceId?stringfilename?string1 <= lengthmimeType?string1 <= lengthcontentBase64?string1 <= lengthfileEntityId?stringCreated file entity + link result
application/json- response
[key: string]?unknowncurl -X POST 'https://pod.example.com/api/hub/entities/497f6eca-6276-4993-bfeb-53cbbbba6f08/attachments' \ -H 'Content-Type: application/json' \ -d '{}'{ "property1": null, "property2": null}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
application/json- body
userId?stringagentUserId?stringuuidworkspaceId?stringuuidsessionId?stringuuiditems*array<>1 <= items <= 500idempotencyKey?stringvalidate?booleanreasoning?stringPer-item receipt: applied / proposed (one pack) / denied / skipped
application/json- response
[key: string]?unknowncurl -X POST 'https://pod.example.com/api/hub/entities/batch-update' \ -H 'Content-Type: application/json' \ -d '{ "items": [ { "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08", "patch": { "property1": null, "property2": null } } ]}'{ "property1": null, "property2": null}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
entityId*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuidapplication/json- body
userId?stringagentUserId?stringworkspaceId?string|nulltitle?stringpreview?stringmetadata?deleteProperties?array<string>reasoning?stringThe proposing agent's rationale for this update, surfaced in the proposal inbox.
sourceMessageId?stringsessionId?stringexpectedStatus?|Compare-and-set on the status: the status you SAW. If it moved meanwhile the call answers 409 with the current status and writes nothing.
Updated entity
application/json- response
status*stringmessage?stringproposalId?string|nullsummary?stringreasoning?stringreviewPath?stringreviewUrl?stringdeferred?trueWorkspace-join gate only (proposalType "join"): this write was KEPT on the join request and is replayed for you once the join is approved — do not resend it.
trueref?stringWith deferred: the kept write's ref on the join proposal.
curl -X PATCH 'https://pod.example.com/api/hub/entities/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{}'{ "status": "string", "message": "string", "proposalId": "string", "summary": "string", "reasoning": "string", "reviewPath": "string", "reviewUrl": "string", "deferred": true, "ref": "string"}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
entityId*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuidworkspaceId?stringuserId?stringreasoning?stringagentUserId?stringDeletion result (completed or proposed)
application/json- response
[key: string]?unknowncurl -X DELETE 'https://pod.example.com/api/hub/entities/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "property1": null, "property2": null}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
entityId*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuidEffective facets
application/json- response
facets*array<>curl -X GET 'https://pod.example.com/api/hub/entities/497f6eca-6276-4993-bfeb-53cbbbba6f08/facets'{ "facets": [ { "property1": null, "property2": null } ]}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
entityId*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuidapplication/json- body
userId?stringprofileSlug?stringprofileId?stringuuidworkspaceId?|uuidcontextEntityId?|uuidstatus?stringproperties?agentUserId?stringuuidreasoning?stringAttach result (or proposal envelope)
application/json- response
[key: string]?unknowncurl -X POST 'https://pod.example.com/api/hub/entities/497f6eca-6276-4993-bfeb-53cbbbba6f08/facets' \ -H 'Content-Type: application/json' \ -d '{}'{ "property1": null, "property2": null}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
facetId*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuidapplication/json- body
userId?stringstatus?stringproperties?workspaceId?|uuidagentUserId?stringuuidreasoning?stringexpectedStatus?|Compare-and-set on the role's status: the status you SAW. If it moved meanwhile the call answers 409 with the current status and writes nothing.
Update result (or proposal envelope)
application/json- response
[key: string]?unknowncurl -X PATCH 'https://pod.example.com/api/hub/facets/497f6eca-6276-4993-bfeb-53cbbbba6f08' \ -H 'Content-Type: application/json' \ -d '{}'{ "property1": null, "property2": null}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
facetId*string^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iuuiduserId?stringagentUserId?stringreasoning?stringDetach result (or proposal envelope)
application/json- response
[key: string]?unknowncurl -X DELETE 'https://pod.example.com/api/hub/facets/497f6eca-6276-4993-bfeb-53cbbbba6f08'{ "property1": null, "property2": null}bearerAuthAuthorizationBearer <API key>Pod API key (Bearer) issued via /api/hub/setup/agent or pod admin tooling. Browser/web clients may use the X-Session-Token header instead. See GET /api/hub/auth/status to introspect the calling key.
application/json- body
kindSlug?stringThe entity kind (profile slug) being created. A weak (same-name) match must be this kind to become match:'weak'; cross-kind rows still ride in candidates.
title?stringName/title to weak-match. Blank → strong-signal lookup only.
workspaceId?stringuuidsignals?Explicit strong identity atoms.
properties?Draft property bag — strong signals are also extracted from it (merged with signals).
Identity resolution result
application/json- response
match*string"strong""weak""none"entityId?stringentityTitle?string|nullentityKind?stringcandidates*array<>crossKindCandidates*array<>Same-title entities of a DIFFERENT kind. ADVISORY: match stays "none" because a title alone never auto-merges — but do NOT treat "none" as "safe to create" when this is non-empty. Prefer proposing a link to one of these over minting a duplicate.
pendingCandidates?array<>Strong-signal matches in YOUR OWN pending capture proposals — a duplicate already in-flight but not yet committed (so match is still "none"). ADVISORY: carries a proposalId, NEVER an entityId — do NOT link to it (it can still be rejected). Wait for review or revise, rather than filing a second copy.
curl -X POST 'https://pod.example.com/api/hub/identity/resolve' \ -H 'Content-Type: application/json' \ -d '{}'{ "match": "strong", "entityId": "string", "entityTitle": "string", "entityKind": "string", "candidates": [ { "entityId": "string", "title": "string", "kind": "string", "score": 0 } ], "crossKindCandidates": [ { "entityId": "string", "title": "string", "kind": "string" } ], "pendingCandidates": [ { "proposalId": "string", "proposalType": "string", "summary": "string", "entityRef": "string", "entityTitle": "string", "profileSlug": "string", "matchedSignals": [ { "type": "string", "value": "string" } ] } ]}