API Reference
The Rust relayer exposes these routes. Routes are defined in services/server/src/main.rs.
See also:
Authentication
All /api/* routes require signed headers. The SDK handles this automatically.
Required headers
| Header | Description |
|---|---|
x-public-key | Hex-encoded Ed25519 public key (32 bytes) |
x-signature | Hex-encoded Ed25519 signature (64 bytes) |
x-timestamp | Unix timestamp in seconds (5-minute validity window) |
x-nonce | UUID v4 nonce. The relayer records it in Redis for replay protection |
Optional headers
| Header | Description |
|---|---|
x-account-id | MemWalAccount object ID hint. Official SDKs always send it and include it in the canonical signature |
x-seal-session | Base64 exported Seal SessionKey for relayer-managed decrypt flows. Used by the TypeScript and Python SDKs |
x-delegate-key | Legacy delegate private key credential for relayer-managed decrypt flows. Deprecated; use x-seal-session where supported |
Signature format
The signed message is:
Source: relayer/api-reference.md{timestamp}.{method}.{path_and_query}.{body_sha256}.{nonce}.{account_id}
For GET requests, body_sha256 is the SHA-256 of an empty byte string. If a raw client omits x-account-id, it must sign the empty string in the final account_id position. Official SDKs send x-account-id.
The relayer verifies the Ed25519 signature, then resolves the owner by looking up the public key in onchain MemWalAccount.delegate_keys.
GET /health
Service health check. No authentication required.
Response:
Source: relayer/api-reference.md{
"status": "ok",
"version": "0.1.0",
"relayerVersion": "0.1.0",
"apiVersion": "1.0.0",
"minSupportedSdk": {
"typescript": "0.0.4",
"python": "0.1.0",
"mcp": "0.0.1"
},
"featureFlags": {
"auth.accountBoundNonce": true,
"auth.sealSessionHeader": true,
"runtime.versionEndpoint": true
},
"deprecations": [],
"build": {},
"mode": "production",
"prompt_versions": {
"extract": "extract.v1",
"ask": "ask.v1"
}
}
GET /version
Stable relayer/API compatibility metadata. No authentication required.
Response: the compatibility object documented in Versioning and Compatibility.
POST /sponsor
Proxy to the Seal/Walrus sidecar's /sponsor endpoint. The request must include
authTimestamp, a UUID-v4 authNonce, and authSignature: a Sui personal-message
signature over the sender, transaction-kind hash, timestamp, and nonce. Only one
allowlisted Walrus Memory account call might be sponsored.
POST /sponsor/execute
Proxy to the sidecar's /sponsor/execute endpoint. sender must match the
short-lived, one-time Redis binding created by the authenticated /sponsor call.
POST /api/remember
Submit text as an encrypted memory job. The relayer returns after creating a background job; embedding, Seal encryption, Walrus upload, and vector indexing continue asynchronously.
Request:
Source: relayer/api-reference.md{
"text": "User prefers dark mode",
"namespace": "demo"
}
namespace defaults to "default" if omitted and is limited to 255 UTF-8 bytes.
Response: 202 Accepted
{
"job_id": "uuid",
"status": "running"
}
GET /api/remember/:job_id
Poll a remember job.
Response:
Source: relayer/api-reference.md{
"job_id": "uuid",
"status": "done",
"owner": "0x...",
"namespace": "demo",
"blob_id": "walrus-blob-id"
}
POST /api/remember/bulk
Submit up to 20 memories in one request. job_ids[i] corresponds to items[i].
Request:
Source: relayer/api-reference.md{
"items": [
{ "text": "User prefers dark mode", "namespace": "demo" },
{ "text": "User works in TypeScript", "namespace": "demo" }
]
}
Response: 202 Accepted
{
"job_ids": ["uuid-1", "uuid-2"],
"total": 2,
"status": "running"
}
POST /api/remember/bulk/status
Poll a batch of remember jobs.
Request:
Source: relayer/api-reference.md{
"job_ids": ["uuid-1", "uuid-2"]
}
Response:
Source: relayer/api-reference.md{
"results": [
{ "job_id": "uuid-1", "status": "done", "blob_id": "walrus-blob-id" },
{ "job_id": "uuid-2", "status": "running" }
]
}
POST /api/recall
Search for memories matching a natural language query. Returns decrypted plaintext results.
Request:
Source: relayer/api-reference.md{
"query": "What do we know about this user?",
"limit": 10,
"namespace": "demo"
}
limit defaults to 10. namespace defaults to "default".
Response:
Source: relayer/api-reference.md{
"results": [
{
"blob_id": "walrus-blob-id",
"text": "User prefers dark mode",
"distance": 0.15
}
],
"total": 1
}
POST /api/remember/manual
Register a client-encrypted payload. The client sends Seal-encrypted data (base64) and a precomputed embedding vector. The relayer uploads the encrypted bytes to Walrus and stores the vector mapping.
Request:
Source: relayer/api-reference.md{
"encrypted_data": "base64-encoded-seal-encrypted-bytes",
"vector": [0.01, -0.02, ...],
"namespace": "demo"
}
Response:
Source: relayer/api-reference.md{
"id": "uuid",
"blob_id": "walrus-blob-id",
"owner": "0x...",
"namespace": "demo"
}
POST /api/recall/manual
Search with a precomputed query vector. Returns blob IDs and distances only, the client handles downloading and decrypting.
Request:
Source: relayer/api-reference.md{
"vector": [0.01, -0.02, ...],
"limit": 10,
"namespace": "demo"
}
Response:
Source: relayer/api-reference.md{
"results": [
{
"blob_id": "walrus-blob-id",
"distance": 0.15
}
],
"total": 1
}
POST /api/analyze
Extract facts from text using an LLM, then enqueue each fact as a separate memory job.
Request:
Source: relayer/api-reference.md{
"text": "I live in Hanoi and prefer dark mode.",
"namespace": "demo"
}
Response: 202 Accepted
{
"job_ids": ["uuid-1", "uuid-2"],
"facts": [
{ "text": "User lives in Hanoi", "id": "uuid-1", "job_id": "uuid-1" },
{ "text": "User prefers dark mode", "id": "uuid-2", "job_id": "uuid-2" }
],
"fact_count": 2,
"status": "pending",
"owner": "0x..."
}
POST /api/ask
Recall memories, inject them into an LLM prompt, and return an AI-generated answer with the context used.
Request:
Source: relayer/api-reference.md{
"question": "What do you know about my preferences?",
"limit": 5,
"namespace": "demo"
}
limit defaults to 5. namespace defaults to "default".
Response:
Source: relayer/api-reference.md{
"answer": "Based on your memories, you prefer dark mode and live in Hanoi.",
"memories_used": 2,
"memories": [
{
"blob_id": "walrus-blob-id",
"text": "User prefers dark mode",
"distance": 0.12
}
]
}
POST /api/restore
Rebuild missing vector entries for one namespace. Queries onchain blobs by owner and namespace, downloads from Walrus, decrypts, re-embeds, and re-indexes only the entries missing from the local database.
Request:
Source: relayer/api-reference.md{
"namespace": "demo",
"limit": 10
}
limit defaults to 10.
Response:
Source: relayer/api-reference.md{
"restored": 3,
"skipped": 7,
"total": 10,
"namespace": "demo",
"owner": "0x...",
"truncated": false
}
truncated is true when this restore is known-incomplete: either more onchain blobs were missing locally than limit allowed this call to restore, or the sidecar's raw onchain candidate fetch (bounded per owner, shared across all of the owner's namespaces, hard-capped independent of limit) hit its own cap before this namespace's blobs were even filtered out of that set. The second case can produce truncated: true even when total is 0 for this namespace, because a cap hit elsewhere can starve this namespace's fetch entirely. Raising limit only helps with the first case, past the sidecar's cap, only a cursor/pagination-based restore would.