Documentation menu
API Reference

Complete reference for all Anansi API endpoints.

Authentication

All requests require a Bearer token in the Authorization header. Create keys from your developer portal.

shell
Authorization: Bearer ans_your_api_key_here

Keys are HMAC-hashed at rest. Every key has a label and creation timestamp visible in the portal. Revoke any key instantly from your dashboard.

POST /v1/ingest

POST/v1/ingest
Ingest content into a user's memory. Content is sanitized, chunked, embedded, and queued for synthesis. Returns immediately — synthesis is asynchronous.
FieldTypeDescription
userIdstringrequiredYour app's identifier for this user. Max 256 chars.
contentstringrequiredText to ingest. Max 100 KB. Secrets and API keys are automatically redacted before storage.
sourceTypestringoptionalconversation · voice · action · agent_summary · onboarding · meeting. Defaults to api_text. Preserved in relevant[].metadata.sourceType.
sourceIdstringoptionalIdempotency key. Alphanum + :_./–, max 256 chars.
sessionIdstringoptionalGroups conversation turns by session. Surfaces in relevant[].metadata.sessionId.
agentIdstringoptionalIdentifies the agent that produced this content. Surfaces in relevant[].metadata.agentId.
metadataobjectoptionalArbitrary key-value pairs. Recognised fields: title, author, timestamp, actionType, resourceId, resourceType.
202Response
{ "id": "api:ws_id:user_abc:uuid", "queued": true }
StatusMeaning
401Missing or invalid API key
400Missing required fields or invalid sourceType
402Monthly ingest quota exceeded
413Content exceeds 100 KB
429Rate limit exceeded (100 req/min)

POST /v1/ingest/batch

POST/v1/ingest/batch
Ingest up to 50 items in a single request. Accepts the same fields as /v1/ingest per item. Ideal for onboarding flows and bulk imports. Synthesis is triggered once for all unique userIds touched. Each item counts as one ingest call against your monthly quota (a 50-item batch = 50 units).
FieldTypeDescription
itemsarrayrequiredArray of ingest objects (1–50). Each item supports the same fields as POST /v1/ingest.
202Response
{ "queued": 4, "ids": ["api:ws:user:uuid1", "api:ws:user:uuid2", ...] }
StatusMeaning
400items is not an array, is empty, or exceeds 50
402Monthly ingest quota exceeded
429Rate limit exceeded

GET /v1/context

GET/v1/context
Retrieve synthesized memory context for a user. Returns static facts, dynamic context, and (if q provided) relevant vector search results.
ParamTypeDescription
userIdstringrequiredSame userId used during ingest. Max 256 chars. Not required when scope=workspace.
qstringoptionalQuery for vector search. Returns top relevant chunks (capped at 8). Omit for synthesized profile only. Max 2000 chars.
scopestringoptionaluser (default) or workspace for the team-wide profile across all users. Workspace scope is Pro+.
alphanumberoptionalHybrid weighting: 1.0 = pure vector, 0.0 = pure keyword. Omit for RRF merge. Values other than 1.0 require hybrid search (Pro+).
thresholdnumberoptionalMinimum similarity score (0.0–1.0) for returned chunks.
filtersstringoptionalJSON-encoded metadata filter (e.g. {"team":"eng"}). Pro+.
sessionIdstringoptionalRestrict retrieval to a single conversation/session.
asOfISO 8601optionalPoint-in-time query. Returns the synthesized profile as it was at this UTC timestamp. Only chunks ingested on or before this date are included. Pro+.
asOfKnowledgeISO 8601optionalBi-temporal query. Returns what your system knew at this timestamp — useful for replaying past system state regardless of when events actually occurred. Pro+.
200Response
{ "static": ["Prefers TypeScript", "Works on payments team"], "dynamic": ["Building webhook retry system"], "relevant": [{ "content": "User prefers TypeScript...", "similarity": 0.87, "metadata": { "timestamp": "2026-06-08T..." } }] }
StatusMeaning
401Missing or invalid API key
400Missing userId or userId exceeds 256 chars
402Monthly context quota exceeded
Tip
Performance: Synthesized profiles are cached in Redis with a 60-second TTL, so repeated context calls within that window skip retrieval entirely. A cache miss runs the profile load plus (when q is set) one hybrid search query.

GET /v1/entities

GET/v1/entities
Return the entity graph for a user — people, organizations, and tools extracted from ingested content. Updated after each synthesis pass.
ParamTypeDescription
userIdstringrequiredThe userId to retrieve the entity graph for.
typestringoptionalFilter by entity type: person · organization · tool. Omit to return all types.
200Response
{ "entities": [ { "name": "Sarah", "type": "person", "relationship": "manager", "confidence": 0.91 }, { "name": "Stripe", "type": "organization", "relationship": "employer", "confidence": 0.87 }, { "name": "BullMQ", "type": "tool", "relationship": "uses", "confidence": 0.94 } ] }
StatusMeaning
401Missing or invalid API key
400Missing userId
404No entity graph found for this user (not yet synthesized)
POST/v1/search
Hybrid vector + keyword search across all memory chunks for a user. Send a JSON body. Use this for raw scored retrieval beyond the top-K results returned by GET /v1/context.
FieldTypeDescription
userIdstringrequiredThe userId to search memory for. Max 256 chars.
querystringrequiredSearch query, max 2000 chars. Combined vector similarity + BM25 keyword match.
searchModestringoptionalsemantic · hybrid (default) · keyword. Hybrid/keyword are Pro+.
alphanumberoptional1.0 = pure vector, 0.0 = pure keyword. Omit for RRF merge (Pro+).
thresholdnumberoptionalMinimum similarity score (0.0–1.0).
limitnumberoptionalMax results to return (default 8, max 50).
filtersobjectoptionalJSONB metadata filters (Pro+).
sourceIdstringoptionalScope search to one ingested document.
sessionIdstringoptionalRestrict search to a session.
200Response
{ "results": [ { "content": "User prefers TypeScript...", "similarity": 0.89, "sourceType": "conversation", "ingestedAt": "2026-06-10T..." }, { "content": "Debugging BullMQ retry logic", "similarity": 0.82, "sourceType": "meeting", "ingestedAt": "2026-06-09T..." } ] }

DELETE /v1/memory

DELETE/v1/memory
Delete all memory for a user — chunks, embeddings, and synthesized profiles. Idempotent.
ParamTypeDescription
userIdstringrequiredThe userId whose memory to delete entirely.
200Response
{ "deleted": 7 }

GET /v1/ledger

GET/v1/ledger
Reconstruct the ledger — cited, trust-tiered claims for a workspace — at any point in time. With asOfKnowledge, answers reflect what was believed at that instant; with asOf, what was true; with neither, the current ledger. Every claim carries its supporting evidence; competing active answers for one question surface as disputes.
ParamTypeDescription
domainstringoptionalRestrict the fold to a single domain. Omit to return the whole ledger.
asOfISO 8601optionalValid-time coordinate — reconstruct what was true at this instant. Accepts YYYY-MM, YYYY-MM-DD, or full ISO 8601.
asOfKnowledgeISO 8601optionalKnowledge-time coordinate — reconstruct what the system believed at this instant.
200Response
{ "workspaceId": "ws_abc", "domain": null, "asOf": null, "asOfKnowledge": null, "claims": [ { "claim": "Prod deploys require two approvals", "claimKey": "deploy.approvals", "claimFingerprint": "a1b2c3", "claimType": "policy", "status": "observed", "disputed": false, "confidence": 0.92, "validFrom": "2026-03-01T00: 00: 00.000Z", "validFromBasis": "stated", "evidence": [ { "chunkId": "chunk-uuid", "quote": "all prod deploys need two approvals", "sourceType": "notion_page" } ], "recordedAt": "2026-03-02T09: 00: 00.000Z" } ], "disputes": [] }
StatusMeaning
401Missing or invalid API key
400Invalid asOf or asOfKnowledge date
429Rate limit exceeded (60 req/min)

GET /v1/ledger/divergences

GET/v1/ledger/divergences
Where a documented answer (wiki, runbook, Notion) disagrees with the observed reality (chat, tickets) for the same question — the doc-vs-reality view only a bi-temporal ledger can produce. Reads history, not just active rows, so it catches docs the ledger already superseded.
ParamTypeDescription
domainstringoptionalRestrict to a single domain. Omit to scan all domains.
200Response
{ "divergences": [ { "claimKey": "deploy.approvals", "documented": { "claim": "Prod deploys require two approvals", "fingerprint": "a1b2c3", "validFrom": "2026-01-01T00: 00: 00.000Z", "evidence": [{ "chunkId": "c1", "quote": "two approvals", "sourceType": "notion_page" }] }, "observed": { "claim": "Prod deploys ship with one approval", "fingerprint": "d4e5f6", "validFrom": "2026-04-01T00: 00: 00.000Z", "evidence": [{ "chunkId": "c2", "quote": "just LGTM and merge", "sourceType": "conversation" }] }, "changedAt": "2026-04-01T00: 00: 00.000Z" } ] }
StatusMeaning
401Missing or invalid API key
429Rate limit exceeded (60 req/min)

GET /v1/ledger/timeline

GET/v1/ledger/timeline
A chronological record of when each answer was adopted and (if closed) superseded. adopted uses a stated start date when one exists, otherwise the moment the claim was first recorded — never an invented date. Sorted ascending by time.
ParamTypeDescription
domainstringoptionalRestrict to a single domain. Omit for all domains.
200Response
{ "timeline": [ { "at": "2026-01-01T00: 00: 00.000Z", "claimKey": "deploy.approvals", "claim": "Prod deploys require two approvals", "fingerprint": "a1b2c3", "kind": "adopted" }, { "at": "2026-04-01T00: 00: 00.000Z", "claimKey": "deploy.approvals", "claim": "Prod deploys require two approvals", "fingerprint": "a1b2c3", "kind": "superseded" } ] }
StatusMeaning
401Missing or invalid API key
429Rate limit exceeded (60 req/min)

Rate limits

EndpointPer-minuteMonthly (API plan)
POST /v1/ingest100 req/min10,000/month
GET /v1/context60 req/min5,000/month
GET /v1/entities60 req/minUnlimited
POST /v1/search60 req/minCounts against context quota
DELETE /v1/memory60 req/minUnlimited
GET /v1/ledger*60 req/minUnlimited

Monthly limit exceeded → 402. Per-minute limit exceeded → 429.