AI and search: your own keys, your own knowledge sources

Embed
Preview of the card
<a href="https://forumulate.com/guides/ai-and-search"><img src="https://forumulate.com/guides/_api/public/orgs/046a9bc0-d530-43ae-9bae-af7945008cda/spaces/36aa4df0-1e95-4cef-8ae9-795169441345/pages/0993a310-6044-4994-b562-aed37b84ca63/social-card.svg?v=3e7ae33eec8b" alt="AI and search: your own keys, your own knowledge sources" width="600" height="315"></a>

Forumulate's AI features are bring-your-own-key, per organization. There is no platform AI key: nothing is sent to a model provider on your behalf unless your organization has connected its own account, and the bill for those calls is yours, from your provider. This guide covers the three places that shows up in the API: the embedding provider behind semantic search, the external knowledge sources the assistant may answer from, and the insights report that tells you what readers asked.

Semantic search and the embedding provider

Search ranks results with two arms: keyword matching and vector similarity. The vector arm needs an embedding model. An organization with no key connected falls back to a deterministic offline embedding, so search still works but only loosely understands meaning. Connect a provider to get real semantic results.

Provider

provider

Default model

Default dimensions

OpenAI

openai

text-embedding-3-small

1536

Google

google

text-embedding-004

768

All five routes need the org.manage_integrations capability.

PUT /orgs/{orgId}/search/embedding-provider
{
  "provider": "openai",
  "apiKey": "sk-...",
  "model": "text-embedding-3-small",
  "dimensions": 1536
}

model and dimensions are optional and default as in the table. The index stores vectors up to 1536 wide, so a model that produces more is refused with a 422 telling you to choose a smaller one. The key is stored encrypted and never read back; the response carries only a keyHint.

Embeddings from different models cannot be compared, so a connect that changes the provider or the model, and a disconnect, re-embed the organization's pages straight away. The response says how many pages that was (reindexed). Community topics are re-embedded by reindex below. Prove a key works before you depend on it:

POST /orgs/{orgId}/search/embedding-provider/test

It answers { "ok": true, "model": "...", "dimensions": 1536 }, or a 422 if no provider is connected, or a 502 if the call to the provider failed or returned no vector.

Method and path

What it does

GET /orgs/{orgId}/search/embedding-provider

Status: provider, model, usingFallback, and indexed page/topic counts.

PUT /orgs/{orgId}/search/embedding-provider

Connect or change the provider.

DELETE /orgs/{orgId}/search/embedding-provider

Disconnect and return to the offline fallback.

POST /orgs/{orgId}/search/embedding-provider/test

One cheap call to check the key.

POST /orgs/{orgId}/search/embedding-provider/reindex

Re-embed pages and community topics: { indexed, topics }.

Use GET first when someone reports that semantic search does not find a page: indexed is how much of the corpus the vector arm can see. Use reindex after a model change or to repair drift.

Knowledge sources for the assistant

The assistant answers out of your own content. If the answers live somewhere else too, add that as a knowledge source: either a page that is fetched once, or a block of text you paste in. Reading needs org.read; adding or removing needs org.manage_integrations.

POST /orgs/{orgId}/ai/sources
{
  "kind": "url",
  "title": "Shipping policy",
  "url": "https://example.com/shipping",
  "spaceId": null
}
POST /orgs/{orgId}/ai/sources
{ "kind": "text", "title": "Refund rules", "content": "Refunds are issued within 14 days..." }
  • kind is url or text. A url source requires url, and its text is fetched when you add it, not on every question.

  • title is 1 to 200 characters. Stored text is capped at 40,000 characters.

  • spaceId limits the source to one space; leave it out or null for the whole organization.

  • The response is 201 { "id": "..." }.

GET /orgs/{orgId}/ai/sources lists them (id, kind, title, url, spaceId) and DELETE /orgs/{orgId}/ai/sources/{id} removes one.

What readers asked: insights

GET /orgs/{orgId}/ai/insights

Needs org.read. It tallies up to 5,000 of the organization's assistant questions:

Field

Meaning

total

Questions asked.

answered, unanswered

How many the assistant could and could not answer.

helpful, notHelpful

Reader feedback on answers.

topQuestions

The 15 most repeated questions, with counts.

knowledgeGaps

Questions it could not answer: the content to write next.

unhelpfulAnswers

Answers readers marked unhelpful: the content to fix.

Questions are lower-cased and trimmed before counting, so "How do I reset?" and "how do i reset?" are one entry.

In the API

Every operation below is also reachable from the other surfaces without a dedicated command. forumulate api <Operation> calls it from the CLI, the JavaScript SDK has a typed method for each one (the last column names it; the Python and Go clients are generated from the same spec), and an agent reaches the organization-scoped ones through the MCP call_api tool. Where a CLI command or MCP tool exists too, the last column names it. Operation names link to the API reference.

Ai Org

Operation

Request

What it does

Shortcuts

AiOrg_insights

GET /orgs/{orgId}/ai/insights

List insights in an organization

client.ai.org.insights()

AiOrg_usageReport

GET /orgs/{orgId}/ai/usage

Get the usage in an organization

client.ai.org.usageReport()

AiOrg_listSources

GET /orgs/{orgId}/ai/sources

List sources in an organization

client.ai.org.listSources()

AiOrg_addSource

POST /orgs/{orgId}/ai/sources

Create a source in an organization

client.ai.org.addSource()

AiOrg_removeSource

DELETE /orgs/{orgId}/ai/sources/{id}

Delete the source

client.ai.org.removeSource()

Embedding Provider

Operation

Request

What it does

Shortcuts

EmbeddingProvider_status

GET /orgs/{orgId}/search/embedding-provider

Get the embedding provider in an organization

client.search.embeddingProvider.status()

EmbeddingProvider_connect

PUT /orgs/{orgId}/search/embedding-provider

Replace the embedding provider in an organization

client.search.embeddingProvider.connect()

EmbeddingProvider_disconnect

DELETE /orgs/{orgId}/search/embedding-provider

Delete the embedding provider in an organization

client.search.embeddingProvider.disconnect()

EmbeddingProvider_test

POST /orgs/{orgId}/search/embedding-provider/test

Test the embedding provider

client.search.embeddingProvider.test()

EmbeddingProvider_reindex

POST /orgs/{orgId}/search/embedding-provider/reindex

Create the reindex in an organization (embedding provider)

client.search.embeddingProvider.reindex()

Org Lens

Operation

Request

What it does

Shortcuts

OrgLens_ask

POST /orgs/{orgId}/ask

Create the ask in an organization

client.ai.lens.ask()

Questions

Operation

Request

What it does

Shortcuts

Questions_list

GET /orgs/{orgId}/spaces/{spaceId}/questions

List questions in a space

client.questions.list()

Questions_ingest

POST /orgs/{orgId}/spaces/{spaceId}/questions

Create a question in a space

client.questions.ingest()

Questions_clusters

GET /orgs/{orgId}/spaces/{spaceId}/questions/clusters

List clusters in a space

client.questions.clusters()

Questions_remove

DELETE /orgs/{orgId}/spaces/{spaceId}/questions/{questionId}

Delete the question

client.questions.remove()

Questions_draft

POST /orgs/{orgId}/spaces/{spaceId}/questions/drafts

Create a draft in a space

client.questions.draft()

Questions_suggest

POST /orgs/{orgId}/spaces/{spaceId}/items/{itemId}/suggestions

Create a suggestion in a space

client.questions.suggest()<br>MCP propose_correction

Questions_listAssertions

GET /orgs/{orgId}/spaces/{spaceId}/items/{itemId}/assertions

List assertions in a space

client.questions.listAssertions()

Questions_addAssertion

POST /orgs/{orgId}/spaces/{spaceId}/items/{itemId}/assertions

Create an assertion in a space

client.questions.addAssertion()

Questions_runAssertions

POST /orgs/{orgId}/spaces/{spaceId}/items/{itemId}/assertions/run

Run the assertion

client.questions.runAssertions()

Questions_removeAssertion

DELETE /orgs/{orgId}/spaces/{spaceId}/items/{itemId}/assertions/{assertionId}

Delete the assertion

client.questions.removeAssertion()

Questions_uncovered

GET /orgs/{orgId}/spaces/{spaceId}/uncovered

Get the uncovered in a space

client.questions.uncovered()

Retrieval

Operation

Request

What it does

Shortcuts

Retrieval_retrieve

POST /orgs/{orgId}/search

Create the search in an organization

client.search.retrieval.retrieve()<br>MCP find_resolution<br>MCP check_prerequisites

Operation

Request

What it does

Shortcuts

Search_run

GET /orgs/{orgId}/spaces/{spaceId}/docs/search

Get the search in a space (docs)

forumulate docs search<br>client.docs.search.run()<br>MCP search

Operation

Request

What it does

Shortcuts

UnifiedSearch_search_

GET /orgs/{orgId}/search

Get the search in an organization

forumulate search query<br>client.search.search()<br>client.search.unified()<br>MCP search

UnifiedSearch_recent

GET /orgs/{orgId}/search/recent

List recent search in an organization

forumulate search recent<br>client.search.recent()

UnifiedSearch_semanticSearch

GET /orgs/{orgId}/search/semantic

Get the semantic in an organization

forumulate search semantic<br>client.search.semanticSearch()

UnifiedSearch_reindex

POST /orgs/{orgId}/search/reindex

Create the reindex in an organization

forumulate search reindex<br>client.search.reindex()

UnifiedSearch_tags

GET /orgs/{orgId}/search/tags

List tags in an organization

forumulate search tags<br>client.search.tags()

UnifiedSearch_tagHub_

GET /orgs/{orgId}/search/tags/{tag}

Get the tag (search)

forumulate search tag<br>client.search.tagHub()

UnifiedSearch_gaps

GET /orgs/{orgId}/search/gaps

List gaps in an organization

forumulate search gaps<br>client.search.gaps()

The Forumulate teamUpdated