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.
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.
Asserted by
- 0.95 confidence
Q3 Retention Review
notion
- 0.88 confidence
Support Themes 2026
zendesk
- 0.81 confidence
Activation Playbook v4
lms_content
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.
{
"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.
| If this fails | 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. |
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.
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" }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