emem Knowledge Graph API
The knowledge-graph API from emem — 2 operation(s) for knowledge-graph.
The knowledge-graph API from emem — 2 operation(s) for knowledge-graph.
Every API here is available over the APIs.io API and to AI agents over MCP.
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
find_apisBrowse and filter every API in the catalog.get_api_artifactsOne API's artifacts, grouped by type.get_openapiThe primary OpenAPI for this API.find_similar_apisAPIs that look like this one.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.curl "https://apis.io/api/v1/apis/emem-dev-knowledge-graph-api"
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
description: emem is shared memory for AI agents working together in the real world.
license:
name: Apache-2.0
title: emem Knowledge Graph API
version: 2.4.0
x-emem-surface-asymmetry:
memory_notes: MCP only
reach_them_at: POST /mcp, method tools/call
read_side_is_here:
- /v1/memory/search
- /v1/memory/sse
- /memories/{path}
tools:
- emem_memory_create
- emem_memory_view
- emem_memory_delete
- emem_memory_rename
- emem_memory_str_replace
- emem_memory_supersede
why_not_here: These write the agent correspondence plane, which is prose and untrusted-by-declaration. It is deliberately not part of the REST fact surface, and the two planes are kept apart rather than merged for convenience.
servers:
- description: Hosted instance (HTTPS-only)
url: https://emem.dev
tags:
- name: knowledge-graph
paths:
/v1/edges:
post:
description: 'Persist temporal knowledge-graph edges. Body is a signed Attestation envelope whose `edges[]` array carries each edge {subj, pred, obj, valid_from, valid_to?, confidence, signer, signed_at, schema_cid?, note?}. The edge leaves are folded into the merkle root so the signature commits to them. Additive: an attestation with no edges behaves exactly as /v1/attest.'
operationId: emem_edges_write
requestBody:
content:
application/json:
schema:
properties:
edges:
items:
properties:
confidence:
type: number
note:
type: string
obj:
description: object fact CID
type: string
pred:
type: string
subj:
description: subject fact CID
type: string
valid_from:
type: integer
valid_to:
type: integer
required:
- subj
- pred
- obj
- valid_from
- confidence
- signer
- signed_at
type: object
type: array
required:
- facts
- edges
- batch_root
- attester
- signature
type: object
required: true
responses:
'200':
content:
application/json:
schema:
type: object
description: ok
default:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
description: 'error, the emem.error.v1 envelope. Branch on the stable `code` (see GET /v1/errors), not the message. A malformed or missing-field request body returns `code: invalid_argument` with the offending field named in `message`.'
summary: Persist temporal knowledge-graph edges.
tags:
- knowledge-graph
/v1/edges/recall:
post:
description: 'Read temporal knowledge-graph edges (subj --pred--> obj, valid over [valid_from, valid_to)), bi-temporally filtered, in EITHER direction. Forward (`subj`, direction="out", the default): edges originating at a subject fact. Reverse (`obj`, direction="in"): edges pointing AT a fact, what disagrees-with / supersedes / relates-to it. Returns a signed list of edges plus the distinct neighbour fact CIDs (`objs` for out, `subjs` for in); the receipt commits the returned edge CIDs into its signature preimage.
When to use: Call this to read the typed CONNECTIONS of a fact, what disagrees with it, what superseded it, what relates to it, as of a point in time. A plain recall gives you the fact; this gives you how that fact links to others in the memory graph. Ask it when the user says ''what is this related to'', ''what replaced this observation'', ''why is this value contested'', or ''what did this place''s relations look like as of date X''. Pick a direction: set `subj` (direction="out") to ask ''what does this fact point at''; set `obj` (direction="in") to ask the REVERSE, ''what disagrees-with / supersedes / points-at this fact''. Set exactly one of subj/obj, an ambiguous or empty request errors honestly rather than returning a silent empty. Pass `as_of_tslot` to get the latest edge per neighbour whose valid interval covers that moment (newer edges shadow older, nothing is deleted); pass `pred` (e.g. `disagrees_with`, `supersedes`) to filter, or omit it (empty string) for every predicate. Tip: a quicker way to get a fact + its outbound edges in one shot is `emem_recall` with include:["edges"]. Follow each edge''s `obj`/`subj` with `emem_fetch` to resolve the related fact, or `emem_verify_receipt` to confirm the signature offline.'
operationId: emem_edges_recall
requestBody:
content:
application/json:
schema:
properties:
as_of_tslot:
description: valid-time bound; latest edge per neighbour whose interval covers it
type: integer
direction:
description: out (default)=subj→objs; in=obj→subjs; inferred from which of subj/obj is set when omitted
enum:
- out
- in
type: string
limit:
default: 100
maximum: 1000
minimum: 1
type: integer
obj:
description: 'object fact CID (reverse / direction=in): what points at this fact'
type: string
pred:
description: predicate filter; empty string scans all predicates
type: string
subj:
description: subject fact CID (forward / direction=out); set exactly one of subj/obj
type: string
type: object
required: true
responses:
'200':
content:
application/json:
schema:
$ref: '#/components/schemas/SignedResponse'
description: ok
default:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorEnvelope'
description: 'error, the emem.error.v1 envelope. Branch on the stable `code` (see GET /v1/errors), not the message. A malformed or missing-field request body returns `code: invalid_argument` with the offending field named in `message`.'
summary: Recall temporal knowledge-graph edges in either direction, bi-temporally…
tags:
- knowledge-graph
components:
schemas:
Cost:
description: 'Self-declared cost block on every receipt. Honest accounting: latencies are observed, freshness is the age of the stalest source cited (null when undatable, never 0 as a stand-in), `was_cached` is true when the hot cache served the read.'
properties:
credits:
description: Conceptual cost units; 0 for L0/L1 read endpoints on the hosted responder.
type: number
latency_p50_ms:
type: number
latency_p99_ms:
type: number
source_freshness_s:
description: 'Age of the STALEST source this response cites: now minus the earliest captured_at across the returned facts'' sources. null when nothing in the response carries a dated source, which is the honest answer for a primitive that reads no observation. Was a hardcoded 0 until 2026-08-05, so a 2021 DEM tile reported as 0 s old; a null here means unknown, never fresh.'
type:
- integer
- 'null'
was_cached:
type: boolean
type: object
Fact:
description: A primary attestation at (cell, band, tslot). `value` is the band's typed reading (number, array of numbers for vector bands, or a categorical class id). `unit` is the band's declared unit (e.g. `m_msl`, `degC`, `mm`).
properties:
absence_reason:
description: Present only when kind=`absence`.
enum:
- unavailable_capability
- outside_coverage
- archetype_seed_unavailable
- gpu_unavailable
- upstream_error
- upstream_timeout
type: string
band:
type: string
cell:
$ref: '#/components/schemas/Cell64'
fact_cid:
$ref: '#/components/schemas/FactCid'
kind:
description: '`primary` = signed measurement; `absence` = signed "we don''t have this here" with a typed reason.'
enum:
- primary
- absence
type: string
provenance:
description: Upstream source key (e.g. `copdem30m`, `s2_l2a`, `cams_eu`).
type: string
receipt:
$ref: '#/components/schemas/Receipt'
tslot:
$ref: '#/components/schemas/Tslot'
unit:
type: string
value:
description: Number, array of numbers, or class id depending on band type.
required:
- kind
- cell
- band
- tslot
- value
- fact_cid
- receipt
type: object
MaterializeNote:
description: 'One entry in the response''s `materialize_notes[]`, recording what the lazy materializer did during this call. status:"materialized" means a signed fact was minted and persisted (a Primary observation OR a confirmed, evidence-backed Absence - both are signed and citeable by fact_cid). status:"skipped" means nothing was signed: `reason_class` says why (transient `timeout`/`upstream_error`, retryable; or structural `unknown_band`/`no_materializer`/`capability_unavailable`, not retryable here) and `absence` is always false, because a skip is ''unknown'', never a confirmed absence.'
properties:
absence:
description: Always false on a skip; a confirmed absence is a signed fact with status:materialized, not a skip.
type: boolean
band:
type: string
cell:
$ref: '#/components/schemas/Cell64'
fact_cid:
type: string
latency_ms:
type: number
ok:
type: boolean
reason:
type: string
reason_class:
enum:
- timeout
- upstream_error
- unknown_band
- no_materializer
- capability_unavailable
type: string
retryable:
type: boolean
status:
enum:
- materialized
- skipped
type: string
type: object
ErrorEnvelope:
description: The `emem.error.v1` failure envelope returned by every endpoint on a 4xx/5xx. Branch on the stable `code` (not the human `message`). See GET /v1/errors for the full code catalog.
properties:
code:
description: Stable machine-readable error code. One of the codes in GET /v1/errors.
example: invalid_argument
type: string
details:
description: Optional structured recovery hints; present on errors that ship machine-readable next-steps.
type: object
message:
description: Human-readable detail. For invalid_argument this names the offending field (e.g. "missing field `q`").
type: string
path:
description: Request path that produced the error.
example: /v1/ask
type: string
schema:
const: emem.error.v1
type: string
required:
- code
- message
- schema
type: object
PubKey:
description: Ed25519 32-byte public key, base32-nopad-lowercase encoded (52 chars). Returned in receipts and `/.well-known/emem.json`.
example: 777er3yihgifqmv5hmc2wwmyszgddzderzhsx6rex4yoakwomvka
type: string
Cell64:
description: 'cell64 wire form: four base-65,536 bigrams separated by dots, e.g. `defi.zb4d9.pefa.zf619`. Encoded resolution is ~9.55 m at the equator. Each bigram is either a CVCV quad, consonant `[bcdfghjklmnpqrstvwxyz]` followed by vowel `[aeiouAEIOU]` repeated twice, OR a synthetic 5-char `z[0-9a-f]{4}` slot used for the unused pad cells in the 65,536-entry alphabet. The regex pin matches `pattern` below byte-for-byte and is also surfaced under `Cell64Pattern` so agents can validate before sending.'
example: defi.zb4d9.pefa.zf619
maxLength: 23
minLength: 19
pattern: ^(?:(?:[bcdfghjklmnpqrstvwxyz][aeiouAEIOU]){2}|z[0-9a-f]{4})(?:\.(?:(?:[bcdfghjklmnpqrstvwxyz][aeiouAEIOU]){2}|z[0-9a-f]{4})){3}$
type: string
SignedResponse:
description: Standard recall envelope. `facts` is the array of signed facts touched by this call (subset of `bands_already_attested_at_cell` after auto-materialization). `receipt` is the responder's signature over the call. `materialize_notes` lists any lazy-materializer activity that happened to satisfy the request, empty for purely warm reads.
properties:
bands_already_attested_at_cell:
description: Bands the cell already has facts for, regardless of whether they were requested. Useful for follow-up calls without a second /v1/coverage_matrix hit.
items:
type: string
type: array
caveats:
description: Plain-language constraints the caller should fold into their answer (grid resolution, revisit cadence, sample-size warnings).
items:
type: string
type: array
facts:
items:
$ref: '#/components/schemas/Fact'
type: array
materialize_notes:
items:
$ref: '#/components/schemas/MaterializeNote'
type: array
receipt:
$ref: '#/components/schemas/Receipt'
required:
- facts
- receipt
type: object
FactCid:
description: 'Content id of a fact: base32-nopad-lowercase encoding of `blake3(canonical_cbor(fact))`, the FULL 32-byte digest with no truncation. Always 52 characters, alphabet `[a-z2-7]`. A cid of any other length is a damaged citation, not a shorter address: /v1/memory_token/resolve rejects it as `fact_cid_malformed_length` rather than guessing. Note that `entity_cid` and `bundle_cid` are NOT this shape; both truncate to 16 bytes (26 characters) and hash an identity anchor or a citation list rather than a complete body.'
example: qtv2bco56qw4pmlohk56dotoxyl3atmnjpmzrijj2kazw2mj57oq
maxLength: 52
minLength: 52
pattern: ^[a-z2-7]{52}$
type: string
Tslot:
description: Band-tempo-relative integer offset from the emem epoch. Each band declares its tempo (`fast` / `medium` / `slow` / `static`); tslot is the rounded count of that tempo's unit since the epoch.
minimum: 0
type: integer
Receipt:
description: 'Ed25519-signed receipt. The browser-side verifier at /verify reconstructs the preimage from the receipt fields alone, no callback to the issuer. **A receipt is byte-for-byte or nothing.** Current receipts carry `preimage_version: 2`, whose preimage binds request_id, served_at, primitive, cells, fact_cids AND, when present, the scope / as_of / edges / source_versions / field digests and the `merkle_proof` segment. Reshaping a receipt — dropping a field an SDK considers redundant, re-keying it, summarising it, round-tripping it through a lossy model — invalidates the signature BY DESIGN, and the result is indistinguishable on the wire from tampering. Store and forward the responder''s exact bytes. POST /v1/verify_receipt names which of the two it is where it can prove the difference (`reason: receipt_reshaped_after_signing` with a `failure_detail`). What is NOT signed: the caller''s `place`/`q` string, raw `lat`/`lng`, requested `bands[]`, requested `tslot`, and `intent` — a wrong-place geocode produces a valid signature for the wrong cell. Branch on /v1/locate `selected.is_high_confidence` before trusting place-anchored answers. Also: `fact_cid` is per-replica (signed_at differs across responders even for byte-identical upstream pixels); cross-replica join key is the tuple (cell, band, tslot). /v1/recall_polygon emits one independently signed receipt per cell under `by_cell.<cell>.receipt`, `merged_facts[]` is convenience flattening and is NOT covered by an aggregate signature.'
properties:
cells:
items:
$ref: '#/components/schemas/Cell64'
type: array
cost:
$ref: '#/components/schemas/Cost'
fact_cids:
items:
$ref: '#/components/schemas/FactCid'
type: array
intent:
description: Optional natural-language hint. Populated when served via /v1/intent.
type: string
merkle_proof:
description: 'Inclusion proof for `fact_cids[0]` when persisted. Omitted from JSON when the cited facts pre-date the proof tree; under preimage_version 2 that absence is itself signed (an explicit ABSENT marker), so it is a statement rather than a gap. Do not strip this field: v2 binds it into the signature and removing it makes an authentic receipt report `signature_valid: false`.'
properties:
leaf_index:
description: u32 leaf index in the canonical-sorted batch.
type: integer
path:
description: Sibling hashes leaf→root.
items:
description: 32-byte sibling hash as a byte array
items:
type: integer
type: array
type: array
root:
description: The expected 32-byte batch root as a byte array.
items:
type: integer
type: array
version:
description: 'Merkle hashing rule: 0 (omitted) = legacy unprefixed, 1 = RFC 6962-style prefixed.'
type: integer
required:
- leaf_index
- path
- root
type: object
primitive:
description: 'Namespaced wire form: `emem.recall`, `emem.find_similar`, `emem.verify`, …'
type: string
registry_cid:
description: CID of the function registry version in force.
type: string
request_id:
description: ULID generated per request.
type: string
responder:
$ref: '#/components/schemas/PubKey'
responder_key_epoch:
description: u32 rotation counter; bumps when the operator rotates keys.
type: integer
responder_pubkey_b32:
$ref: '#/components/schemas/PubKey'
schema_cid:
description: CID of the active CDDL profile.
type: string
served_at:
description: ISO 8601 UTC, second precision.
type: string
signature:
description: Ed25519 signature, 64 bytes base32-nopad-lowercase encoded.
type: string
source_versions:
additionalProperties:
type: string
description: Per-source freshness map.
type: object
required:
- request_id
- served_at
- primitive
- cells
- fact_cids
- schema_cid
- responder
- responder_key_epoch
- responder_pubkey_b32
- signature
- registry_cid
type: object