Product Search
Mint a short-lived, search-only token that queries an account's product catalog directly from the browser, with no further call to ibakepro per search.
Intended for headless and custom storefronts. It is products-only: there is no equivalent token for orders, customers, or other resources.
How it works
- Your app calls
POST /api/v2/products/search-tokenwith an ibakepro API key. - ibakepro returns a scoped search token (valid 1 hour), the search host to connect to, and the recommended query parameters.
- Your app queries the search engine (Typesense) directly using that token - no further calls to ibakepro per keystroke.
- The token stops working 1 hour after minting. Mint a new one to keep searching.
Call this from the browser with a publishable key (ibp_pk_); secret keys
also work. The account is derived from the key, never from the request.
Mint a search token
Returns a scoped, search-only token plus the host and query parameters to use. No request body is required, and any body you send is ignored.
Required scope: products:search
This scope is available to publishable keys and is separate from products:read. A products:search key can only mint search tokens - it cannot paginate or bulk-export the catalog the way products:read can.
Response fields
- Name
token- Type
- string
- Description
The scoped, search-only token. Send it as the
X-TYPESENSE-API-KEYheader when querying the search host. The parent search key is never returned.
- Name
search- Type
- object
- Description
host,port,protocol, andcollection(products) - where to send your search requests.
- Name
query- Type
- object
- Description
Recommended search parameters:
query_by,group_by,group_limit,per_page,sort_by. Use them as-is for behaviour matching the ibakepro storefront. They are defaults, not constraints - you may overrideper_pageorsort_byon your own request.
- Name
expires_at- Type
- integer
- Description
Unix timestamp in seconds when the token stops working. This is the expiry baked into the token itself, not a re-derived clock read. Tokens last 1 hour from minting.
Errors
If search is not configured for the account's region, or key minting fails, the endpoint returns 503 with code search_not_configured. This is an infrastructure state rather than a bad request, and it is retryable.
Request
curl -X POST https://au.api.ibakepro.com/api/v2/products/search-token \
-H "Authorization: Bearer ibp_pk_live_au_ABC"
Response
{
"token": "<scoped search-only token>",
"search": {
"host": "n7k2qx4p1v9t3wzb-1.a1.typesense.net",
"port": 443,
"protocol": "https",
"collection": "products"
},
"query": {
"query_by": "name,category,description",
"group_by": "productId",
"group_limit": 1,
"per_page": 8,
"sort_by": "_text_match:desc"
},
"expires_at": 1781694000
}
Querying the catalog
Send your search directly to the returned host, using the token as the X-TYPESENSE-API-KEY header. With group_by=productId, results arrive under grouped_hits (one group per product, because the index holds one document per variant); take the first hit in each group.
Browser
// 1. Mint a token. It is valid for 1 hour.
const res = await fetch(
'https://au.api.ibakepro.com/api/v2/products/search-token',
{ method: 'POST', headers: { Authorization: 'Bearer ibp_pk_live_au_ABC' } },
)
const { token, search, query } = await res.json()
// 2. Query the catalog directly, with no further ibakepro call.
async function searchProducts(q) {
const params = new URLSearchParams({ q, ...query })
const r = await fetch(
`${search.protocol}://${search.host}:${search.port}` +
`/collections/${search.collection}/documents/search?${params}`,
{ headers: { 'X-TYPESENSE-API-KEY': token } },
)
const data = await r.json()
return (data.grouped_hits || []).map((g) => g.hits[0].document)
}
Result fields
The token bakes in an include_fields allowlist, so a hit can only ever carry these public catalog fields (any that the document actually has):
productId, name, slug, description, category, imageUrl,
price, priceMin, priceMax, pricePerPortion, portions,
variantName, variantCount, size, availableSizes, availableTiers, tierCount,
storefrontEnabled, featured, collections, isUpsell, upsellCategories,
allergens, mayContain, dietaryFlags, metaTitle, metaDescription
Because it is an allowlist rather than a denylist, internal fields added to the index later can never start leaking. Costs, margins, recipe composition, revenue, and order counts are not in it.
A field is present on a hit only when the indexed document carries it, so slug and the price fields can be absent. Search hits are for discovery only - fetch the product by productId before building an order line, since variants, choices, and the authoritative pricing are not in the index.
allergens and mayContain here are the raw indexed lists, not the
{ allergen, level } shape the products endpoint returns. Read allergens from
the product endpoint before displaying them on a product page.
Security
The token embeds a filter of the issuing account plus status:=active and storefrontEnabled:=true, and that filter is signed into the token, so a client cannot widen it or reach another account's catalog. It is search-only: no writes, no other collections, and no way to add fields beyond the allowlist above. It expires 1 hour after minting.
Rate limits
The mint endpoint is rate-limited per key, under the same api-write and api-public-ip rules as any other POST. See Rate limiting. Requests sent directly to the search host do not count against ibakepro's limits.