{"openapi":"3.1.0","info":{"title":"EngramPort REST API","version":"1.0.0","description":"EngramPort gives any agent a brain: persistent, self-organizing memory accessible by HTTP. Drop in via MCP or the REST endpoints below, and the same substrate carries state across Claude, Cursor, ChatGPT, and your own bots.","contact":{"email":"hello@covenantsystems.ai"}},"servers":[{"url":"https://api.engramport.com"}],"tags":[{"name":"auth","description":"Tenant provisioning and the upgrade flow."},{"name":"credentials","description":"Bring-your-own LLM key registration."},{"name":"memory","description":"Store, fetch, and delete individual memories."},{"name":"recall","description":"Semantic search across a namespace."},{"name":"chat","description":"Conversational interface with retrieval-grounded answers."},{"name":"brain","description":"Per-namespace stats and graph telemetry."}],"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"X-API-Key","description":"Customer EngramPort key, prefix ek_live_. Issued by POST /v1/signup."},"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Supabase Auth access token. Used only on POST /v1/signup."}},"schemas":{"EngramportSource":{"type":"object","description":"Server-controlled source-of-write attribution. Set by the EngramPort gateway based on request headers (X-Engramport-Transport, X-Engramport-Client, X-Engramport-Server, X-Engramport-Agent, X-Engramport-Agentic-Context). Output-only on memory responses: any value supplied by the client in the request body is stripped before storage.","properties":{"transport":{"type":"string","enum":["mcp-stdio","mcp-http","rest","a2a"],"description":"Transport over which the write arrived."},"client":{"type":"string","description":"Calling client identifier (claude_desktop, claude_code, cursor, chatgpt_action, raw_http, ...)."},"server":{"type":"string","description":"EngramPort adapter version that issued the write, e.g. engramport-npm-2.0.0, openapi-direct."},"agent":{"type":"string","description":"Optional. Agent identifier for bot writes. Absent for non-bot traffic.","nullable":true},"agentic_context":{"type":"object","description":"Optional. Arbitrary jsonb context the agent wishes to attach (task, phase, run id, ...).","additionalProperties":true,"nullable":true}}},"MemoryMatch":{"type":"object","properties":{"memory_id":{"type":"string","format":"uuid"},"content":{"type":"string"},"score":{"type":"number","format":"float","description":"Similarity score 0-1 (recall) or 1.0 (direct fetch)."},"node_type":{"type":"string","enum":["memory","insight","principle","hypothesis"]},"namespace":{"type":"string"},"provenance_hash":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"metadata":{"type":"object","description":"Caller-supplied metadata, plus the server-controlled engramport_source block (see EngramportSource).","additionalProperties":true,"properties":{"engramport_source":{"$ref":"#/components/schemas/EngramportSource"}}},"linked_ids":{"type":"array","items":{"type":"string"}}}},"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"string","description":"Machine-readable error code. Stable values across releases.","enum":["tenant_slug_taken","user_already_provisioned","invalid_slug","invalid_plan","invalid_provider","unauthorized","unknown_price_id","tenant_not_found","vault_unconfigured","stripe_api_error","stripe_unconfigured","credential_save_failed","engramport_supabase_unconfigured","auth_provider_unreachable","verify_failed","signup_misconfigured"]},"detail":{"type":"string","description":"Optional human-readable detail. May change between releases."},"tenant_slug":{"type":"string","description":"Present on user_already_provisioned responses."},"namespace":{"type":"string","description":"Present on user_already_provisioned responses."},"supported":{"type":"array","items":{"type":"string"},"description":"Present on invalid_provider responses."},"valid_prices":{"type":"array","items":{"type":"string"},"description":"Present on unknown_price_id responses."}}},"SignupRequest":{"type":"object","required":["tenant_slug"],"properties":{"tenant_slug":{"type":"string","minLength":3,"maxLength":32,"pattern":"^[a-z0-9](?:[a-z0-9-]{1,30}[a-z0-9])?$"},"plan":{"type":"string","enum":["free","hobbyist","pro","team","enterprise"],"default":"free","description":"Accepted for forward compatibility. Initial tenant always lands on free; upgrades happen via /v1/stripe/checkout/create-session."}}},"SignupResponse":{"type":"object","required":["tenant_id","tenant_slug","namespace","api_key","api_key_prefix","plan"],"properties":{"tenant_id":{"type":"string","format":"uuid"},"tenant_slug":{"type":"string"},"namespace":{"type":"string","description":"Default namespace, derived as {tenant_slug}-default."},"api_key":{"type":"string","description":"Raw ek_live_ key. Shown ONCE. Save it now."},"api_key_prefix":{"type":"string","description":"First 12 characters of the key. Safe to display."},"plan":{"type":"string","enum":["free","hobbyist","pro","team","enterprise"]}}},"CheckoutRequest":{"type":"object","required":["price_id"],"properties":{"price_id":{"type":"string","description":"Stripe price ID of the tier the tenant is upgrading to."}}},"CheckoutResponse":{"type":"object","required":["url","session_id"],"properties":{"url":{"type":"string","format":"uri","description":"Stripe Checkout URL to redirect the user to."},"session_id":{"type":"string"}}},"VerifyCredentialRequest":{"type":"object","required":["provider","api_key"],"properties":{"provider":{"type":"string","enum":["anthropic","openai","google","openrouter"]},"api_key":{"type":"string","description":"Plaintext provider API key. Not stored on this endpoint."}}},"VerifyCredentialResponse":{"type":"object","properties":{"ok":{"type":"boolean"},"provider":{"type":"string"},"model_tested":{"type":"string"},"error":{"type":"string"},"detail":{"type":"string"}}},"SaveCredentialRequest":{"type":"object","required":["provider","api_key"],"properties":{"provider":{"type":"string","enum":["anthropic","openai","google","openrouter"]},"api_key":{"type":"string","description":"Plaintext provider key. Verified, encrypted via AES-256-GCM, then stored."},"label":{"type":"string","maxLength":128,"description":"Optional human-readable label."}}},"SaveCredentialResponse":{"type":"object","properties":{"ok":{"type":"boolean"},"credential_id":{"type":"string","format":"uuid"},"provider":{"type":"string"},"verified_at":{"type":"string","format":"date-time"},"model_tested":{"type":"string"}}},"MemoryIngestRequest":{"type":"object","required":["content","namespace"],"properties":{"content":{"type":"string","minLength":1,"maxLength":50000},"namespace":{"type":"string","minLength":1,"maxLength":128},"node_type":{"type":"string","enum":["memory","insight","principle","hypothesis"],"default":"memory"},"metadata":{"type":"object","additionalProperties":true,"description":"Caller metadata. Keys under metadata.engramport_source are stripped server-side."},"source_url":{"type":"string","format":"uri"},"auto_link":{"type":"boolean","default":true}}},"MemoryIngestResponse":{"type":"object","properties":{"memory_id":{"type":"string","format":"uuid"},"namespace":{"type":"string"},"node_type":{"type":"string"},"provenance_hash":{"type":"string"},"linked_count":{"type":"integer"},"timestamp":{"type":"string","format":"date-time"},"deduplicated":{"type":"boolean"}}},"BulkIngestRequest":{"type":"object","required":["memories"],"properties":{"memories":{"type":"array","items":{"$ref":"#/components/schemas/MemoryIngestRequest"}}}},"BulkIngestResponse":{"type":"object","properties":{"ingested":{"type":"integer"},"failed":{"type":"integer"},"results":{"type":"array","items":{"$ref":"#/components/schemas/MemoryIngestResponse"}}}},"RecallRequest":{"type":"object","required":["query","namespace"],"properties":{"query":{"type":"string","description":"Natural-language query. Embedded and matched semantically."},"namespace":{"type":"string"},"top_k":{"type":"integer","minimum":1,"maximum":20,"default":5},"include_context":{"type":"boolean","default":true,"description":"Include graph-connected memories in addition to direct semantic matches."}}},"RecallResponse":{"type":"object","properties":{"query":{"type":"string"},"namespace":{"type":"string"},"direct_matches":{"type":"array","items":{"$ref":"#/components/schemas/MemoryMatch"}},"contextual_links":{"type":"array","items":{"$ref":"#/components/schemas/MemoryMatch"}}}},"ChatRequest":{"type":"object","required":["message","namespace"],"properties":{"message":{"type":"string"},"namespace":{"type":"string"},"mode":{"type":"string","enum":["reflex","deep_think","intense"],"default":"reflex","description":"reflex: single-pass Haiku tier. deep_think: multi-step plan + multi-recall + Sonnet synthesis. intense: 4-6 plan queries + wider recall + Opus synthesis."},"system_prompt":{"type":"string","description":"Optional system prompt override."},"top_k":{"type":"integer","minimum":1,"maximum":20,"default":5}}},"ChatResponse":{"type":"object","properties":{"message":{"type":"string"},"namespace":{"type":"string"},"answer":{"type":"string"},"mode":{"type":"string"},"cost_usd":{"type":"number"},"matches":{"type":"array","items":{"$ref":"#/components/schemas/MemoryMatch"}}}},"BrainStats":{"type":"object","properties":{"namespace":{"type":"string"},"memory_count":{"type":"integer"},"insight_count":{"type":"integer"},"principle_count":{"type":"integer"},"edge_count":{"type":"integer"},"gqi":{"type":"number","description":"Graph Quality Index 0-1. Higher means denser, more interlinked memories."}}}}},"security":[{"ApiKeyAuth":[]}],"paths":{"/v1/signup":{"post":{"tags":["auth"],"summary":"Provision a tenant and issue a customer key.","description":"Public endpoint. Auth is a Supabase Auth access token in the Authorization header. Returns the raw ek_live_ key once. Idempotent by JWT email: a second call from the same user returns 409 user_already_provisioned with the existing tenant.","security":[{"BearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}}},"responses":{"201":{"description":"Tenant created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupResponse"}}}},"400":{"description":"Invalid slug or plan.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing or invalid Supabase JWT.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Slug taken, or user already has a tenant.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Supabase auth provider unreachable.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/stripe/checkout/create-session":{"post":{"tags":["auth"],"summary":"Create a Stripe Checkout Session for a paid tier.","description":"Customer-keyed. tenant_id derives from the X-API-Key, so a tenant can only upgrade itself.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}}},"responses":{"200":{"description":"Stripe Checkout URL returned.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"400":{"description":"Unknown price_id.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Tenant not found (key authed but tenant row missing).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Stripe API error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Stripe not configured.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/llm-credentials/verify":{"post":{"tags":["credentials"],"summary":"Verify a BYO LLM key without storing it.","description":"Tests the supplied provider key against a low-cost model. Use during onboarding to validate before save.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCredentialRequest"}}}},"responses":{"200":{"description":"Verification result (ok true or false).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCredentialResponse"}}}},"400":{"description":"Invalid provider.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/llm-credentials/save":{"post":{"tags":["credentials"],"summary":"Verify and store a BYO LLM key for the authenticated tenant.","description":"Always verifies before storing. Encrypted via AES-256-GCM at rest. Marks any previously active credential for the same tenant + provider as revoked.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialRequest"}}}},"responses":{"200":{"description":"Credential stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveCredentialResponse"}}}},"400":{"description":"Invalid provider, or verification failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Vault or backing store unconfigured.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v2/memory":{"post":{"tags":["memory"],"summary":"Store a memory.","description":"Embeds the content, deduplicates by provenance hash, and (if auto_link is true) links to similar existing memories. The server-controlled engramport_source attribution is injected from X-Engramport-* request headers.","parameters":[{"name":"X-Engramport-Transport","in":"header","required":false,"schema":{"type":"string","enum":["mcp-stdio","mcp-http","rest","a2a"],"default":"rest"},"description":"Source-of-write transport. Defaults to rest when absent."},{"name":"X-Engramport-Client","in":"header","required":false,"schema":{"type":"string","default":"raw_http"},"description":"Calling client identifier. Defaults to raw_http when absent."},{"name":"X-Engramport-Server","in":"header","required":false,"schema":{"type":"string","default":"openapi-direct"},"description":"EngramPort adapter version. Defaults to openapi-direct when absent."},{"name":"X-Engramport-Agent","in":"header","required":false,"schema":{"type":"string"},"description":"Optional agent identifier for bot writes."},{"name":"X-Engramport-Agentic-Context","in":"header","required":false,"schema":{"type":"string"},"description":"Optional JSON-encoded context attached to the write. Parsed server-side."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryIngestRequest"}}}},"responses":{"200":{"description":"Memory stored.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryIngestResponse"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Namespace not in this key's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v2/memory/bulk":{"post":{"tags":["memory"],"summary":"Store many memories in one call.","description":"Same per-item semantics as POST /v2/memory. Partial failures return per-item errors in the results array.","parameters":[{"name":"X-Engramport-Transport","in":"header","required":false,"schema":{"type":"string","enum":["mcp-stdio","mcp-http","rest","a2a"],"default":"rest"},"description":"Source-of-write transport. Defaults to rest when absent."},{"name":"X-Engramport-Client","in":"header","required":false,"schema":{"type":"string","default":"raw_http"},"description":"Calling client identifier. Defaults to raw_http when absent."},{"name":"X-Engramport-Server","in":"header","required":false,"schema":{"type":"string","default":"openapi-direct"},"description":"EngramPort adapter version. Defaults to openapi-direct when absent."},{"name":"X-Engramport-Agent","in":"header","required":false,"schema":{"type":"string"},"description":"Optional agent identifier for bot writes."},{"name":"X-Engramport-Agentic-Context","in":"header","required":false,"schema":{"type":"string"},"description":"Optional JSON-encoded context attached to the write. Parsed server-side."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIngestRequest"}}}},"responses":{"200":{"description":"Bulk ingest result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkIngestResponse"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v2/memory/{memory_id}":{"get":{"tags":["memory"],"summary":"Fetch a memory by ID.","parameters":[{"name":"memory_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Memory found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemoryMatch"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Memory not found in the given namespace.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"tags":["memory"],"summary":"Delete a memory.","parameters":[{"name":"memory_id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Memory deleted."},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Memory not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v2/recall":{"post":{"tags":["recall"],"summary":"Semantic search across a namespace.","description":"Returns direct semantic matches plus optional graph-expanded contextual links.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecallRequest"}}}},"responses":{"200":{"description":"Recall result.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecallResponse"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Namespace not in this key's scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v2/chat":{"post":{"tags":["chat"],"summary":"Ask the brain a question.","description":"Retrieval-grounded answer. Three modes by cost and depth: reflex (Haiku tier), deep_think (Sonnet tier with multi-step planning), intense (Opus tier with wider recall).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}}},"responses":{"200":{"description":"Chat answer.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatResponse"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v2/brain/stats":{"get":{"tags":["brain"],"summary":"Per-namespace memory and graph statistics.","parameters":[{"name":"namespace","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Brain stats.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrainStats"}}}},"401":{"description":"Invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}