REST API reference
The hosted service at https://memory.neo4jlabs.com/v1 exposes a REST API.
This page is a curated companion to the machine-readable contract — it maps
selected endpoints to protocol operation names and client accessors. A protocol operation is not necessarily exposed as a public method in every SDK.
|
The authoritative, always-current contract is the OpenAPI document at memory.neo4jlabs.com/openapi.json (production). Request/response schemas live there; this page covers the cross-cutting rules — auth, versioning, errors, pagination — and the SDK-method mapping the spec doesn’t show. |
The protocol-operation column uses conformance names from the agent-memory-tck
cross-language conformance suite. Check the client accessor column rather than converting a protocol name to another casing. Python endpoint registry names can differ (for example, its message-list route uses list_messages, while its public method is short_term.get_conversation).
Base URL and protocol version
NAMS is an unversioned, continuously shipped service. /v1 identifies its REST protocol; it is independent of Python/TypeScript package versions. The production base URL is https://memory.neo4jlabs.com/v1. The SDK appends paths to the configured
MEMORY_ENDPOINT (default the URL above). The /v{n} prefix also selects the
REST transport; endpoints without it use the TCK bridge protocol (see
Bolt vs NAMS).
|
The active workspace is resolved from the API key (and/or the |
Request headers
Every request carries Authorization: Bearer <token>, where the token is either
your API key (nams_…) used directly, or a short-lived JWT obtained from the
Auth0 exchange endpoints (POST /v1/auth/exchange, POST /v1/auth/refresh).
The target workspace depends on the key’s category (see
Authentication and API keys): a workspace
key is already bound to one workspace, so X-Workspace-Id is optional (and a
different value is rejected with 403); an admin key names the workspace
per request with X-Workspace-Id: <workspace_id>. The SDK sends the header
automatically when workspace_id / workspaceId (or MEMORY_WORKSPACE_ID) is
configured. Python’s default transport sends its configured API key directly; calling a token-refresh wrapper does not install automatic token refresh. See Use NAMS.
Conversations
| HTTP | Path | Protocol operation | Python accessor | TS |
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
short_term.get_conversation (combined metadata/messages) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
No public wrapper |
Go and C# clients are not part of this repository; their method names for this table are collapsed below for reference.
Details
| Path | Go | C# |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Because extraction runs asynchronously on NAMS, Python short_term.get_extraction_status reads the conversation pipeline status; long_term.wait_for_extraction(session_id=…) polls it for you. TypeScript has no public extraction-status wrapper in this checkout: its longTerm.waitForExtraction polls entity search using expected names, a predicate, or result count. Entity search counts alone can match unrelated existing workspace entities.
On Python, get_conversation makes both metadata and message requests. There is no public get_conversation_metadata or delete_conversation; use clear_session for whole-conversation deletion.
Entities
| HTTP | Path | Protocol operation | Python accessor | TS |
|---|---|---|---|---|
|
|
|
No public wrapper |
|
|
|
|
|
|
|
|
|
long_term.get_related_entities / get_entity_relationships (relationships only) |
|
|
|
|
No public wrapper |
|
|
|
|
No public wrapper |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
No public wrapper |
|
|
|
|
No public wrapper |
|
|
|
|
|
|
|
|
|
|
|
Go and C# clients are not part of this repository; their method names for this table are collapsed below for reference.
Details
| Path | Go | C# |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
POST /graph/expand returns the 1-hop neighbourhood of a node ({nodes, edges}),
excluding any IDs you already have (loadedIds on the wire; Python argument loaded_ids) — it backs incremental
graph-visualization ("expand this node"). Exposed as long_term.expand_graph /
longTerm.expandGraph.
Auto-merged entity creates
When POST /entities resolves a name to an existing entity, it returns a
resolution: "merged" envelope instead of a complete entity. Python
add_entity and TypeScript addEntity fetch the canonical entity and return it.
Both expose the create operation’s resolution in entity.metadata under the
reserved nams_resolution key, preserving other entity metadata:
{
"nams_resolution": {
"resolution": "merged",
"merged_into": "00000000-0000-0000-0000-000000000001",
"merge_confidence": 0.93,
"fallback": false
}
}
merge_confidence is the service’s name-match score and is omitted when absent
or null. It does not replace the canonical entity’s own confidence.
If the canonical GET returns 404, an empty body, or an incomplete response
without a usable name, the SDK can return a fallback using the server-provided
merge ID and requested name/type. fallback: true identifies this result;
its creation timestamp is generated by the client, not read from the server.
Python uses its entity confidence default of 1.0; TypeScript leaves entity
confidence undefined. These fallback values are not estimates of stored
canonical values. Missing merge IDs and malformed populated fields are
validation errors. Authentication, rate-limit, network, and server errors
propagate to the caller instead of returning a fallback.
Ordinary creates and review_pending responses return their entity directly
without a follow-up GET.
Reasoning
| HTTP | Path | Protocol operation | Python accessor | TS |
|---|---|---|---|---|
|
|
|
|
|
|
|
|
No public wrapper |
|
|
|
|
No public wrapper |
|
|
|
|
|
|
|
|
|
reasoning.get_session_traces / get_trace_with_steps |
|
|
|
|
|
|
Go and C# clients are not part of this repository; their method names for this table are collapsed below for reference.
Details
| Path | Go | C# |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Python reasoning uses a local synthetic trace lifecycle over conversation-level server steps. complete_trace does not persist a server trace/outcome. See Reasoning API for lifetime and retrieval limits.
Cypher and authentication
| HTTP | Path | Protocol operation | Python accessor | TS |
|---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Go and C# clients are not part of this repository; their method names for this table are collapsed below for reference.
Details
| Path | Go | C# |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
The Python and TypeScript SDKs expose authentication operations on |
Ontologies
Typed, versioned domain schemas. The workspace is selected by credentials and the configured workspace header. Request bodies are snake_case. See Ontology API for the document schema and validation modes.
| HTTP | Path | Python | TypeScript |
|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Errors
Error responses use standard HTTP status codes with a JSON body of the shape
{"error": "<message>"}. Some errors carry extra fields (e.g. message,
limit on quota errors). The SDK maps them to typed exceptions:
| Status | Meaning | Python SDK exception |
|---|---|---|
|
Invalid request, write Cypher attempted, validation failure |
|
|
Missing/invalid token, or workspace not accessible |
|
|
Resource not found |
|
|
Operation not available on this backend |
|
|
Rate limited |
|
|
Service error |
|
Other 4xx (e.g. |
Conflict, gone, payload too large, semantic validation |
|
All SDK exceptions subclass MemoryError. The Python transport retries 429, 500, 502, 503, 504, and connection/timeout/remote-protocol errors with exponential backoff. It honors numeric Retry-After seconds; HTTP-date Retry-After values are not parsed. See NAMS limits and behavior
for rate-limit and quota specifics.
The TypeScript REST transport reports 404 as TransportError with
statusCode === 404; its exported NotFoundError is not used by that transport.
Pagination
Pagination is endpoint- and client-specific; inspect the OpenAPI schema for the endpoint you call. Python short_term.list_conversations forwards limit and user_identifier (as userId), but does not forward offset. Do not infer that an accepted **kwargs name becomes a request parameter. Other Python accessors may implement their own pagination controls. Pass supported limits explicitly when deterministic page sizes are needed.
Wire format differences
-
Hosted REST: camelCase fields (
userId,conversationId,createdAt). -
Bridge protocol: snake_case fields (
user_id,conversation_id,created_at).
The wrappers translate their supported fields; NAMS ontologies use snake_case request documents. Python may synthesize model fields where hosted responses do not carry bolt equivalents; see the API references. If you’re writing a custom transport,
see the bridge-protocol reference
and the language-specific casing modules in the TCK repo.
See also
-
Authentication and API keys — how these endpoints authenticate requests.
-
NAMS limits and behavior — quotas and runtime behavior for this API.
-
MemoryClient API reference — the Python client that wraps this API.
-
TypeScript SDK API reference — the TypeScript client that wraps this API.