On this page
- Search relevance
- Endpoints
- Search products and collections
- Query parameters
- Request
- Response 200
- Get search suggestions
- Query parameters
- Request
- Response 200 (Skirre)
- Response 200 (default)
- Bootstrap search index
- Request
- Response 200
- Create a synonym group
- Request body
- Request
- Response 201
- List synonym groups
- Request
- Response 200
- Update a synonym group
- Request body
- Request
- Response 200
- Delete a synonym group
- Request
- Response 204
- Create a merchandising rule
- Request body
- Request
- Response 201
- List merchandising rules
- Request
- Response 200
- Get a merchandising rule
- Request
- Response 200
- Update a merchandising rule
- Request body
- Request
- Response 200
- Delete a merchandising rule
- Request
- Response 204
- Top search queries
- Query parameters
- Request
- Response 200
- Zero-result queries
- Query parameters
- Request
- Response 200
- The synonym object
- The merchandising rule object
Search
Hydra provides a powerful search engine with typo correction, synonym expansion, faceted filtering, and merchandising controls. Search queries are logged for analytics, and results can be influenced through synonym groups and merchandising rules (pin, boost, bury, hide).
Full-text search indexes the following fields with weighted relevance:
| Weight | Fields | Description |
|---|---|---|
| A | Product title | Highest relevance, stemmed |
| B | Product description | Secondary relevance, stemmed |
| C | Tags, product type | Consumer search terms, exact match |
| D | Variant SKU, barcode | Staff/B2B lookups, exact match |
All fields are indexed automatically — no configuration required.
Search relevance
For projects using the Skirre search engine, search ranking is a blend of three signals:
- Keyword relevance (BM25) — how well the query matches indexed text fields, weighted by the table above
- Semantic similarity (optional) — meaning-based matching via vector embeddings, for queries like “comfortable running shoes” matching “ergonomic jogging sneakers”
- Popularity scoring (optional) — behavioral signals (purchases, clicks, views) automatically boost popular products. Skirre aggregates these from shopper events every 6 hours. No configuration beyond enabling scoring in the search engine settings
Commerce-based scoring (sales velocity, revenue, inventory health) is computed nightly by Hydra and applied during index bootstraps. When Skirre’s behavioral scoring is also enabled, both signals combine for the most accurate ranking.
Base URL: https://api.hydrajs.dev
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
GET |
/v1/search |
Publishable | Search products and collections |
GET |
/v1/search/suggest |
Publishable | Get typeahead suggestions |
POST |
/v1/search/synonyms |
Secret | Create a synonym group |
GET |
/v1/search/synonyms |
Secret | List synonym groups |
PATCH |
/v1/search/synonyms/{id} |
Secret | Update a synonym group |
DELETE |
/v1/search/synonyms/{id} |
Secret | Delete a synonym group |
POST |
/v1/search/merchandising |
Secret | Create a merchandising rule |
GET |
/v1/search/merchandising |
Secret | List merchandising rules |
GET |
/v1/search/merchandising/{id} |
Secret | Get a merchandising rule |
PATCH |
/v1/search/merchandising/{id} |
Secret | Update a merchandising rule |
DELETE |
/v1/search/merchandising/{id} |
Secret | Delete a merchandising rule |
POST |
/v1/search/bootstrap |
Secret | Rebuild the search index |
GET |
/v1/search/analytics/top-queries |
Secret | Top search queries |
GET |
/v1/search/analytics/zero-results |
Secret | Zero-result queries |
Search products and collections
GET /v1/search
Returns search results across one or more resource types. Supports typo correction, synonym expansion, faceted filtering, and multi-currency price conversion.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
q |
string | - | Search term (1-200 chars, required) |
types |
string | products |
Comma-separated: products, collections |
limit |
integer | 20 |
Results per type (1-50) |
offset |
integer | 0 |
Result offset for pagination (0-1000) |
product_type |
string | - | Filter products by type |
collection_id |
string | - | Filter products by collection |
tag |
string | - | Filter products by tag |
in_stock |
string | - | true for in-stock only, false for out-of-stock only |
price_min |
integer | - | Minimum price in cents |
price_max |
integer | - | Maximum price in cents |
facets |
string | true |
Include facet counts in response (true or false) |
currency |
string | - | 3-letter ISO currency code for price conversion |
ℹSearch syntax
Hydra supports Google-style search operators. Use quotes for exact phrases ("red sneakers"), a
minus sign to exclude terms (sneakers -nike), and OR for alternatives (sneakers OR trainers). Typo correction is applied automatically.
Request
curl "https://api.hydrajs.dev/v1/search?q=sneakers&types=products&limit=10&in_stock=true" \
-H "Authorization: Bearer pk_YOUR_KEY"
Response 200
{
"data": {
"products": {
"data": [
{
"id": "prod_abc123",
"title": "Classic Sneakers",
"handle": "classic-sneakers",
"status": "active",
"product_type": "Footwear",
"tags": ["sneakers", "footwear"],
"skus": ["SNKR-BLK-10", "SNKR-WHT-10"],
"image": "https://cdn.hydrajs.dev/stores/store_xxx/img_abc.webp",
"price": 8999,
"sale_price": 11999,
"score": 1.85
}
],
"total": 24
},
"collections": {
"data": [],
"total": 0
}
}
}
Get search suggestions
GET /v1/search/suggest
Returns typeahead suggestions based on a query prefix. The suggestion source depends on the project’s search engine:
- Skirre — query-based suggestions derived from search analytics (popular queries, click-through rates, conversions) and catalog data (product titles, types, brands, tags). Suggestions are scored and maintained automatically. An empty
qreturns the most popular suggestions. - Default (Postgres) — entity-based suggestions from product titles, collection names, product types, tags, and variant titles using trigram similarity ranking.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
q |
string | "" |
Partial search term (0-100 chars). Empty returns popular suggestions |
limit |
integer | 5 |
Max suggestions (1-10) |
Request
curl "https://api.hydrajs.dev/v1/search/suggest?q=snea&limit=5" \
-H "Authorization: Bearer pk_YOUR_KEY"
Response 200 (Skirre)
{
"data": [
{ "text": "sneakers", "type": "product" },
{ "text": "sneaker collection", "type": "product" },
{ "text": "snow boots", "type": "product" }
]
}
Skirre returns query-level suggestions — each entry is a search query string. Results are ranked by a blended score of search frequency, click-through rate, and conversion rate. Catalog-derived suggestions provide a baseline from day one (cold start), and analytics-derived suggestions take over as search traffic builds.
Response 200 (default)
{
"data": [
{ "text": "Classic Sneakers", "type": "product", "id": "prod_abc123", "handle": "classic-sneakers", "image": "https://cdn.hydrajs.dev/stores/store_xxx/img_abc.webp" },
{ "text": "Footwear", "type": "product_type" },
{ "text": "sneakers", "type": "tag" },
{ "text": "Sneaker Collection", "type": "collection", "id": "col_def456", "handle": "sneaker-collection" },
{ "text": "Size 10 / Black", "type": "variant" }
]
}
The default engine returns entity-based suggestions. Each includes a type field: product, collection, product_type, tag, or variant. Products and collections include id, handle, and optionally image for building direct links.
Bootstrap search index
POST /v1/search/bootstrap
Reads all active products from the database and pushes them to the search index in batches. Use this after bulk imports, data migrations, or when search results appear stale.
⚠Requirements
This endpoint only works when the store’s search engine is set to skirre. Calling it on a store using the default Postgres search engine returns a 400 error.
No request body is required. The endpoint reads all active, non-deleted products and indexes them automatically. The index language is set based on the project’s locale setting — for example, a project with locale fr or fr-FR uses French tokenization with accent folding, while ja uses Japanese dictionary-based word segmentation.
Request
curl -X POST "https://api.hydrajs.dev/v1/search/bootstrap" \
-H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response 200
{
"indexed": 369
}
The indexed field indicates the total number of products pushed to the search index.
Create a synonym group
POST /v1/search/synonyms
Creates a synonym group. When a user searches for any term in the group, results for all terms are included.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
synonym_type |
string | No | equivalent (default) or oneway. Equivalent synonyms expand in all directions; one-way synonyms only expand the first term to the rest |
terms |
string[] | Yes | Array of synonym terms (2-20 terms, each max 100 chars) |
ℹSynonym types
With equivalent synonyms, searching for any term returns results for all terms. With one-way synonyms, only the first term triggers expansion - searching for later terms returns only those exact results.
Request
curl -X POST https://api.hydrajs.dev/v1/search/synonyms \
-H "Authorization: Bearer sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"synonym_type": "equivalent",
"terms": ["sneakers", "trainers", "kicks"]
}'
Response 201
{
"data": {
"id": "syn_abc123",
"synonym_type": "equivalent",
"terms": ["sneakers", "trainers", "kicks"],
"is_active": true,
"created_at": "2026-08-17T10:00:00Z",
"updated_at": "2026-08-17T10:00:00Z"
}
}
List synonym groups
GET /v1/search/synonyms
Returns all synonym groups for the project, ordered by creation date.
Request
curl https://api.hydrajs.dev/v1/search/synonyms \
-H "Authorization: Bearer sk_YOUR_KEY"
Response 200
{
"data": [
{
"id": "syn_abc123",
"synonym_type": "equivalent",
"terms": ["sneakers", "trainers", "kicks"],
"is_active": true,
"created_at": "2026-08-17T10:00:00Z",
"updated_at": "2026-08-17T10:00:00Z"
},
{
"id": "syn_def456",
"synonym_type": "oneway",
"terms": ["laptop", "notebook", "ultrabook"],
"is_active": true,
"created_at": "2026-08-16T08:00:00Z",
"updated_at": "2026-08-16T08:00:00Z"
}
]
}
Update a synonym group
PATCH /v1/search/synonyms/{id}
Updates a synonym group. All fields are optional.
Request body
| Field | Type | Description |
|---|---|---|
synonym_type |
string | equivalent or oneway |
terms |
string[] | Replacement terms (2-20) |
is_active |
boolean | Enable or disable the synonym |
Request
curl -X PATCH https://api.hydrajs.dev/v1/search/synonyms/syn_abc123 \
-H "Authorization: Bearer sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"terms": ["sneakers", "trainers", "kicks", "tennis shoes"]
}'
Response 200
{
"data": {
"id": "syn_abc123",
"synonym_type": "equivalent",
"terms": ["sneakers", "trainers", "kicks", "tennis shoes"],
"is_active": true,
"created_at": "2026-08-17T10:00:00Z",
"updated_at": "2026-08-17T10:05:00Z"
}
}
Delete a synonym group
DELETE /v1/search/synonyms/{id}
Permanently deletes a synonym group.
Request
curl -X DELETE https://api.hydrajs.dev/v1/search/synonyms/syn_abc123 \
-H "Authorization: Bearer sk_YOUR_KEY"
Response 204
Empty body.
Create a merchandising rule
POST /v1/search/merchandising
Creates a rule that influences search results for matching queries. Rules can pin products to specific positions, boost or bury their relevance scores, or hide them entirely.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Human-readable name (max 200 chars) |
match_query |
string | Yes | Query pattern to match (max 200 chars) |
match_type |
string | No | contains (default), exact, or all (matches every query) |
action |
string | Yes | pin, boost, bury, or hide |
product_id |
string | Yes | Product ID to apply the action to |
pin_position |
integer | Conditional | Required when action is pin. Zero-based position in results |
score_multiplier |
number | Conditional | Required when action is boost or bury. Multiplier for relevance score (0.01-100) |
priority |
integer | No | Rule priority (0-1000, default 0). Higher priority rules are evaluated first |
⚠Action requirements
pin requires pin_position. boost and bury require score_multiplier. Two active pin rules
cannot share the same (match_query, match_type, pin_position) combination.
Request
curl -X POST https://api.hydrajs.dev/v1/search/merchandising \
-H "Authorization: Bearer sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Promote summer sneakers",
"match_query": "sneakers",
"match_type": "contains",
"action": "pin",
"product_id": "prod_abc123",
"pin_position": 0,
"priority": 10
}'
Response 201
{
"data": {
"id": "mr_abc123",
"name": "Promote summer sneakers",
"match_query": "sneakers",
"match_type": "contains",
"action": "pin",
"product_id": "prod_abc123",
"pin_position": 0,
"score_multiplier": null,
"priority": 10,
"is_active": true,
"created_at": "2026-08-17T10:00:00Z",
"updated_at": "2026-08-17T10:00:00Z"
}
}
List merchandising rules
GET /v1/search/merchandising
Returns all merchandising rules, ordered by priority (descending) then creation date.
Request
curl https://api.hydrajs.dev/v1/search/merchandising \
-H "Authorization: Bearer sk_YOUR_KEY"
Response 200
{
"data": [
{
"id": "mr_abc123",
"name": "Promote summer sneakers",
"match_query": "sneakers",
"match_type": "contains",
"action": "pin",
"product_id": "prod_abc123",
"pin_position": 0,
"score_multiplier": null,
"priority": 10,
"is_active": true,
"created_at": "2026-08-17T10:00:00Z",
"updated_at": "2026-08-17T10:00:00Z"
},
{
"id": "mr_def456",
"name": "Boost premium brand",
"match_query": "shoes",
"match_type": "contains",
"action": "boost",
"product_id": "prod_xyz789",
"pin_position": null,
"score_multiplier": 2.5,
"priority": 5,
"is_active": true,
"created_at": "2026-08-16T08:00:00Z",
"updated_at": "2026-08-16T08:00:00Z"
}
]
}
Get a merchandising rule
GET /v1/search/merchandising/{id}
Returns a single merchandising rule by ID.
Request
curl https://api.hydrajs.dev/v1/search/merchandising/mr_abc123 \
-H "Authorization: Bearer sk_YOUR_KEY"
Response 200
{
"data": {
"id": "mr_abc123",
"name": "Promote summer sneakers",
"match_query": "sneakers",
"match_type": "contains",
"action": "pin",
"product_id": "prod_abc123",
"pin_position": 0,
"score_multiplier": null,
"priority": 10,
"is_active": true,
"created_at": "2026-08-17T10:00:00Z",
"updated_at": "2026-08-17T10:00:00Z"
}
}
Update a merchandising rule
PATCH /v1/search/merchandising/{id}
Updates a merchandising rule. All fields are optional. Changing the action may require providing the corresponding parameter (pin_position for pin, score_multiplier for boost/bury).
Request body
| Field | Type | Description |
|---|---|---|
name |
string | Human-readable name (max 200 chars) |
match_query |
string | Query pattern to match (max 200 chars) |
match_type |
string | contains, exact, or all |
action |
string | pin, boost, bury, or hide |
product_id |
string | Product ID to target |
pin_position |
integer | null | Position for pin action |
score_multiplier |
number | null | Multiplier for boost/bury actions |
priority |
integer | Rule priority (0-1000) |
is_active |
boolean | Enable or disable the rule |
Request
curl -X PATCH https://api.hydrajs.dev/v1/search/merchandising/mr_abc123 \
-H "Authorization: Bearer sk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"pin_position": 1,
"priority": 20
}'
Response 200
Returns the full updated merchandising rule object.
Delete a merchandising rule
DELETE /v1/search/merchandising/{id}
Permanently deletes a merchandising rule.
Request
curl -X DELETE https://api.hydrajs.dev/v1/search/merchandising/mr_abc123 \
-H "Authorization: Bearer sk_YOUR_KEY"
Response 204
Empty body.
Top search queries
GET /v1/search/analytics/top-queries
Returns the most popular search queries over a time period, ranked by frequency.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
period |
string | 7d |
Time period: 1d, 7d, 14d, 30d |
limit |
integer | 20 |
Max results (1-100) |
Request
curl "https://api.hydrajs.dev/v1/search/analytics/top-queries?period=7d&limit=10" \
-H "Authorization: Bearer sk_YOUR_KEY"
Response 200
{
"data": [
{ "query": "sneakers", "count": 342, "avg_results": 18 },
{ "query": "t-shirt", "count": 256, "avg_results": 45 },
{ "query": "jeans", "count": 198, "avg_results": 32 }
]
}
Zero-result queries
GET /v1/search/analytics/zero-results
Returns search queries that returned no results over a time period. Use this to identify gaps in your catalog or opportunities to add synonyms.
Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
period |
string | 7d |
Time period: 1d, 7d, 14d, 30d |
limit |
integer | 20 |
Max results (1-100) |
Request
curl "https://api.hydrajs.dev/v1/search/analytics/zero-results?period=30d&limit=10" \
-H "Authorization: Bearer sk_YOUR_KEY"
Response 200
{
"data": [
{ "query": "sandals", "count": 87 },
{ "query": "waterproof jacket", "count": 42 },
{ "query": "running shoes size 15", "count": 15 }
]
}
ℹImproving zero-result queries
When you spot recurring zero-result queries, consider adding synonym groups to map those terms to existing products, or use the data to inform catalog expansion.
The synonym object
| Field | Type | Description |
|---|---|---|
id |
string | Unique ID (prefix: syn_) |
synonym_type |
string | equivalent or oneway |
terms |
string[] | Array of synonym terms (lowercased) |
is_active |
boolean | Whether the synonym is active |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |
The merchandising rule object
| Field | Type | Description |
|---|---|---|
id |
string | Unique ID (prefix: mr_) |
name |
string | Human-readable rule name |
match_query |
string | Query pattern to match (lowercased) |
match_type |
string | contains, exact, or all |
action |
string | pin, boost, bury, or hide |
product_id |
string | Target product ID |
pin_position |
integer | null | Zero-based position (pin action only) |
score_multiplier |
number | null | Relevance multiplier (boost/bury only) |
priority |
integer | Evaluation priority (higher = first) |
is_active |
boolean | Whether the rule is active |
created_at |
string | ISO 8601 timestamp |
updated_at |
string | ISO 8601 timestamp |