Skip to content

The product

From what you've written to something you can act on.

You already have the content. This is what it becomes: one place to ask, answers in plain language, and the evidence behind every one of them.

  • no crawler
  • nothing of yours to connect
  • nothing to migrate

End to end

Three moves, and none of them are yours to build.

What you send, what we make of it, and what your users get back.

1 · You send your content

Whatever you already have, with your own identifier on it. Most teams hook this into whatever already fires when their content changes, and never think about it again.

one call per document · safe to repeat

2 · We read it properly

Not just indexed for search — read for what it actually claims, and for which of your other documents say the same thing. That is what lets an answer join two of them up.

what it says · and who said it

3 · Your users get an answer

In plain language, with the passages behind it, how many sources agree, and a clear admission when your content does not cover the question.

the answer · and the receipts

How it finds things

Your question rarely matches the document that answers it.

So it searches three ways at once: for what you asked, for what you meant, and for the documents that back the answer up.

  1. Direct

    weight 1.0

    Hybrid dense and keyword search on the query exactly as it was asked.

    This lane is the floor. It runs on every search, at full weight, whatever the graph does or fails to do.

    always runs
  2. Expanded

    weight 0.6

    Entities in the query are resolved to graph nodes, traversed two hops, then the query is re-embedded together with the names it reached.

    This is how a search reaches content whose wording the question never used. Ask about React and the traversal pulls in JSX and Meta.

  3. Evidence

    weight 0.6

    The original question is asked again, restricted to the documents that provide provenance for the facts the traversal crossed.

    Ranked by corroboration — how many distinct documents assert each fact. This is the lane that finds the passage supporting a point rather than the passage matching a phrase.

Reciprocal rank fusion

The three result sets are merged on rank rather than on score, so no lane can dominate because its similarity numbers happen to be on a different scale. The top documents are then hydrated to chunk text and synthesised into one cited answer.

When your content changes

Your answers keep up with your content.

Re-send a document and it replaces the old version. Unpublish one and it stops influencing answers — including any claim that was only holding up because of it.

  • Every document that asserts a fact keeps its own confidence for it. Removing one document does not remove the fact if three others still say it.
  • This is bookkeeping, not judgement: we do not decide which of two conflicting documents is right. Both are kept, with their sources, and the answer can say they disagree.
  • The console has a contradictions surface for claim-against-claim review. Detection is specified and not yet built — the page ships as a declared placeholder, and we would rather tell you that here.
Onboarding completionreducesNinety-day churn3 sources

Asserted by

  • Q3 Retention Review

    notion

    0.95 confidence
  • Support Themes 2026

    zendesk

    0.88 confidence
  • Activation Playbook v4

    lms_content

    0.81 confidence

What comes back

Everything it learned on the way, not just the answer.

The passages, the answer, the connections it used and how long each step took — because the point is that you can check any of it.

POST /v1/search — response
{
  "results": [
    { "documentId": "...", "externalId": "account-4471",
      "title": "Account 4471 — Team Annual",
      "integrationType": "salesforce",     // which system it came from
      "score": 0.0263,
      "chunk": "Plan: Team Annual. Seats: 240. SSO entitlement: false.",
      "summary": null,
      "metadata": { "accountUrl": "https://crm.example/4471" } }
  ],
  "answer": {
    "text": "Not on your current plan — account 4471 is on Team Annual [1]...",
    "citations": [
      { "marker": 1, "documentId": "...", "externalId": "account-4471",
        "title": "Account 4471 — Team Annual" }
    ],
    "tokensIn": 3184, "tokensOut": 96, "generationMs": 890
  },
  "graphContext": {
    "facts": ["Team Annual —excludes→ SAML SSO (confidence 0.93, 2 sources)"],
    "resolvedFromQuery": ["SSO"],
    "expandedEntities": ["SAML SSO", "Team Annual", "Business"]
  },
  "metadata": {
    "mode": "graph", "retrievalPath": "fused", "graphExpansion": true,
    "searchTimeMs": 661, "vectorSearchMs": 142, "graphTraversalMs": 187,
    "entitiesResolved": 1, "entitiesExpanded": 3
  }
}
results
Ranked passages with the score AND its unit. A 0.026 fusion rank and a 0.700 similarity are not comparable numbers, so we never print them as if they were.
answer
The cited prose, with token counts and generation latency. Null rather than absent if synthesis failed, so your code has one shape to handle.
graphContext
The facts the traversal crossed, rendered readably, plus which entities were resolved from the question and which were reached from them.
metadata
Per-step timings. This is what makes a slow search diagnosable from the caller side without asking us to look at a log.

Your systems

Records and prose, read differently, joined anyway.

Tell us which system something came from and we read it accordingly. Then the account in a billing row and the account in a support ticket resolve to one thing, which is what lets an answer span the two.

  • salesforce · billing · product analytics

    Records — what is true of this account

    Plans, entitlements, seats, renewal dates, usage. Serialise the row and send it as text; we read it as facts about that account, and it becomes joinable to everything else that mentions them.

  • zendesk

    Support history — what went wrong before

    Where the same problem is described five different ways. Resolution collapses those into one entity rather than five near-duplicates, so the fifth person to hit it finds the first four.

  • notion · help centre

    Documentation — how any of it works

    Wikis, runbooks, policies, decision records. The content that explains why, and that nobody can ever find at the moment they need it.

  • lms_content

    Learning content — how to do it

    Courses and modules, read for concepts, skills and prerequisites rather than for problems and resolutions. A course library is not read the same way as a ticket queue.

  • generic

    Anything else

    A source with no domain hints. Every workspace is seeded with one, so a first call works with nothing configured.

When something breaks

It degrades, it does not fall over.

Worth reading before you build on it, because it tells you how much error handling you actually need — which is less than you would expect.

What you still get

The graph store is unreachable
Vector search returns results as normal. The expanded and evidence lanes are skipped.
Entity extraction on the query finds nothing
Nothing to traverse, so the direct lane is the answer. No error, no empty response.
Traversal reaches no facts
Graph expansion contributes nothing and fusion has one lane to fuse. Results stand.
Answer synthesis fails
The response carries a null answer and the ranked documents intact. The caller loses the prose, never the sources.

Connecting it

Two calls, and nothing to migrate.

No library to adopt, no framework to buy into, and nothing in your stack that depends on ours.

POST /v1/ingest
curl -X POST https://api.graas.ai/v1/ingest \
  -H "x-api-key: $GRAAS_KEY" \
  -H "content-type: application/json" \
  -d '{
    "sourceSlug": "billing",
    "externalId": "account-4471",
    "title": "Account 4471 — Team Annual",
    "textContent": "Plan: Team Annual. Seats: 240.
                    SSO entitlement: false. Renews: 2027-03-01."
  }'

# 202 Accepted
# { "documentId": "...", "externalId": "account-4471",
#   "status": "extracting", "chunksCreated": 1,
#   "statusUrl": "/v1/ingest/.../status" }
POST /v1/search
curl -X POST https://api.graas.ai/v1/search \
  -H "x-api-key: $GRAAS_KEY" \
  -H "content-type: application/json" \
  -d '{ "query": "does onboarding reduce churn?" }'

FAQ

Frequently asked

The questions engineers ask in the first call.

Start with the free tier. Ship the first answer today.

RAG is free, with no card and no sales call. Add the graph when your corpus earns it.

  • no card required
  • first workspace is free
  • one POST to ingest