API docs

Everything in Graphyte is an HTTP call: store files, search them, and get answers with citations. JSON in, JSON out.

Quickstart

Create an account, then an API key under Console → API keys. Every request sends it as a bearer token. Set two variables and you can run every example on this page as-is:

shell
export GRAPHYTE=https://your-graphyte-host
export GRAPHYTE_API_KEY=gk_...

# create a bucket, store a file, ask about it
curl -X POST $GRAPHYTE/api/v1/buckets -H "Authorization: Bearer $GRAPHYTE_API_KEY" -d '{"name": "handbook"}'
curl -X PUT $GRAPHYTE/api/v1/buckets/handbook/objects/leave.md -H "Authorization: Bearer $GRAPHYTE_API_KEY" --data-binary @leave.md
curl -X POST $GRAPHYTE/api/v1/answer -H "Authorization: Bearer $GRAPHYTE_API_KEY" -d '{"question": "How much parental leave do we offer?"}'

Authentication and errors

Send Authorization: Bearer gk_... on every request. A key belongs to one workspace and can read and write everything in it. Revoke keys in the console; revoked keys fail immediately.

Errors are JSON with an HTTP status and a stable code:

401 Unauthorized
{ "error": { "code": "unauthorized", "message": "Send a valid API key as `Authorization: Bearer gk_...`." } }

MCP for agents

Graphyte is an MCP server at POST /api/mcp (Streamable HTTP). Authenticate with the same bearer key. Tools: answer, search, research, list_buckets, list_objects, read_object and store_text, which lets an agent write notes it can find and cite later.

Claude Code
claude mcp add --transport http graphyte $GRAPHYTE/api/mcp \
  --header "Authorization: Bearer $GRAPHYTE_API_KEY"
other MCP clients
{
  "mcpServers": {
    "graphyte": {
      "type": "http",
      "url": "https://graphyte.one/api/mcp",
      "headers": { "Authorization": "Bearer ${GRAPHYTE_API_KEY}" }
    }
  }
}

Tenants

Building a product for many customers? Send X-Graphyte-Tenant: <customer id> (letters, numbers, ._:-, up to 128 characters) on any request, including MCP. Objects written with the header belong to that tenant; reads, search, answers and research see only that tenant's objects, and links between passages never cross tenants. The same key can exist once per tenant.

Requests without the header use the workspace's own default space. Buckets are shared, so deleting one needs a request without the header.

Ontology, links and ranking

As each file is read, Graphyte extracts the entities its passages mention (people, products, sites, systems, policies…) with inferred types, and the relations between them. Browse them under Console → Ontology. Search results list the entities each passage mentions.

Passages are linked when they share meaning, enough vocabulary, or an entity. Search first gathers direct evidence (keywords, meaning, entities named in the query), then runs personalized PageRank over the links, restarting at that evidence. A passage tied to many matches ranks higher even if it shares no words with the query; those results carry "via": ["graph"].

Images (PNG, JPEG, GIF, WebP up to 5 MB) are described and their text transcribed, then indexed like any document.

Buckets

GET /api/v1/buckets lists buckets with their object counts and sizes.

POST /api/v1/buckets creates one. Names are 3 to 63 characters: lowercase letters, numbers, dots and hyphens.

DELETE /api/v1/buckets/:bucket deletes a bucket and every object in it.

create a bucket
curl -X POST $GRAPHYTE/api/v1/buckets \
  -H "Authorization: Bearer $GRAPHYTE_API_KEY" \
  -d '{"name": "support-docs"}'

Objects

PUT /api/v1/buckets/:bucket/objects/:key stores the request body under key (which may contain slashes), keeping its Content-Type. Same key again replaces the object, like S3. Uploading identical bytes is a no-op.

POST /api/v1/buckets/:bucket/objects takes multipart/form-data with one or more file fields and an optional prefix.

GET /api/v1/buckets/:bucket/objects?prefix= lists objects. GET …/objects/:key returns the bytes; add ?meta=1 for metadata and index status. DELETE …/objects/:key removes it.

After an upload the object is pending while Graphyte reads it, then indexed, failed (with an error), or unsupported for files it stores but doesn't read yet. POST /api/v1/objects/:id/reindex reads it again.

upload and check
curl -X PUT $GRAPHYTE/api/v1/buckets/support-docs/objects/manuals/charger.pdf \
  -H "Authorization: Bearer $GRAPHYTE_API_KEY" \
  -H "Content-Type: application/pdf" \
  --data-binary @charger.pdf

curl "$GRAPHYTE/api/v1/buckets/support-docs/objects/manuals/charger.pdf?meta=1" \
  -H "Authorization: Bearer $GRAPHYTE_API_KEY"
# → { "object": { "status": "indexed", "chunks": 42, ... } }

Answer

POST /api/v1/answer with question and optionally bucket. Graphyte searches, then asks the model to answer using only those passages. The answer comes back as segments: runs of text, each with the citations it rests on. sources holds every passage that was read.

If the passages don't contain the answer, the reply says so. refused: true means the model declined the question.

response
{
  "segments": [
    { "text": "400 V three-phase on its own 63 A breaker.",
      "citations": [{ "chunkId": 812, "title": "support-docs/manuals/charger.pdf (page 14)", "citedText": "…" }] }
  ],
  "sources": [ … ], "model": "…", "refused": false
}

Research

POST /api/v1/research takes the same body as Answer. The model plans and runs its own searches (up to a dozen rounds), then writes a report with citations. The response has the same shape as Answer, plus steps: the queries it ran, in order.

Research can take a few minutes. Set your client timeout to at least five minutes.