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

What it finds

Your question rarely matches the document that answers it.

So a search here is not hunting for your phrase. It goes after what you meant, and after the documents that back the answer up — on top of a plain search that always runs anyway.

  • what you meant

    Documents your words never matched

    Your question says renewal; the document says uplift, or true-up, or escalator. Nothing about those strings resembles each other, and the document comes back anyway — because we have read enough of your content to know they are the same subject.

  • not the ones that resemble it

    The documents that support the point

    Once it knows which claims are relevant it goes looking for everything in your corpus that states them, so the evidence behind an answer is a real set of documents rather than whichever passage happened to score highest.

always, at full strength

Everything an ordinary good search would find

The literal search for what you typed runs on every question and is never held back, traded off or turned down to make room for anything else. Whatever the rest of the system manages or fails to manage, the plain search is always underneath it — on a question where nothing else helps, its results are what you get.

the floor

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, and you see both, with the system each came from beside it.
  • On the graph tier, from the Growth plan up, we do notice when they conflict and tell you: statements in different documents that disagree are listed for a person to review. The call is still yours — once you make it, answers follow it — and it will not catch every disagreement, so treat the list as a lead rather than a guarantee.
Onboarding completion—reduces→Ninety-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, each with the system it came from. Read the order rather than the score: a rank is meaningful within one response and means nothing across two.
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 connections the question travelled across, in readable form — what it recognised in your wording, and what that led it to.
metadata
Timings. This is what makes a slow search diagnosable from your side, without asking us to go and read 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 the things courses contain rather than the things a ticket does. A course library is not read the same way as a ticket queue.

  • generic

    Anything else

    A source with no particular kind of content declared. 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 connections between your documents are unavailable
Search answers normally from the content itself. You lose the cross-document reach, never the results.
The question mentions nothing we recognise
There is nothing to connect it to, so the plain search is the answer. No error, no empty response.
Nothing relevant is found to connect
The extra work contributes nothing and the ordinary results stand unchanged.
Writing the answer fails
You get 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