Skip to content
SearchJet
Updated October 1, 2026

Search API Deep Dive

The Search API is the core of SearchJet. A single GET endpoint runs full-text search, powered by Meilisearch, across your site's index. It can also do hybrid semantic search and generate AI answers. This page goes deeper than the REST API Reference, with usage notes and plan differences.

Endpoint and authentication

GET https://app.searchjetengine.com/api/v1/search

The path must start with /api: requests to https://app.searchjetengine.com/v1/search return 404.

Send your public search key, which is shown on the dashboard's Sites list as "Public Key". It's read-only, and CORS is enabled, so browsers can call the endpoint directly. The private key doesn't work here: it returns 401 INVALID_API_KEY.

Authorization: Bearer YOUR_PUBLIC_KEY
Accept: application/json

Example request

curl -G "https://app.searchjetengine.com/api/v1/search" \
  -H "Authorization: Bearer $SEARCHJET_PUBLIC_KEY" \
  -H "Accept: application/json" \
  --data-urlencode "q=installation guide" \
  --data-urlencode "limit=10"
const params = new URLSearchParams({ q: 'installation guide', limit: '10' });
const res = await fetch(`https://app.searchjetengine.com/api/v1/search?${params}`, {
  headers: { Authorization: 'Bearer YOUR_PUBLIC_KEY', Accept: 'application/json' },
});
const data = await res.json();
data.results.forEach((hit) => console.log(hit.title, hit.url));
import os
import httpx

response = httpx.get(
    "https://app.searchjetengine.com/api/v1/search",
    params={"q": "installation guide", "limit": 10},
    headers={
        "Authorization": f"Bearer {os.environ['SEARCHJET_PUBLIC_KEY']}",
        "Accept": "application/json",
    },
)
response.raise_for_status()
for hit in response.json()["results"]:
    print(hit["title"], hit["url"])

Parameters

Parameter Notes
q Required. If it's missing, you get 400 MISSING_QUERY.
limit 1 to 100, default 20
page / offset page defaults to 1. If you send offset, it overrides page.
filters Meilisearch filter string, at most 1,000 characters
sort Comma-separated attr:asc or attr:desc, up to 5
attributes Comma-separated fields to return, within your plan's field list
semantic, semanticRatio Hybrid semantic search (Pro and above)
ai_answer true adds an AI-generated answer

On Pro, Growth and Enterprise you can also use facets, attributesToHighlight, attributesToCrop, cropLength, highlightPreTag, highlightPostTag, showMatchesPosition and matchingStrategy. On Free these are silently ignored.

Response

{
  "results": [
    {
      "id": "doc-123",
      "title": "Installation Guide",
      "url": "https://example.com/docs/installation",
      "type": "page",
      "excerpt": "A step-by-step guide to installing SearchJet..."
    }
  ],
  "remaining_quota": 48766,
  "total": 12,
  "limit": 10,
  "offset": 0,
  "page": 1,
  "semantic_search_used": false,
  "facet_distribution": [],
  "facet_stats": [],
  "processing_time_ms": 3
}
  • results is the array of hits. It isn't wrapped in another object.
  • total is an estimate of the number of matches.
  • remaining_quota shows the searches left in your site's monthly quota. It's null on unlimited plans, and -1 if metering is briefly unavailable.
  • Optional keys: answer (with ai_answer=true), semantic_ratio (on semantic searches), and meta (for example, warnings).

Which fields each hit contains

Hits contain only the fields your plan returns:

  • Free: id, title, url, type, thumbnail, price, currency, sku. There's no content or excerpt, so design your result template around the title.
  • Pro: adds excerpt, content, author, date, image, categories, tags, regular_price, sale_price and stock_status.
  • Growth and Enterprise: every stored field.

On Free, ids come back as site__. To recover your own id, strip the prefix. Hits have no highlighting by default. On paid plans, set attributesToHighlight (or attributesToCrop) to get a _formatted object on each hit.

Filters

type = "post"
price < 50
type = "product" AND price >= 10
type = "post" OR type = "page"
NOT type = "archive"
  • On Free, you can filter only on id, title, type, price, currency and sku. Any other field returns 400 INVALID_FILTER ("Field 'x' is not available in your plan").
  • On paid plans, you can filter on any attribute marked filterable in Index Settings – General Attributes. Anything else returns INVALID_FILTER with a hint to add it to filterableAttributes.
  • Unbalanced quotes or parentheses also return INVALID_FILTER.

Comparison operators work on numbers, so to filter by date, index a numeric timestamp field. For more patterns, see Building Search Queries.

Sorting

sort=date:desc or sort=price:asc,title:asc (up to 5 fields). Free can sort on one field from id, title or price. Paid plans can sort on any sortable attribute. An unsupported sort returns 400 INVALID_SORT.

Send semantic=true, and optionally semanticRatio (0 = keyword only, 1 = semantic only, default 0.5). It requires:

  • Pro or higher. Otherwise you get 403 SEMANTIC_PLAN_REQUIRED.
  • Semantic search enabled in your site settings. Otherwise you get 403 SEMANTIC_NOT_ENABLED.

When it ran, the response has semantic_search_used: true and semantic_ratio.

AI answers

Add ai_answer=true to get a short generated answer based on the top results. This works on all plans, within the monthly AI-answer quota: Free 50, Pro 500, Growth 5,000, Enterprise 100,000. Some things to know:

  • An answer is generated only when the search has results.
  • If you're over quota, the search still succeeds, but there's no answer and meta.warnings contains "AI answer quota exceeded."
  • answer can be null if generation failed.
  • On Free, hits carry no excerpt or content, so answers are based on titles only.

Quota and caching

Every authenticated search counts toward your site's monthly search quota. That includes cached responses and many error responses. When the quota is used up, you get 429 QUOTA_EXCEEDED until the next month or until you upgrade. See Rate Limits & Quotas.

Results are cached for a short time per plan: 10 minutes on Free, 3 on Pro, 1 on Growth, and no caching on Enterprise. Semantic searches aren't cached. Indexing or deleting documents clears the cache.

Errors

Status Code Meaning
400 MISSING_QUERY q is missing
400 INVALID_FILTER / INVALID_SORT See above
400 INDEX_NOT_CONFIGURED The site has no search index yet
401 MISSING_API_KEY / INVALID_API_KEY No key, a wrong key, or the private key
403 SEMANTIC_PLAN_REQUIRED / SEMANTIC_NOT_ENABLED Semantic search isn't available
429 QUOTA_EXCEEDED Monthly search quota used up
429 – Too many requests from your IP (30 per minute)
500 MEILISEARCH_ERROR / UNEXPECTED_SEARCH_ERROR Engine error. For example, facets requested on an attribute that isn't facetable.

Retry code is in Error Handling.

Best practices

  1. Call search from the browser with the public key. The 30-per-minute limit applies per client IP, so routing every visitor's search through one server means they all share a single budget.
  2. Debounce search-as-you-type, and paginate rather than requesting 100 results.
  3. Watch remaining_quota.
  4. Send Accept: application/json, so errors always come back as JSON.

Was this article helpful?

Ready to add search to your project?

Start free. No credit card required. Deploy in under 10 minutes.