Strut AI Grounding Engine — Developer Integration
Strut is a web grounding engine. It discovers sources, extracts their readable content, ranks the passages that answer your query, and returns them with quotes verified against the page — optionally with a synthesized answer on top.
/v1/ground fetches live pages, isolates the passages that answer the query, and returns each with a quote taken from the page and a bracketed citation [1]. Retrieval-only responses typically land in ~1.3s; adding a synthesized answer takes about 2s.
Quick cURL Test
curl -X POST "$STRUT_BASE_URL/v1/ground" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $STRUT_API_KEY" \
-d '{
"query": "What are topological quantum qubits?",
"max_sources": 3
}'
Telemetry & Pipeline Benchmarks
Every grounding response includes microsecond-precision breakdown telemetry:
Strips ads, scripts, navbars, and converts raw HTML directly to clean semantic markdown.
Preserves header hierarchy and extracts contextual 350-word passages.
Exact phrase matching and semantic alignment ranking across evaluated chunks.
Every factual claim is aligned to exact source URLs and quotes with `[1]`, `[2]` tags.
Authentication & Keys
Every request to /v1/ground, /v1/search and /v1/extract
must carry an API key. Create one in the
developer console.
curl -X POST "https://your-deployment.example.com/v1/search" \
-H "Authorization: Bearer strut_live_..." \
-H "Content-Type: application/json" \
-d '{"query": "who invented the transistor"}'
x-api-key: strut_live_... is accepted as an alternative to the
Authorization header.
Scopes
Each key carries a scope, chosen when the key is created and enforced on every request.
| Scope | Grants |
|---|---|
full | /v1/ground, /v1/search, /v1/extract |
ground-only | /v1/ground |
search-only | /v1/search |
extract-only | /v1/extract |
Rate limits
Each key has a per-minute request limit, set when the key is created. Every response carries the current state:
| Header | Meaning |
|---|---|
X-RateLimit-Limit | Requests permitted per minute for this key. |
X-RateLimit-Remaining | Requests left in the current window. |
X-RateLimit-Reset | Seconds until the window resets. |
Retry-After | Sent with 429; seconds to wait before retrying. |
Rate limit counters are held per server instance. On a horizontally scaled deployment the effective limit is per instance, not global — a shared store is required for a hard global limit.
Error responses
| Status | Meaning |
|---|---|
401 | No key supplied, or the key is unknown or revoked. |
403 | The key is valid but its scope does not cover this endpoint. |
429 | The key's per-minute rate limit is exhausted. |
402 | The account's monthly spend cap has been reached. |
Every error body is JSON with an error field and, where useful, a hint.
POST /v1/ground
Generates an end-to-end factually grounded answer from live web sources with verified quotes and bracketed citations.
Request Parameters
| Field | Type | Default | Description |
|---|---|---|---|
query | string | Required | The question or prompt to ground against the live web. |
max_sources | number | 5 | Maximum number of candidate web pages to evaluate. |
model | string | strut/web-grounding | Model identifier (strut/web-grounding, strut-ground-v1, groq/llama-3.3-70b-versatile). |
include_answer | boolean | false | When false (default) the response returns extracted, reranked passages with verified quotes and no synthesized prose — roughly 1.6s and zero token cost. Recommended when the consumer is an LLM. Set true for a written answer (adds ~0.6s and the model call). |
stream | boolean | false | Whether to stream response tokens via Server-Sent Events (SSE). |
Response Payload
{
"query": "What are topological qubits?",
"grounded_answer": "Topological qubits store quantum information in non-local topological properties of matter [1]...",
"citations": [
{
"source_index": 1,
"title": "Topological quantum computer - Wikipedia",
"url": "https://en.wikipedia.org/wiki/Topological_quantum_computer",
"verified_quote": "Topological qubits are quantum bits that store information in non-local...",
"relevance_score": 0.8842
}
],
"model": "strut/web-grounding",
"telemetry": {
"fetchMs": 450,
"extractMs": 18,
"chunkMs": 2,
"rerankMs": 6,
"synthesis_ms": 980,
"total_end_to_end_ms": 1456
}
}
POST /v1/search
Discovery and ranking without synthesis. search_depth=fast returns ranked
candidates from the index layer; deep additionally fetches each page, extracts
the readable text and reranks passages. Neither depth calls a language model.
Request Parameters
| Field | Type | Default | Description |
|---|---|---|---|
query | string | — | Required. The search query. |
search_depth | string | fast | fast or deep. |
max_results | integer | 5 | Results to return. |
include_domains | string[] | [] | Restrict discovery to these domains. |
exclude_domains | string[] | [] | Drop results from these domains. |
POST /v1/extract
Fetch a list of URLs and return their readable content as clean Markdown, with scripts, styles and navigation removed. Useful when you already know which pages you want.
| Field | Type | Default | Description |
|---|---|---|---|
urls | string[] | — | Required. URLs to fetch and extract. |
GET /v1/models
Engine capabilities, the models available for synthesis, which providers are configured, and the metered rate. Unauthenticated. The developer console reads the rate from here so the price it displays cannot drift from the rate the spend cap is enforced against.
{
"engine": "Strut Grounding Engine",
"pricing": { "cost_per_query": 0.0001, "currency": "USD" },
"providers": { "web_search_index": { "mojeek_configured": false } }
}
SSE Token Streaming
Set stream: true on /v1/ground to receive the answer as
Server-Sent Events. Citations are resolved before the first token, so the source list is
available immediately and the prose arrives incrementally. Streaming implies
include_answer; a retrieval-only request has nothing to stream.
curl -N -X POST "$STRUT_BASE_URL/v1/ground" \
-H "Authorization: Bearer $STRUT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query": "...", "stream": true, "include_answer": true}'
LangChain & LangGraph Integration
Use Strut as a verified live grounding tool in your autonomous AI agents:
from langchain.tools import tool
import requests
@tool
def strut_grounding_tool(query: str) -> str:
"""Search the live web and obtain factually grounded synthesis with verified citations."""
res = requests.post(
"$STRUT_BASE_URL/v1/ground",
json={"query": query, "max_sources": 4},
headers={"Content-Type": "application/json"}
)
if not res.ok:
return f"Lookup error: {res.text}"
data = res.json()
return data.get("grounded_answer", "")
# Attach to LangChain Agent
from langchain_openai import ChatOpenAI
from langchain.agents import create_openai_tools_agent, AgentExecutor
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
tools = [strut_grounding_tool]
llm = ChatOpenAI(model="gpt-4o-mini", temperature=0)
prompt = ChatPromptTemplate.from_messages([
("system", "You are an autonomous research agent using Strut AI web grounding."),
MessagesPlaceholder(variable_name="chat_history", optional=True),
("user", "{input}"),
MessagesPlaceholder(variable_name="agent_scratchpad"),
])
agent = create_openai_tools_agent(llm, tools, prompt)
executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
# Run Query
response = executor.invoke({"input": "What are the latest developments in quantum qubits in 2026?"})
print(response["output"])
Vercel AI SDK Integration
Wire Strut grounding seamlessly with the ai package in Next.js App Router:
import { openai } from '@ai-sdk/openai';
import { streamText, tool } from 'ai';
import { z } from 'zod';
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4o-mini'),
messages,
tools: {
strutGround: tool({
description: 'Ground live web queries with sub-second verified factual citations',
parameters: z.object({
query: z.string().describe('The web search query to ground factually')
}),
execute: async ({ query }) => {
const res = await fetch('$STRUT_BASE_URL/v1/ground', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ query, max_sources: 4 })
});
return await res.json();
}
})
}
});
return result.toDataStreamResponse();
}
Strut Python SDK Client
Lightweight drop-in client for Python backends:
from sdk.python.strut import StrutClient
client = StrutClient(base_url="https://your-deployment.example.com", api_key=os.environ["STRUT_API_KEY"])
# 1. Factual Grounding
grounded = client.ground("What is topological quantum computing?")
print("Answer:", grounded["grounded_answer"])
# 2. Fast AI Search
search_res = client.search("Latest AI breakthroughs 2026", search_depth="fast")
for item in search_res["results"]:
print(f"• {item['title']} ({item['domain']}): {item['snippet'][:100]}...")
# 3. Batch Markdown Extraction
extracted = client.extract(["https://en.wikipedia.org/wiki/Quantum_computing"])
print("Markdown preview:", extracted["results"][0]["markdown"][:300])