API Documentation
Base URL: https://api.masalasearch.com/v1
Authentication
All endpoints require a Bearer token. Write operations require specific scopes (e.g. products:write). An admin:write key bypasses all individual scope checks.
# Include on every request: Authorization: Bearer msk_your_api_key_here
curl "https://api.masalasearch.com/v1/search?q=masala" \ -H "Authorization: Bearer msk_..."
401 Unauthorized. Missing scope → 403 Forbidden.Rate Limits
Two layers of enforcement:
- IP-level: 120 requests / 60 s per IP (Upstash Redis sliding window)
- Key-level: hourly + monthly quotas set per key at creation time
When exceeded → 429 Too Many Requests with a Retry-After header.
Scopes
Each API key carries a list of scopes. admin:write grants full access to everything.
Products
/productsPaginated list of products. Includes brand details.
Query Parameters
Example
curl "https://api.masalasearch.com/v1/products?search=masala" \ -H "Authorization: Bearer msk_..."
/products/[id]Single product by UUID. Includes brand, active listings, and assigned categories.
Example
curl "https://api.masalasearch.com/v1/products/40169688-939a-4287-ad5f-844559d6faf0" \ -H "Authorization: Bearer msk_..."
/products/[id]/priceHistoryFull price history for a product across all store listings.
Query Parameters
Example
curl "https://api.masalasearch.com/v1/products/[id]/priceHistory?days=90" \ -H "Authorization: Bearer msk_..."
/productsCreate a new product.
Request Body
{
"canonical_name": "Garam Masala", // required
"brand_id": "uuid...",
"size_label": "100g",
"weight_g": 100
}Example
curl -X POST "https://api.masalasearch.com/v1/products" \
-H "Authorization: Bearer msk_..." \
-d '{"canonical_name":"Garam Masala"}'/products/[id]Partially update a product. All fields optional.
Example
curl -X PATCH "https://api.masalasearch.com/v1/products/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"size_label":"200g"}'/products/[id]Delete a product by UUID. Returns 404 if not found.
Example
curl -X DELETE "https://api.masalasearch.com/v1/products/uuid-here" \ -H "Authorization: Bearer msk_..."
Listings
Listings represent the actual products sold by stores, including their current price and URL. Querying listings across different stores for the same product is the recommended approach for building a Price Comparison feature.
/listingsAll listings with price filtering and sorting.
Query Parameters
Example
curl "https://api.masalasearch.com/v1/listings?sort=price_per_100g&limit=20" \ -H "Authorization: Bearer msk_..."
/listings/[id]Single listing by UUID.
Example
curl "https://api.masalasearch.com/v1/listings/uuid-here" \ -H "Authorization: Bearer msk_..."
/listings/[id]/priceHistoryPrice history for a single listing.
Query Parameters
Example
curl "https://api.masalasearch.com/v1/listings/uuid-here/priceHistory?days=90" \ -H "Authorization: Bearer msk_..."
/listingsCreate a new listing.
Request Body
{
"store_id": "uuid...", // required UUID
"url": "https://...", // required
"title": "Basmati 1kg", // required
"price": 2.99 // required
}Example
curl -X POST "https://api.masalasearch.com/v1/listings" \
-H "Authorization: Bearer msk_..." \
-d '{"store_id":"uuid...","url":"https://...","title":"Basmati 1kg","price":2.99}'/listings/[id]Update a listing.
Example
curl -X PATCH "https://api.masalasearch.com/v1/listings/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"price":3.49}'/listings/[id]Delete a listing by UUID.
Example
curl -X DELETE "https://api.masalasearch.com/v1/listings/uuid-here" \ -H "Authorization: Bearer msk_..."
Search
/searchUnified typo-tolerant search across products and brands. Powered by pg_trgm + Full-Text Search — handles typos, partial words, and any word order.
Query Parameters
Example
curl "https://api.masalasearch.com/v1/search?q=garam+masala" \ -H "Authorization: Bearer msk_..."
Stores
/storesAll stores ordered by name.
Example
curl "https://api.masalasearch.com/v1/stores" \ -H "Authorization: Bearer msk_..."
/stores/[id]Single store by UUID.
Example
curl "https://api.masalasearch.com/v1/stores/uuid-here" \ -H "Authorization: Bearer msk_..."
/stores/[id]/listingsFull product catalogue for a store.
Query Parameters
Example
curl "https://api.masalasearch.com/v1/stores/uuid-here/listings" \ -H "Authorization: Bearer msk_..."
/storesCreate a store.
Request Body
{
"name": "Little India", // required
"base_url": "https://...",
"enabled": true
}Example
curl -X POST "https://api.masalasearch.com/v1/stores" \
-H "Authorization: Bearer msk_..." \
-d '{"name":"Little India","enabled":true}'/stores/[id]Update a store.
Example
curl -X PATCH "https://api.masalasearch.com/v1/stores/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"enabled":false}'/stores/[id]Delete a store by UUID.
Example
curl -X DELETE "https://api.masalasearch.com/v1/stores/uuid-here" \ -H "Authorization: Bearer msk_..."
Brands
/brandsPaginated list of all brands.
Query Parameters
Example
curl "https://api.masalasearch.com/v1/brands?search=shan" \ -H "Authorization: Bearer msk_..."
/brands/[id]Single brand by UUID.
Example
curl "https://api.masalasearch.com/v1/brands/uuid-here" \ -H "Authorization: Bearer msk_..."
/brands/[id]/productsAll products belonging to a brand.
Example
curl "https://api.masalasearch.com/v1/brands/uuid-here/products" \ -H "Authorization: Bearer msk_..."
/brandsCreate a brand.
Request Body
{
"name": "Shan", // required
"slug": "shan" // required
}Example
curl -X POST "https://api.masalasearch.com/v1/brands" \
-H "Authorization: Bearer msk_..." \
-d '{"name":"Shan","slug":"shan"}'/brands/[id]Update a brand.
Example
curl -X PATCH "https://api.masalasearch.com/v1/brands/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"country":"Pakistan"}'/brands/[id]Delete a brand.
Example
curl -X DELETE "https://api.masalasearch.com/v1/brands/uuid-here" \ -H "Authorization: Bearer msk_..."
Categories
/categoriesAll categories ordered by sort_order. Includes parent_id for building a category tree.
Example
curl "https://api.masalasearch.com/v1/categories" \ -H "Authorization: Bearer msk_..."
/categories/[id]Single category by UUID.
Example
curl "https://api.masalasearch.com/v1/categories/uuid-here" \ -H "Authorization: Bearer msk_..."
/categories/[id]/productsPaginated products within a category.
Example
curl "https://api.masalasearch.com/v1/categories/uuid-here/products" \ -H "Authorization: Bearer msk_..."
/categoriesCreate a category.
Request Body
{
"name": "Spices", // required
"slug": "spices", // required
"parent_id": null // optional UUID
}Example
curl -X POST "https://api.masalasearch.com/v1/categories" \
-H "Authorization: Bearer msk_..." \
-d '{"name":"Spices","slug":"spices"}'/categories/[id]Update a category.
Example
curl -X PATCH "https://api.masalasearch.com/v1/categories/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"sort_order":10}'/categories/[id]Delete a category.
Example
curl -X DELETE "https://api.masalasearch.com/v1/categories/uuid-here" \ -H "Authorization: Bearer msk_..."
Brand Aliases
/brand-aliasesList all brand aliases.
Example
curl "https://api.masalasearch.com/v1/brand-aliases" \ -H "Authorization: Bearer msk_..."
/brand-aliases/[id]Single brand alias by UUID.
Example
curl "https://api.masalasearch.com/v1/brand-aliases/uuid-here" \ -H "Authorization: Bearer msk_..."
/brand-aliasesCreate a brand alias.
Request Body
{
"brand_id": "uuid...", // required UUID
"alias": "MDH Foods" // required
}Example
curl -X POST "https://api.masalasearch.com/v1/brand-aliases" \
-H "Authorization: Bearer msk_..." \
-d '{"brand_id":"uuid...","alias":"MDH Foods"}'/brand-aliases/[id]Update a brand alias.
Example
curl -X PATCH "https://api.masalasearch.com/v1/brand-aliases/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"alias":"MDH Spices"}'/brand-aliases/[id]Delete a brand alias.
Example
curl -X DELETE "https://api.masalasearch.com/v1/brand-aliases/uuid-here" \ -H "Authorization: Bearer msk_..."
Product Aliases
/product-aliasesList all product aliases.
Example
curl "https://api.masalasearch.com/v1/product-aliases" \ -H "Authorization: Bearer msk_..."
/product-aliases/[id]Single product alias.
Example
curl "https://api.masalasearch.com/v1/product-aliases/uuid-here" \ -H "Authorization: Bearer msk_..."
/product-aliasesCreate a product alias.
Request Body
{
"product_id": "uuid...", // required UUID
"alias": "Basmati Rice" // required
}Example
curl -X POST "https://api.masalasearch.com/v1/product-aliases" \
-H "Authorization: Bearer msk_..." \
-d '{"product_id":"uuid...","alias":"Basmati Rice"}'/product-aliases/[id]Update a product alias.
Example
curl -X PATCH "https://api.masalasearch.com/v1/product-aliases/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"alias":"Premium Basmati"}'/product-aliases/[id]Delete a product alias.
Example
curl -X DELETE "https://api.masalasearch.com/v1/product-aliases/uuid-here" \ -H "Authorization: Bearer msk_..."
Category Aliases
/category-aliasesList all category aliases.
Example
curl "https://api.masalasearch.com/v1/category-aliases" \ -H "Authorization: Bearer msk_..."
/category-aliases/[id]Single category alias.
Example
curl "https://api.masalasearch.com/v1/category-aliases/uuid-here" \ -H "Authorization: Bearer msk_..."
/category-aliasesCreate a category alias.
Request Body
{
"category_id": "uuid...", // required UUID
"alias": "Dal & Lentils" // required
}Example
curl -X POST "https://api.masalasearch.com/v1/category-aliases" \
-H "Authorization: Bearer msk_..." \
-d '{"category_id":"uuid...","alias":"Dal & Lentils"}'/category-aliases/[id]Update a category alias.
Example
curl -X PATCH "https://api.masalasearch.com/v1/category-aliases/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"alias":"Lentils"}'/category-aliases/[id]Delete a category alias.
Example
curl -X DELETE "https://api.masalasearch.com/v1/category-aliases/uuid-here" \ -H "Authorization: Bearer msk_..."
Category Rules
/category-rulesList all category rules.
Example
curl "https://api.masalasearch.com/v1/category-rules" \ -H "Authorization: Bearer msk_..."
/category-rules/[id]Single rule by UUID.
Example
curl "https://api.masalasearch.com/v1/category-rules/uuid-here" \ -H "Authorization: Bearer msk_..."
/category-rulesCreate a categorization rule.
Request Body
{
"category_id": "uuid...", // required UUID
"field": "canonical_name",
"operator": "contains",
"value": "masala",
"priority": 10
}Example
curl -X POST "https://api.masalasearch.com/v1/category-rules" \
-H "Authorization: Bearer msk_..." \
-d '{"category_id":"uuid...","field":"canonical_name","operator":"contains","value":"masala"}'/category-rules/[id]Update a rule.
Example
curl -X PATCH "https://api.masalasearch.com/v1/category-rules/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"priority":20}'/category-rules/[id]Delete a rule.
Example
curl -X DELETE "https://api.masalasearch.com/v1/category-rules/uuid-here" \ -H "Authorization: Bearer msk_..."
Product Categories
[product_id] and [category_id]./product-categoriesList all product–category assignments.
Example
curl "https://api.masalasearch.com/v1/product-categories" \ -H "Authorization: Bearer msk_..."
/product-categories/[product_id]/[category_id]Single assignment by composite key.
Example
curl "https://api.masalasearch.com/v1/product-categories/p-uuid/c-uuid" \ -H "Authorization: Bearer msk_..."
/product-categoriesAssign a product to a category.
Request Body
{
"product_id": "uuid...", // required UUID
"category_id": "uuid...", // required UUID
"is_primary": false,
"review_status": "pending"
}Example
curl -X POST "https://api.masalasearch.com/v1/product-categories" \
-H "Authorization: Bearer msk_..." \
-d '{"product_id":"p-uuid","category_id":"c-uuid"}'/product-categories/[product_id]/[category_id]Update an assignment.
Example
curl -X PATCH "https://api.masalasearch.com/v1/product-categories/p-uuid/c-uuid" \
-H "Authorization: Bearer msk_..." \
-d '{"is_primary":true}'/product-categories/[product_id]/[category_id]Remove a product from a category.
Example
curl -X DELETE "https://api.masalasearch.com/v1/product-categories/p-uuid/c-uuid" \ -H "Authorization: Bearer msk_..."
Product Merges
/product-mergesList all merge records.
Example
curl "https://api.masalasearch.com/v1/product-merges" \ -H "Authorization: Bearer msk_..."
/product-merges/[id]Single merge record.
Example
curl "https://api.masalasearch.com/v1/product-merges/uuid-here" \ -H "Authorization: Bearer msk_..."
/product-mergesCreate a merge mapping.
Request Body
{
"source_canonical_name": "Basmati 1kg", // required
"target_product_id": "uuid...", // required UUID
"source_brand_id": "uuid...", // optional UUID
"source_size_label": "1kg"
}Example
curl -X POST "https://api.masalasearch.com/v1/product-merges" \
-H "Authorization: Bearer msk_..." \
-d '{"source_canonical_name":"Basmati 1kg","target_product_id":"uuid..."}'/product-merges/[id]Update a merge record.
Example
curl -X PATCH "https://api.masalasearch.com/v1/product-merges/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"source_size_label":"1000g"}'/product-merges/[id]Delete a merge record.
Example
curl -X DELETE "https://api.masalasearch.com/v1/product-merges/uuid-here" \ -H "Authorization: Bearer msk_..."
Contact Messages
/contact-messagesList all contact messages.
Example
curl "https://api.masalasearch.com/v1/contact-messages" \ -H "Authorization: Bearer msk_..."
/contact-messages/[id]Single message by UUID.
Example
curl "https://api.masalasearch.com/v1/contact-messages/uuid-here" \ -H "Authorization: Bearer msk_..."
/contact-messagesSubmit a contact message.
Request Body
{
"name": "Jane Doe", // required
"email": "jane@example.com", // required email
"message": "Hello!" // required
}Example
curl -X POST "https://api.masalasearch.com/v1/contact-messages" \
-H "Authorization: Bearer msk_..." \
-d '{"name":"Jane","email":"jane@example.com","message":"Hello!"}'/contact-messages/[id]Update a message.
Example
curl -X PATCH "https://api.masalasearch.com/v1/contact-messages/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"message":"Updated"}'/contact-messages/[id]Delete a message.
Example
curl -X DELETE "https://api.masalasearch.com/v1/contact-messages/uuid-here" \ -H "Authorization: Bearer msk_..."
admin scope for reads and admin:write for mutations.API Keys
msk_-prefixed key and returns it once only. Only a SHA-256 hash is stored./api-keysList all API key records (hashes only).
Example
curl "https://api.masalasearch.com/v1/api-keys" \ -H "Authorization: Bearer msk_..."
/api-keys/[id]Single API key by UUID.
Example
curl "https://api.masalasearch.com/v1/api-keys/uuid-here" \ -H "Authorization: Bearer msk_..."
/api-keysIssue a new API key. Raw key returned once — store it immediately.
Request Body
{
"user_id": "uuid...", // required UUID
"name": "My App Key", // optional
"scopes": ["products","search"], // required
"rate_limit": 1000, // hourly limit
"monthly_limit": 100000
}Example
curl -X POST "https://api.masalasearch.com/v1/api-keys" \
-H "Authorization: Bearer msk_..." \
-d '{"user_id":"uuid...","scopes":["products","search"]}'/api-keys/[id]Update a key (e.g. disable it, change scopes).
Example
curl -X PATCH "https://api.masalasearch.com/v1/api-keys/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"is_active":false}'/api-keys/[id]Permanently delete an API key.
Example
curl -X DELETE "https://api.masalasearch.com/v1/api-keys/uuid-here" \ -H "Authorization: Bearer msk_..."
Crawl Jobs
/crawl-jobsList all crawl job records.
Example
curl "https://api.masalasearch.com/v1/crawl-jobs" \ -H "Authorization: Bearer msk_..."
/crawl-jobs/[id]Single crawl job.
Example
curl "https://api.masalasearch.com/v1/crawl-jobs/uuid-here" \ -H "Authorization: Bearer msk_..."
/crawl-jobsCreate a crawl job record.
Request Body
{
"store_id": "uuid...", // required UUID
"status": "running" // default
}Example
curl -X POST "https://api.masalasearch.com/v1/crawl-jobs" \
-H "Authorization: Bearer msk_..." \
-d '{"store_id":"uuid..."}'/crawl-jobs/[id]Update a crawl job.
Example
curl -X PATCH "https://api.masalasearch.com/v1/crawl-jobs/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"status":"completed","listings_found":1200}'/crawl-jobs/[id]Delete a crawl job record.
Example
curl -X DELETE "https://api.masalasearch.com/v1/crawl-jobs/uuid-here" \ -H "Authorization: Bearer msk_..."
Crawler Paths
/crawler-pathsList all crawler paths.
Example
curl "https://api.masalasearch.com/v1/crawler-paths" \ -H "Authorization: Bearer msk_..."
/crawler-paths/[id]Single crawler path.
Example
curl "https://api.masalasearch.com/v1/crawler-paths/uuid-here" \ -H "Authorization: Bearer msk_..."
/crawler-pathsAdd a crawler path for a store.
Request Body
{
"store_id": "uuid...", // required UUID
"path": "/products", // required
"sort_order": 0
}Example
curl -X POST "https://api.masalasearch.com/v1/crawler-paths" \
-H "Authorization: Bearer msk_..." \
-d '{"store_id":"uuid...","path":"/products"}'/crawler-paths/[id]Update a crawler path.
Example
curl -X PATCH "https://api.masalasearch.com/v1/crawler-paths/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"sort_order":5}'/crawler-paths/[id]Delete a crawler path.
Example
curl -X DELETE "https://api.masalasearch.com/v1/crawler-paths/uuid-here" \ -H "Authorization: Bearer msk_..."
Job Queue
/job-queueList queued crawl jobs.
Example
curl "https://api.masalasearch.com/v1/job-queue" \ -H "Authorization: Bearer msk_..."
/job-queue/[id]Single queued job.
Example
curl "https://api.masalasearch.com/v1/job-queue/uuid-here" \ -H "Authorization: Bearer msk_..."
/job-queueEnqueue a store for crawling.
Request Body
{
"store_id": "uuid..." // required UUID
}Example
curl -X POST "https://api.masalasearch.com/v1/job-queue" \
-H "Authorization: Bearer msk_..." \
-d '{"store_id":"uuid..."}'/job-queue/[id]Update a queued job.
Example
curl -X PATCH "https://api.masalasearch.com/v1/job-queue/uuid-here" \
-H "Authorization: Bearer msk_..." \
-d '{"store_id":"uuid..."}'/job-queue/[id]Remove a job from the queue.
Example
curl -X DELETE "https://api.masalasearch.com/v1/job-queue/uuid-here" \ -H "Authorization: Bearer msk_..."
Settings
key string (not a UUID)./settingsList all settings.
Example
curl "https://api.masalasearch.com/v1/settings" \ -H "Authorization: Bearer msk_..."
/settings/[key]Single setting by key string.
Example
curl "https://api.masalasearch.com/v1/settings/crawler_enabled" \ -H "Authorization: Bearer msk_..."
/settingsCreate a setting.
Request Body
{
"key": "crawler_enabled", // required string
"value": "true" // required string
}Example
curl -X POST "https://api.masalasearch.com/v1/settings" \
-H "Authorization: Bearer msk_..." \
-d '{"key":"crawler_enabled","value":"true"}'/settings/[key]Update a setting.
Example
curl -X PATCH "https://api.masalasearch.com/v1/settings/crawler_enabled" \
-H "Authorization: Bearer msk_..." \
-d '{"value":"false"}'/settings/[key]Delete a setting.
Example
curl -X DELETE "https://api.masalasearch.com/v1/settings/crawler_enabled" \ -H "Authorization: Bearer msk_..."
Error Reference
All errors: { "data": null, "meta": null, "error": { "code": "...", "message": "..." } }