Start here
3 steps- 1. Create and copy an API key.
- 2. Enable and configure providers.
- 3. Replace the placeholder in the curl example and send the request.
Send one request to eligible search providers. SearchMesh returns results and shows which providers succeeded, skipped, or failed.
Automatic provider selection
POST https://search-staging.prosvita.io/api/v1/searchcurl --request POST \
--url "https://search-staging.prosvita.io/api/v1/search" \
--header "Authorization: Bearer poshuk_REPLACE_ME" \
--header "Content-Type: application/json" \
--data '{
"query": "open source metasearch engines",
"limit": 10,
"aggregation": "ranked"
}'Use this endpoint when SearchMesh should choose eligible providers. The request body must not include providers.
Let SearchMesh select providers
POST https://search-staging.prosvita.io/api/v1/searchUse the automatic endpoint for one provider-neutral result set. raw results do not expose provider identity or adapter metadata.
What happens: When at least one eligible provider is ready, SearchMesh sends your validated query and a fixed, generic capability taxonomy to OpenAI Decisions. It uses the returned capability matches to choose from providers eligible to your account.
What it does not send: provider identities, credentials, secrets, or account metadata. Your query is sent verbatim, so do not include information you do not want to share with OpenAI.
Need direct control? Use search_providers. It bypasses OpenAI selection and uses only provider credentials configured for your account.
Account credentials take priority. In production, a rejected account credential can fall back once to a platform credential. If no platform credential is available, providers that support anonymous requests can use that path. Development and staging use account credentials only.
Choose account-configured providers
POST https://search-staging.prosvita.io/api/v1/search_providersUse this endpoint when you want to choose provider IDs or keep provider-attributed groups. Unknown IDs return an error. Known but unavailable providers are reported as skipped.
Required headers
Authorization: Bearer poshuk_REPLACE_ME
Content-Type: application/jsonqueryproviderssearch_providers. Omit it to use every available account credential. For explicit IDs, provide up to 20 canonical provider IDs. Your plan can set a lower cap.limitaggregationraw, grouped, or ranked. Default: raw.language and regionsafe_search and time_rangeoff, moderate, or strict. Time range: day, week, month, or year.timeout_ms and include_metadataGET https://search-staging.prosvita.io/api/v1/providersUse the same API key to list providers ready for your account. Filter by one exact, case-sensitive category, for example ?category=independent-index.
{
"providers": [
{
"id": "brave",
"name": "Brave Search",
"description": "Broad web search backed by Brave's independent index.",
"categories": ["general-web", "independent-index"]
}
]
}Each provider has an id, name, description, and categories. A valid category can return an empty list. Categories help selection but do not rank providers.
This is a local readiness check. It does not test upstream health, rate limits, circuits, or your credit balance.
require "json"
require "net/http"
uri = URI("https://search-staging.prosvita.io/api/v1/search")
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer poshuk_REPLACE_ME"
request["Content-Type"] = "application/json"
request.body = JSON.generate({
query: "open source metasearch engines",
limit: 10,
aggregation: "ranked",
})
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") { |http| http.request(request) }
puts JSON.pretty_generate(JSON.parse(response.body))async function main() {
const response = await fetch("https://search-staging.prosvita.io/api/v1/search", {
method: "POST",
headers: {
Authorization: "Bearer poshuk_REPLACE_ME",
"Content-Type": "application/json",
},
body: JSON.stringify({
query: "open source metasearch engines",
limit: 10,
aggregation: "ranked",
}),
});
console.log(await response.json());
}
main().catch((error) => {
console.error(error);
process.exitCode = 1;
});import json
from urllib.request import Request, urlopen
payload = {
"query": "open source metasearch engines",
"limit": 10,
"aggregation": "ranked",
}
request = Request(
"https://search-staging.prosvita.io/api/v1/search",
data=json.dumps(payload).encode(),
headers={
"Authorization": "Bearer poshuk_REPLACE_ME",
"Content-Type": "application/json",
},
method="POST",
)
with urlopen(request) as response:
print(json.loads(response.read()))Connect a remote MCP client when you do not want to manage an API key. The client opens your browser for SearchMesh sign-in and consent.
MCP endpoint
https://search-staging.prosvita.io/mcpsearch uses the same automatic selection flow as the HTTP API. search_providers bypasses selection and uses only account-supplied provider credentials.
Every search grant includes search, search_providers, and user_feedback. Approve account:read to also use list_providers and account_status.
{
"mcpServers": {
"searchmesh": {
"url": "https://search-staging.prosvita.io/mcp"
}
}
}Client setup varies by workspace. Revoke access from MCP connections.
Successful responses include request_id, status, results, providers.successful, providers.skipped, providers.failed, and meta. A partial provider failure can still return results.
SearchMesh reserves the full applicable quote before provider work starts. Failed and skipped providers cost zero, and the final charge does not exceed the quote. Subscription credits are used first, then purchased Mesh Credits. Purchased credits do not expire.
If credits are too low, the response returns insufficient_credits. Add Mesh Credits in Billing, wait for renewal, or use fewer providers where selection is supported.
Other non-2xx responses include an error object with a request ID. Include that ID when you contact support.
Allow anonymous usage measurement on public pages? Necessary sign-in and security cookies are always used.