{"openapi":"3.0.3","info":{"title":"AACSearch API","description":"Hosted search as a service. One API key scopes every request to your organization; collections, documents, synonyms, curation, analytics, recommendations, voice and assistants are all namespaced per tenant. This document is the contract every AACSearch SDK is generated from.\n","version":"1.0.0","license":{"name":"Proprietary — AACSearch Terms of Service","url":"https://aacsearch.com/terms"}},"servers":[{"url":"https://{host}/v1","description":"AACSearch production API (SaaS)","variables":{"host":{"default":"api.aacsearch.com","description":"API host for the production SaaS. Use the default unless you were given a dedicated one. A self-hosted control plane serves the same contract under /v1.\n"}}},{"url":"http://localhost:8787/v1","description":"Local development (wrangler dev)"}],"externalDocs":{"description":"AACSearch documentation","url":"https://docs.aacsearch.com"},"security":[{"api_key_header":[]}],"tags":[{"name":"cms","description":"CMS installations and versioned configuration"},{"name":"collections","description":"A collection is defined by a schema","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/#create-collection"}},{"name":"documents","description":"A document is an individual record to be indexed and belongs to a collection","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/#index-document"}},{"name":"analytics","description":"AACSearch can aggregate search queries for both analytics purposes and for query suggestions.","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/analytics-query-suggestions"}},{"name":"browser-keys","description":"Short-lived `search`-scoped keys a server-side integration mints for the browser: the storefront widget, the assistant chat and the search UI call the API directly with such a key, while the integration's own full key never leaves the server.\n","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/browser-keys"}},{"name":"health","description":"Service health checks"},{"name":"stopwords","description":"Manage stopwords sets","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/stopwords"}},{"name":"presets","description":"Store and reference search parameters","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/search"}},{"name":"conversations","description":"Engine-side conversational search: register an external LLM as a conversation model and pass `conversation_model_id` to a search. Requires your own LLM credentials on the model. For managed RAG with no key of your own, use `assistants` instead — it runs on the platform, cites the documents it answered from, and keeps conversation memory.\n","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/conversational-search-rag"}},{"name":"synonyms","description":"Manage synonyms","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/synonyms"}},{"name":"curation_sets","description":"Manage curation sets"},{"name":"stemming","description":"Manage stemming dictionaries","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/stemming"}},{"name":"nl_search_models","description":"Natural-language query parsing: a model translates \"red shoes under $50\" into `q`/`filter_by`/`sort_by` for a normal search (see `parsed_nl_query` in the response). This is query understanding, not chat — for answers over your documents use `assistants`.\n","externalDocs":{"description":"Find out more","url":"https://docs.aacsearch.com/api/natural-language-search"}},{"name":"events","description":"Behavioural events (searches, views, clicks, add-to-cart, purchases) reported by your application. They power recommendation models and analytics; purchase and add-to-cart events carry revenue so conversions can be attributed.\n"},{"name":"recommendations","description":"Recommendation models configured on a collection and the recommendations they produce (similar items, related items, trending, session-based).\n"},{"name":"query_intelligence","description":"Query understanding surfaces: typeahead suggestions while typing and pre-search prompts before typing. Search responses carry the post-search side (`query_understanding`, `correction`, `refinements`).\n"},{"name":"voice","description":"Speech to text for search: transcribe an audio clip, or search a collection with one. Multilingual (Russian included) — the recording is transcribed by the control-plane, not by the engine's English-only voice model.\nReal-time voice search is a WebSocket, which OpenAPI cannot describe: `GET /v1/collections/{collectionName}/documents/search/voice_stream?api_key=…` with `Upgrade: websocket`. Send `{\"type\":\"start\",\"params\":{\"query_by\":\"title\"}}`, then binary audio chunks as the microphone produces them, then `{\"type\":\"stop\"}`; the server answers `transcript` and `results` frames while you speak and a `final` frame at the end. The TypeScript SDK ships `connectVoiceSearch()` for it (hand-written, not generated).\n"},{"name":"assistants","description":"Conversational assistants over your collections: retrieval-augmented answers with the documents they were based on, conversation memory, and a streaming variant.\n"},{"name":"connectors","description":"CMS and feed sync into a collection: create a connector, give the shop its id and signing secret, then push catalogue events to `POST /connectors/{id}/webhook` (HMAC, no API key). Optional pull mode and schedule for shops that cannot open outbound connections. Journaled ingest — see docs/adr/0001-canonical-ingest-search-connectors.md.\n"},{"name":"ingest","description":"Asynchronous web and document ingest jobs (URL crawl, sitemap, YML, YouTube, or inline documents). Create a job, then poll `getIngestJob` until `status` is `ready` or `failed` — the Agentset-style upload status pattern on Cloudflare Queues. Yandex Market YML feeds of any size are streamed and imported in resumable passes; `uploadIngestFeed` takes a feed file, `createIngestJob` (source `yml`) a feed URL or a small feed inline.\n"},{"name":"media","description":"Images for visual search: upload, get a multilingual embedding computed for them (and written into a document), search a collection by image or by meaning, and embed text with the same model so documents and queries live in one vector space.\n"},{"name":"support","description":"Live human chat between a site visitor and the organization, alongside the AI assistant: a visitor opens a thread and sends messages with a `search`-scoped key, sticky per `X-NOVA-SESSION-ID` the same way a conversation is; the organization reads and replies from the console. No realtime transport — poll `getSupportThread` for new messages.\n"},{"name":"experiments","description":"A/B tests on a collection's search: variants of search parameters served to a share of sessions, sticky per `X-NOVA-SESSION-ID`, with click / add-to-cart / purchase metrics per variant computed from the events you already send.\n"},{"name":"search_profiles","description":"Named, server-compiled search configurations per collection: which fields are searched, which facets and filters a client may use, the sorts it may pick by stable id, and the page-size ceiling. A client names a profile with `profile=<name>` (and `sort=<id>`) or is pinned to one through a browser key, and never writes `query_by` / `sort_by` / `facet_by` itself. The number of profiles per collection is limited by the plan.\n"},{"name":"search_rules","description":"Per-collection merchandising applied by AACSearch to every `searchCollection` and `multiSearch` request before it reaches the engine and to the result on the way back: an exclusion filter, a zero-hit fallback, boosts compiled into a ranking expression, redirects for exact or partial queries, and refinement suggestions (manual entries plus top facet values). One rule set per collection; a storefront widget cannot bypass it.\n"},{"name":"entitlement","description":"What the organization's plan includes, when it ends, and how much of the two metered resources is left: search requests for the period and AI credits. An integration reads it to degrade honestly — hide what the plan does not cover, stop AI when credits run out, and warn before a subscription lapses instead of failing at the till.\n"},{"name":"synonym_suggestions","description":"Speller for zero-hit queries. Takes the queries that found nothing (from your `search` events with `found: 0`, from a `nohits_queries` analytics rule, or from an explicit list), generates candidates — keyboard-layout switch, transliteration, look-alike letters, and an LLM pass for brand spellings and synonyms — and keeps only candidates the engine actually finds documents for, with the matched catalogue term and sample titles as evidence. Accepting a suggestion writes a one-way synonym (`query → term`) into a synonym set attached to the collection.\n"},{"name":"graph","description":"Light-touch GraphRAG over your own document text, without a dedicated graph database or an offline clustering service. `generateGraphEntities` extracts named entities and relations from documents you name; `generateGraphCommunities` groups the connected entities (plain connected-components, not Leiden) and writes one LLM-summarized report per group, embedded for semantic retrieval. The assistant blends both into its answers when relevant — entity neighbors for a specific product/topic, community reports for broader \"how does this all connect\" questions. Human-triggered and incremental by design, same reasoning as the synonym speller: entity extraction is the expensive step, so nothing runs on a schedule.\n"},{"name":"seo","description":"Search-engine landing pages for filter combinations. A rule turns one facet of a collection into metatags — title, description, H1 and body text — rendered for every value of that facet, so a page like \"Ноутбуки Lenovo до 50 000\", which exists only as a combination of filters, stops being empty for search engines. Rules are templates with `#PLACEHOLDER#` substitutions; `generateSeoPages` materializes one page per facet value from the live index, `auditSeoPages` re-checks the materialized pages, and `exportSeoSitemap` emits the urlset.\n"}],"paths":{"/collections":{"get":{"tags":["collections"],"summary":"List all collections","description":"Returns a summary of all your collections. The collections are returned sorted by creation date, with the most recent collections appearing first.","operationId":"getCollections","parameters":[{"name":"getCollectionsParameters","in":"query","schema":{"type":"object","properties":{"exclude_fields":{"description":"Comma-separated list of fields from the collection to exclude from the response","type":"string"},"limit":{"description":"Number of collections to fetch. Default: returns all collections.\n","type":"integer"},"offset":{"description":"Identifies the starting point to return collections when paginating.","type":"integer"}}}}],"responses":{"200":{"description":"List of all collections","content":{"application/json":{"schema":{"type":"array","x-go-type":"[]*CollectionResponse","items":{"$ref":"#/components/schemas/CollectionResponse"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"tags":["collections"],"summary":"Create a new collection","description":"When a collection is created, we give it a name and describe the fields that will be indexed from the documents added to the collection.","operationId":"createCollection","requestBody":{"description":"The collection object to be created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionSchema"}}},"required":true},"responses":{"201":{"description":"Collection successfully created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionResponse"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Collection already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}":{"get":{"tags":["collections"],"summary":"Retrieve a single collection","description":"Retrieve the details of a collection, given its name.","operationId":"getCollection","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to retrieve","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Collection fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"patch":{"tags":["collections"],"summary":"Update a collection","description":"Update a collection's schema to modify the fields and their types.","operationId":"updateCollection","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to update","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The document object with fields to be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionUpdateSchema"}}},"required":true},"responses":{"200":{"description":"The updated partial collection schema","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionUpdateSchema"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The collection was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["collections"],"summary":"Delete a collection","description":"Permanently drops a collection. This action cannot be undone. For large collections, this might have an impact on read latencies.","operationId":"deleteCollection","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to delete","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Collection deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/documents":{"post":{"tags":["documents"],"summary":"Index a document","description":"A document to be indexed in a given collection must conform to the schema of the collection.","operationId":"indexDocument","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to add the document to","required":true,"schema":{"type":"string"}},{"name":"action","in":"query","description":"Additional action to perform","schema":{"type":"string","example":"upsert","$ref":"#/components/schemas/IndexAction"}},{"name":"dirty_values","in":"query","description":"Dealing with Dirty Data","schema":{"$ref":"#/components/schemas/DirtyValues"}}],"requestBody":{"description":"The document object to be indexed","content":{"application/json":{"schema":{"type":"object","description":"Can be any key-value pair","x-go-type":"interface{}"}}},"required":true},"responses":{"201":{"description":"Document successfully created/indexed","content":{"application/json":{"schema":{"type":"object","description":"Can be any key-value pair"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"patch":{"tags":["documents"],"summary":"Update documents with conditional query","description":"The filter_by query parameter is used to filter to specify a condition against which the documents are matched. The request body contains the fields that should be updated for any documents that match the filter condition. This endpoint is only available if the AACSearch node is version `0.25.0.rc12` or later.","operationId":"updateDocuments","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to update documents in","required":true,"schema":{"type":"string"}},{"name":"updateDocumentsParameters","in":"query","schema":{"type":"object","properties":{"filter_by":{"type":"string","example":"num_employees:>100 && country: [USA, UK]"}}}}],"responses":{"200":{"description":"The response contains a single field, `num_updated`, indicating the number of documents affected.","content":{"application/json":{"schema":{"type":"object","required":["num_updated"],"properties":{"num_updated":{"type":"integer","description":"The number of documents that have been updated","example":1}}}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The collection was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}},"requestBody":{"description":"The document fields to be updated","content":{"application/json":{"schema":{"type":"object","description":"Can be any key-value pair","x-go-type":"interface{}"}}},"required":true}},"delete":{"tags":["documents"],"summary":"Delete a bunch of documents","description":"Delete a bunch of documents that match a specific filter condition. Use the `batch_size` parameter to control the number of documents that should deleted at a time. A larger value will speed up deletions, but will impact performance of other operations running on the server.","operationId":"deleteDocuments","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to delete documents from","required":true,"schema":{"type":"string"}},{"name":"deleteDocumentsParameters","in":"query","schema":{"type":"object","required":["filter_by"],"properties":{"filter_by":{"type":"string","example":"num_employees:>100 && country: [USA, UK]"},"batch_size":{"description":"Batch size parameter controls the number of documents that should be deleted at a time. A larger value will speed up deletions, but will impact performance of other operations running on the server.","type":"integer"},"ignore_not_found":{"type":"boolean"},"truncate":{"description":"When true, removes all documents from the collection while preserving the collection and its schema.","type":"boolean"}}}}],"responses":{"200":{"description":"Documents successfully deleted","content":{"application/json":{"schema":{"type":"object","required":["num_deleted"],"properties":{"num_deleted":{"type":"integer"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/documents/search":{"get":{"tags":["documents"],"summary":"Search for documents in a collection","description":"Search for documents in a collection that match the search criteria. AACSearch extension: with `debug=true` (or the `X-NOVA-DEBUG: 1` header) the response includes `_trace` — what the platform did to the request (search rules applied, experiment variants, query rewrite and fallback outcome, stage timings, engine status) — and every hit an `_explain` object with the engine's scoring signals and which search-rule boosts matched. Every search response also carries an `X-Nova-Trace-Id` header identifying it in the query log.\n","operationId":"searchCollection","x-nova-key-scope":"search","parameters":[{"name":"X-NOVA-DEBUG","in":"header","required":false,"description":"AACSearch extension. `1` requests debug output, same as the `debug` search parameter: the response carries `_trace` and every hit an `_explain` object.\n","schema":{"type":"string"}},{"name":"collectionName","in":"path","description":"The name of the collection to search for the document under","required":true,"schema":{"type":"string"}},{"name":"X-NOVA-SESSION-ID","in":"header","required":false,"description":"The caller's session. Enrols the request in running experiments on the collection (sticky per session); the applied variants come back in the `X-Nova-Experiment` response header as `<experiment_id>:<variant_id>`. Send the same value as `session_id` in your events so experiment reports can attribute them.\n","schema":{"type":"string"}},{"name":"searchParameters","required":true,"in":"query","style":"form","explode":true,"schema":{"$ref":"#/components/schemas/SearchParameters"}}],"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResult"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The collection or field was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_sets":{"get":{"tags":["synonyms"],"summary":"List all synonym sets","description":"Retrieve all synonym sets","operationId":"retrieveSynonymSets","responses":{"200":{"description":"List of all synonym sets","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SynonymSetSchema"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_sets/{synonymSetName}":{"get":{"tags":["synonyms"],"summary":"Retrieve a synonym set","description":"Retrieve a specific synonym set by its name","operationId":"retrieveSynonymSet","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set to retrieve","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Synonym set fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSetSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Synonym set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["synonyms"],"summary":"Create or update a synonym set","description":"Create or update a synonym set with the given name","operationId":"upsertSynonymSet","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set to create/update","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The synonym set to be created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSetCreateSchema"}}},"required":true},"responses":{"200":{"description":"Synonym set successfully created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSetSchema"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["synonyms"],"summary":"Delete a synonym set","description":"Delete a specific synonym set by its name","operationId":"deleteSynonymSet","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set to delete","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Synonym set successfully deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSetDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Synonym set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_sets/{synonymSetName}/items":{"get":{"tags":["synonyms"],"summary":"List items in a synonym set","description":"Retrieve all synonym items in a set","operationId":"retrieveSynonymSetItems","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set to retrieve items for","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of synonym items","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SynonymItemSchema"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Synonym set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_sets/{synonymSetName}/items/{itemId}":{"get":{"tags":["synonyms"],"summary":"Retrieve a synonym set item","description":"Retrieve a specific synonym item by its id","operationId":"retrieveSynonymSetItem","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","description":"The id of the synonym item to retrieve","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Synonym item fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymItemSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Synonym item not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["synonyms"],"summary":"Create or update a synonym set item","description":"Create or update a synonym set item with the given id","operationId":"upsertSynonymSetItem","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","description":"The id of the synonym item to upsert","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The synonym item to be created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymItemUpsertSchema"}}},"required":true},"responses":{"200":{"description":"Synonym item successfully created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymItemSchema"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["synonyms"],"summary":"Delete a synonym set item","description":"Delete a specific synonym item by its id","operationId":"deleteSynonymSetItem","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","description":"The id of the synonym item to delete","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Synonym item successfully deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymItemDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Synonym item not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/curation_sets":{"get":{"tags":["curation_sets"],"summary":"List all curation sets","description":"Retrieve all curation sets","operationId":"retrieveCurationSets","responses":{"200":{"description":"List of all curation sets","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CurationSetSchema"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/curation_sets/{curationSetName}":{"get":{"tags":["curation_sets"],"summary":"Retrieve a curation set","description":"Retrieve a specific curation set by its name","operationId":"retrieveCurationSet","parameters":[{"name":"curationSetName","in":"path","description":"The name of the curation set to retrieve","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Curation set fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationSetSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Curation set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["curation_sets"],"summary":"Create or update a curation set","description":"Create or update a curation set with the given name","operationId":"upsertCurationSet","parameters":[{"name":"curationSetName","in":"path","description":"The name of the curation set to create/update","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The curation set to be created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationSetCreateSchema"}}},"required":true},"responses":{"200":{"description":"Curation set successfully created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationSetSchema"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["curation_sets"],"summary":"Delete a curation set","description":"Delete a specific curation set by its name","operationId":"deleteCurationSet","parameters":[{"name":"curationSetName","in":"path","description":"The name of the curation set to delete","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Curation set successfully deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationSetDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Curation set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/curation_sets/{curationSetName}/items":{"get":{"tags":["curation_sets"],"summary":"List items in a curation set","description":"Retrieve all curation items in a set","operationId":"retrieveCurationSetItems","parameters":[{"name":"curationSetName","in":"path","description":"The name of the curation set to retrieve items for","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of curation items","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CurationItemSchema"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Curation set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/curation_sets/{curationSetName}/items/{itemId}":{"get":{"tags":["curation_sets"],"summary":"Retrieve a curation set item","description":"Retrieve a specific curation item by its id","operationId":"retrieveCurationSetItem","parameters":[{"name":"curationSetName","in":"path","description":"The name of the curation set","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","description":"The id of the curation item to retrieve","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Curation item fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationItemSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Curation item not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["curation_sets"],"summary":"Create or update a curation set item","description":"Create or update a curation set item with the given id","operationId":"upsertCurationSetItem","parameters":[{"name":"curationSetName","in":"path","description":"The name of the curation set","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","description":"The id of the curation item to upsert","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The curation item to be created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationItemCreateSchema"}}},"required":true},"responses":{"200":{"description":"Curation item successfully created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationItemSchema"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["curation_sets"],"summary":"Delete a curation set item","description":"Delete a specific curation item by its id","operationId":"deleteCurationSetItem","parameters":[{"name":"curationSetName","in":"path","description":"The name of the curation set","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","description":"The id of the curation item to delete","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Curation item successfully deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CurationItemDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Curation item not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/documents/export":{"get":{"tags":["documents"],"summary":"Export all documents in a collection","description":"Export all documents in a collection in JSON lines format.","operationId":"exportDocuments","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"exportDocumentsParameters","in":"query","schema":{"type":"object","properties":{"filter_by":{"description":"Filter conditions for refining your search results. Separate multiple conditions with &&.","type":"string"},"include_fields":{"description":"List of fields from the document to include in the search result","type":"string"},"exclude_fields":{"description":"List of fields from the document to exclude in the search result","type":"string"}}}}],"responses":{"200":{"description":"Exports all the documents in a given collection.","content":{"application/octet-stream":{"schema":{"type":"string","example":"{\"id\": \"124\", \"company_name\": \"Stark Industries\", \"num_employees\": 5215, \"country\": \"US\"}\n{\"id\": \"125\", \"company_name\": \"Future Technology\", \"num_employees\": 1232,\"country\": \"UK\"}\n{\"id\": \"126\", \"company_name\": \"Random Corp.\", \"num_employees\": 531,\"country\": \"AU\"}\n"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The collection was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/documents/import":{"post":{"tags":["documents"],"summary":"Import documents into a collection","description":"The documents to be imported must be formatted in a newline delimited JSON structure. You can feed the output file from a AACSearch export operation directly as import.","operationId":"importDocuments","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"importDocumentsParameters","in":"query","schema":{"type":"object","properties":{"batch_size":{"type":"integer"},"return_id":{"type":"boolean","description":"Returning the id of the imported documents. If you want the import response to return the ingested document's id in the response, you can use the return_id parameter."},"remote_embedding_batch_size":{"type":"integer"},"return_doc":{"type":"boolean"},"action":{"$ref":"#/components/schemas/IndexAction"},"dirty_values":{"$ref":"#/components/schemas/DirtyValues"}}}}],"requestBody":{"description":"The json array of documents or the JSONL file to import","content":{"application/octet-stream":{"schema":{"type":"string","description":"The JSONL file to import"}}},"required":true},"responses":{"200":{"description":"Result of the import operation. Each line of the response indicates the result of each document present in the request body (in the same order). If the import of a single document fails, it does not affect the other documents. If there is a failure, the response line will include a corresponding error message and as well as the actual document content.","content":{"application/octet-stream":{"schema":{"type":"string","example":"{\"success\": true}\n{\"success\": false, \"error\": \"Bad JSON.\", \"document\": \"[bad doc\"}\n"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The collection was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/documents/{documentId}":{"get":{"tags":["documents"],"summary":"Retrieve a document","description":"Fetch an individual document from a collection by using its ID.","operationId":"getDocument","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to search for the document under","required":true,"schema":{"type":"string"}},{"name":"documentId","in":"path","description":"The Document ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The document referenced by the ID","content":{"application/json":{"schema":{"type":"object","description":"Can be any key-value pair"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The document or collection was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"patch":{"tags":["documents"],"summary":"Update a document","description":"Update an individual document from a collection by using its ID. The update can be partial.","operationId":"updateDocument","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to search for the document under","required":true,"schema":{"type":"string"}},{"name":"documentId","in":"path","description":"The Document ID","required":true,"schema":{"type":"string"}},{"name":"dirty_values","in":"query","description":"Dealing with Dirty Data","schema":{"$ref":"#/components/schemas/DirtyValues"}}],"requestBody":{"description":"The document object with fields to be updated","content":{"application/json":{"schema":{"type":"object","description":"Can be any key-value pair","x-go-type":"interface{}"}}},"required":true},"responses":{"200":{"description":"The document referenced by the ID was updated","content":{"application/json":{"schema":{"type":"object","description":"Can be any key-value pair"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The document or collection was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["documents"],"summary":"Delete a document","description":"Delete an individual document from a collection by using its ID.","operationId":"deleteDocument","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection to search for the document under","required":true,"schema":{"type":"string"}},{"name":"documentId","in":"path","description":"The Document ID","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The document referenced by the ID was deleted","content":{"application/json":{"schema":{"type":"object","description":"Can be any key-value pair"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The document or collection was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/conversations/models":{"get":{"description":"Retrieve all conversation models","operationId":"retrieveAllConversationModels","responses":{"200":{"content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ConversationModelSchema"},"type":"array","x-go-type":"[]*ConversationModelSchema"}}},"description":"List of all conversation models"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"List all conversation models","tags":["conversations"]},"post":{"summary":"Create a conversation model","description":"Create a Conversation Model","operationId":"createConversationModel","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationModelCreateSchema"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationModelSchema"}}},"description":"Created Conversation Model"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}},"description":"Bad request, see error message for details"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"tags":["conversations"]}},"/conversations/models/{modelId}":{"get":{"description":"Retrieve a conversation model","operationId":"retrieveConversationModel","parameters":[{"name":"modelId","in":"path","description":"The id of the conversation model to retrieve","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationModelSchema"}}},"description":"A conversation model"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Retrieve a conversation model","tags":["conversations"]},"put":{"description":"Update a conversation model","operationId":"updateConversationModel","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationModelUpdateSchema"}}},"required":true},"parameters":[{"name":"modelId","in":"path","description":"The id of the conversation model to update","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationModelSchema"}}},"description":"The conversation model was successfully updated"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Update a conversation model","tags":["conversations"]},"delete":{"description":"Delete a conversation model","operationId":"deleteConversationModel","parameters":[{"name":"modelId","in":"path","description":"The id of the conversation model to delete","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationModelSchema"}}},"description":"The conversation model was successfully deleted"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}},"summary":"Delete a conversation model","tags":["conversations"]}},"/browser-keys":{"post":{"tags":["browser-keys"],"summary":"Mint a short-lived search key for a browser","description":"Derives a secured key (`nssk_…`) from the calling full key, narrowed to the `search` scope and to the given collections and origins. It reaches only the storefront operations — search, recommendations, events, voice, image and semantic search and the assistant — and expires by itself (at most seven days), so a copy taken out of a page has a bounded blast radius. Revoking or rotating the parent key invalidates every browser key derived from it. The parent must be a full key created after secured keys were introduced (it carries a signing secret); a browser key cannot mint another.\n","operationId":"createBrowserKey","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrowserKeyRequest"}}}},"responses":{"201":{"description":"The minted browser key — returned only here, it is not stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrowserKey"}}}},"400":{"description":"The parent key cannot mint browser keys, or a restriction is malformed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/aliases":{"get":{"tags":["collections"],"summary":"List all aliases","description":"List all aliases and the corresponding collections that they map to.","operationId":"getAliases","responses":{"200":{"description":"List of all collection aliases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionAliasesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/aliases/{aliasName}":{"put":{"tags":["collections"],"summary":"Create or update a collection alias","description":"Create or update a collection alias. An alias is a virtual collection name that points to a real collection. If you're familiar with symbolic links on Linux, it's very similar to that. Aliases are useful when you want to reindex your data in the background on a new collection and switch your application to it without any changes to your code.","operationId":"upsertAlias","parameters":[{"name":"aliasName","in":"path","description":"The name of the alias to create/update","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Collection alias to be created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionAliasSchema"}}}},"responses":{"200":{"description":"The collection alias was created/updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionAlias"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Alias not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"get":{"tags":["collections"],"summary":"Retrieve an alias","description":"Find out which collection an alias points to by fetching it","operationId":"getAlias","parameters":[{"name":"aliasName","in":"path","description":"The name of the alias to retrieve","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Collection alias fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionAlias"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The alias was not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["collections"],"summary":"Delete an alias","description":"Deletes a collection alias by name, removing the alias mapping from the system.","operationId":"deleteAlias","parameters":[{"name":"aliasName","in":"path","description":"The name of the alias to delete","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Collection alias was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionAlias"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Alias not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/health":{"get":{"tags":["health"],"summary":"Checks if AACSearch node is ready to accept requests.","description":"Checks if AACSearch node is ready to accept requests.","operationId":"health","responses":{"200":{"description":"Search service is ready for requests.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/multi_search":{"post":{"operationId":"multiSearch","x-nova-key-scope":"search","tags":["documents"],"summary":"send multiple search requests in a single HTTP request","description":"This is especially useful to avoid round-trip network latencies incurred otherwise if each of these requests are sent in separate HTTP requests. You can also use this feature to do a federated search across multiple collections in a single HTTP request. AACSearch extension: with `debug=true` (in the query string, on a search item, or the `X-NOVA-DEBUG: 1` header) the response includes `_trace` and every hit an `_explain` object, as for `searchCollection`. Every response carries an `X-Nova-Trace-Id` header identifying it in the query log.\n","parameters":[{"name":"X-NOVA-DEBUG","in":"header","required":false,"description":"AACSearch extension. `1` requests debug output, same as the `debug` search parameter: the response carries `_trace` and every hit an `_explain` object.\n","schema":{"type":"string"}},{"name":"multiSearchParameters","required":true,"in":"query","style":"form","explode":true,"schema":{"$ref":"#/components/schemas/MultiSearchParameters"}},{"name":"X-NOVA-SESSION-ID","in":"header","required":false,"description":"The caller's session. Enrols each search in running experiments on its collection (sticky per session); the applied variants come back in the `X-Nova-Experiment` response header as `<experiment_id>:<variant_id>`, comma-separated.\n","schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultiSearchSearchesParameter"}}}},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MultiSearchResult"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/analytics/events":{"post":{"tags":["analytics"],"summary":"Create an analytics event","description":"Submit a single analytics event. The event must correspond to an existing analytics rule by name.","operationId":"createAnalyticsEvent","requestBody":{"description":"The analytics event to be created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsEvent"}}},"required":true},"responses":{"200":{"description":"Analytics event successfully created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsEventCreateResponse"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"get":{"tags":["analytics"],"summary":"Retrieve analytics events","description":"Retrieve the most recent events for a user and rule.","operationId":"getAnalyticsEvents","parameters":[{"name":"user_id","in":"query","required":true,"schema":{"type":"string"}},{"name":"name","in":"query","description":"Analytics rule name","required":true,"schema":{"type":"string"}},{"name":"n","in":"query","description":"Number of events to return (max 1000)","required":true,"schema":{"type":"integer"}}],"responses":{"200":{"description":"Events fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsEventsResponse"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/analytics/rules":{"post":{"tags":["analytics"],"summary":"Create analytics rule(s)","description":"Create one or more analytics rules. You can send a single rule object or an array of rule objects.","operationId":"createAnalyticsRule","requestBody":{"description":"The analytics rule(s) to be created","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AnalyticsRuleCreate"},{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsRuleCreate"}}]}}},"required":true},"responses":{"200":{"description":"Analytics rule(s) successfully created","content":{"application/json":{"schema":{"oneOf":[{"$ref":"#/components/schemas/AnalyticsRule"},{"type":"array","items":{"oneOf":[{"$ref":"#/components/schemas/AnalyticsRule"},{"type":"object","properties":{"error":{"type":"string"}}}]}}]}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"get":{"tags":["analytics"],"summary":"Retrieve analytics rules","description":"Retrieve all analytics rules. Use the optional rule_tag filter to narrow down results.","operationId":"retrieveAnalyticsRules","parameters":[{"in":"query","name":"rule_tag","schema":{"type":"string"},"required":false,"description":"Filter rules by rule_tag"}],"responses":{"200":{"description":"Analytics rules fetched","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsRule"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/analytics/rules/{ruleName}":{"put":{"tags":["analytics"],"summary":"Upserts an analytics rule","description":"Upserts an analytics rule with the given name.","operationId":"upsertAnalyticsRule","parameters":[{"in":"path","name":"ruleName","description":"The name of the analytics rule to upsert","schema":{"type":"string"},"required":true}],"requestBody":{"description":"The Analytics rule to be upserted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsRuleUpdate"}}},"required":true},"responses":{"200":{"description":"Analytics rule successfully upserted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsRule"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"get":{"tags":["analytics"],"summary":"Retrieves an analytics rule","description":"Retrieve the details of an analytics rule, given it's name","operationId":"retrieveAnalyticsRule","parameters":[{"in":"path","name":"ruleName","description":"The name of the analytics rule to retrieve","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Analytics rule fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsRule"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Analytics rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["analytics"],"summary":"Delete an analytics rule","description":"Permanently deletes an analytics rule, given it's name","operationId":"deleteAnalyticsRule","parameters":[{"in":"path","name":"ruleName","description":"The name of the analytics rule to delete","schema":{"type":"string"},"required":true}],"responses":{"200":{"description":"Analytics rule deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsRule"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Analytics rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/analytics/metrics/queries":{"get":{"tags":["analytics"],"summary":"Popular queries with search/CTR/conversion/revenue metrics","description":"Per-query table for the organization: searches, results-found rate (whose inverse is the zero-result rate), CTR, no-click rate, add-to-carts, purchases, revenue and conversion rate, computed from stored search events. Sorted by search volume, then revenue. Requires a bounded date range (`from`/`to`, max 366 days).\n","operationId":"listAnalyticsQueryMetrics","parameters":[{"$ref":"#/components/parameters/AnalyticsMetricsFrom"},{"$ref":"#/components/parameters/AnalyticsMetricsTo"},{"$ref":"#/components/parameters/AnalyticsMetricsCollection"},{"$ref":"#/components/parameters/AnalyticsMetricsLimit"},{"$ref":"#/components/parameters/AnalyticsMetricsOffset"}],"responses":{"200":{"description":"Query metrics page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsQueryMetricsResponse"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/analytics/metrics/zero-results":{"get":{"tags":["analytics"],"summary":"Zero-result query share","description":"Per-query zero-result rate (the inverse of `results_found_rate`), sorted by zero-result rate then search volume, plus the organization-wide zero-result share for the range. Requires a bounded date range (`from`/`to`, max 366 days).\n","operationId":"listAnalyticsZeroResultMetrics","parameters":[{"$ref":"#/components/parameters/AnalyticsMetricsFrom"},{"$ref":"#/components/parameters/AnalyticsMetricsTo"},{"$ref":"#/components/parameters/AnalyticsMetricsCollection"},{"$ref":"#/components/parameters/AnalyticsMetricsLimit"},{"$ref":"#/components/parameters/AnalyticsMetricsOffset"}],"responses":{"200":{"description":"Zero-result metrics page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsZeroResultMetricsResponse"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/analytics/metrics/funnel":{"get":{"tags":["analytics"],"summary":"Search-to-purchase funnel","description":"Fixed `search -> click -> add_to_cart -> purchase` funnel: sessions reaching each step, step conversion and overall conversion. Requires a bounded date range (`from`/`to`, max 366 days).\n","operationId":"getAnalyticsFunnelMetrics","parameters":[{"$ref":"#/components/parameters/AnalyticsMetricsFrom"},{"$ref":"#/components/parameters/AnalyticsMetricsTo"},{"$ref":"#/components/parameters/AnalyticsMetricsCollection"}],"responses":{"200":{"description":"Funnel metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsFunnelMetricsResponse"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/analytics/metrics/revenue-attribution":{"get":{"tags":["analytics"],"summary":"Last-search revenue attribution","description":"Purchases attributed to the most recent search within a 30-minute window: totals (purchases, attributed purchases, revenue, attributed/unattributed revenue) plus a paginated per-query breakdown. Requires a bounded date range (`from`/`to`, max 366 days).\n","operationId":"getAnalyticsRevenueAttributionMetrics","parameters":[{"$ref":"#/components/parameters/AnalyticsMetricsFrom"},{"$ref":"#/components/parameters/AnalyticsMetricsTo"},{"$ref":"#/components/parameters/AnalyticsMetricsCollection"},{"$ref":"#/components/parameters/AnalyticsMetricsLimit"},{"$ref":"#/components/parameters/AnalyticsMetricsOffset"}],"responses":{"200":{"description":"Revenue attribution metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyticsRevenueAttributionMetricsResponse"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/stopwords":{"get":{"tags":["stopwords"],"summary":"Retrieves all stopwords sets.","description":"Retrieve the details of all stopwords sets","operationId":"retrieveStopwordsSets","responses":{"200":{"description":"Stopwords sets fetched.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopwordsSetsRetrieveAllSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/stopwords/{setId}":{"put":{"tags":["stopwords"],"summary":"Upserts a stopwords set.","description":"When an analytics rule is created, we give it a name and describe the type, the source collections and the destination collection.","operationId":"upsertStopwordsSet","parameters":[{"in":"path","name":"setId","description":"The ID of the stopwords set to upsert.","schema":{"type":"string"},"required":true,"example":"countries"}],"requestBody":{"description":"The stopwords set to upsert.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopwordsSetUpsertSchema"}}},"required":true},"responses":{"200":{"description":"Stopwords set successfully upserted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopwordsSetSchema"}}}},"400":{"description":"Bad request, see error message for details.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"get":{"tags":["stopwords"],"summary":"Retrieves a stopwords set.","description":"Retrieve the details of a stopwords set, given it's name.","operationId":"retrieveStopwordsSet","parameters":[{"in":"path","name":"setId","description":"The ID of the stopwords set to retrieve.","schema":{"type":"string"},"required":true,"example":"countries"}],"responses":{"200":{"description":"Stopwords set fetched.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StopwordsSetRetrieveSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Stopwords set not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["stopwords"],"summary":"Delete a stopwords set.","description":"Permanently deletes a stopwords set, given it's name.","operationId":"deleteStopwordsSet","parameters":[{"in":"path","name":"setId","description":"The ID of the stopwords set to delete.","schema":{"type":"string"},"required":true,"example":"countries"}],"responses":{"200":{"description":"Stopwords set rule deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"}},"required":["id"],"example":{"id":"countries"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Stopwords set not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/presets":{"get":{"tags":["presets"],"summary":"Retrieves all presets.","description":"Retrieve the details of all presets","operationId":"retrieveAllPresets","responses":{"200":{"description":"Presets fetched.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresetsRetrieveSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/presets/{presetId}":{"get":{"tags":["presets"],"summary":"Retrieves a preset.","description":"Retrieve the details of a preset, given it's name.","operationId":"retrievePreset","parameters":[{"in":"path","name":"presetId","description":"The ID of the preset to retrieve.","schema":{"type":"string"},"required":true,"example":"listing_view"}],"responses":{"200":{"description":"Preset fetched.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresetSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Preset not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["presets"],"summary":"Upserts a preset.","description":"Create or update an existing preset.","operationId":"upsertPreset","parameters":[{"in":"path","name":"presetId","description":"The name of the preset set to upsert.","schema":{"type":"string"},"required":true,"example":"listing_view"}],"requestBody":{"description":"The stopwords set to upsert.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresetUpsertSchema"}}},"required":true},"responses":{"200":{"description":"Preset successfully upserted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresetSchema"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["presets"],"summary":"Delete a preset.","description":"Permanently deletes a preset, given it's name.","operationId":"deletePreset","parameters":[{"in":"path","name":"presetId","description":"The ID of the preset to delete.","schema":{"type":"string"},"required":true,"example":"listing_view"}],"responses":{"200":{"description":"Preset deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresetDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Preset not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/stemming/dictionaries":{"get":{"tags":["stemming"],"summary":"List all stemming dictionaries","description":"Retrieve a list of all available stemming dictionaries.","operationId":"listStemmingDictionaries","responses":{"200":{"description":"List of all dictionaries","content":{"application/json":{"schema":{"type":"object","properties":{"dictionaries":{"type":"array","items":{"type":"string"},"example":["irregular-plurals","company-terms"]}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/stemming/dictionaries/{dictionaryId}":{"get":{"tags":["stemming"],"summary":"Retrieve a stemming dictionary","description":"Fetch details of a specific stemming dictionary.","operationId":"getStemmingDictionary","parameters":[{"name":"dictionaryId","in":"path","description":"The ID of the dictionary to retrieve","required":true,"schema":{"type":"string"},"example":"irregular-plurals"}],"responses":{"200":{"description":"Stemming dictionary details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StemmingDictionary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Dictionary not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/stemming/dictionaries/import":{"post":{"tags":["stemming"],"summary":"Import a stemming dictionary","description":"Upload a JSONL file containing word mappings to create or update a stemming dictionary.","operationId":"importStemmingDictionary","parameters":[{"name":"id","in":"query","description":"The ID to assign to the dictionary","required":true,"schema":{"type":"string"},"example":"irregular-plurals"}],"requestBody":{"description":"The JSONL file containing word mappings","required":true,"content":{"application/json":{"schema":{"type":"string","example":"{\"word\": \"people\", \"root\": \"person\"}\n{\"word\": \"children\", \"root\": \"child\"}\n"}}}},"responses":{"200":{"description":"Dictionary successfully imported","content":{"application/octet-stream":{"schema":{"type":"string","example":"{\"word\": \"people\", \"root\": \"person\"} {\"word\": \"children\", \"root\": \"child\"}\n"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/nl_search_models":{"get":{"tags":["nl_search_models"],"summary":"List all NL search models","description":"Retrieve all NL search models.","operationId":"retrieveAllNLSearchModels","responses":{"200":{"description":"List of all NL search models","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/NLSearchModelSchema"}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"tags":["nl_search_models"],"summary":"Create a NL search model","description":"Create a new NL search model.","operationId":"createNLSearchModel","requestBody":{"description":"The NL search model to be created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLSearchModelCreateSchema"}}},"required":true},"responses":{"201":{"description":"NL search model successfully created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLSearchModelSchema"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/nl_search_models/{modelId}":{"get":{"tags":["nl_search_models"],"summary":"Retrieve a NL search model","description":"Retrieve a specific NL search model by its ID.","operationId":"retrieveNLSearchModel","parameters":[{"name":"modelId","in":"path","description":"The ID of the NL search model to retrieve","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NL search model fetched","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLSearchModelSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"NL search model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["nl_search_models"],"summary":"Update a NL search model","description":"Update an existing NL search model.","operationId":"updateNLSearchModel","parameters":[{"name":"modelId","in":"path","description":"The ID of the NL search model to update","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"The NL search model fields to update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLSearchModelUpdateSchema"}}},"required":true},"responses":{"200":{"description":"NL search model successfully updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLSearchModelSchema"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"NL search model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["nl_search_models"],"summary":"Delete a NL search model","description":"Delete a specific NL search model by its ID.","operationId":"deleteNLSearchModel","parameters":[{"name":"modelId","in":"path","description":"The ID of the NL search model to delete","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"NL search model successfully deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NLSearchModelDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"NL search model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/events":{"post":{"tags":["events"],"summary":"Ingest behavioural events","description":"Records a batch of behavioural events for the calling organization. Events are validated synchronously and stored asynchronously; the response reports how many were accepted and which entries were rejected. Use `query_id` to tie clicks and purchases back to the search or recommendation response they came from.\n","operationId":"ingestEvents","x-nova-key-scope":"search","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsBatch"}}}},"responses":{"202":{"description":"Batch accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsAccepted"}}}},"400":{"description":"Malformed batch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/entitlement":{"get":{"tags":["entitlement"],"summary":"Plan, expiry and what is left","description":"The organization's subscription and the state of both metered resources. Everything an integration needs to decide what to show: `plan.status` and `plan.expires_at` for the subscription, `features` for what the plan covers, `quota` for search requests in the current period, and `credits` for AI operations (assistants, voice, image and semantic search). Cheap to call and safe to cache for a few minutes — it is not a per-request authorization check, the API enforces the same limits itself.\n","operationId":"getEntitlement","responses":{"200":{"description":"Current entitlement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entitlement"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/recommendation_models":{"get":{"tags":["recommendations"],"summary":"List recommendation models","description":"Lists the recommendation models configured on a collection.","operationId":"listRecommendationModels","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Recommendation models on the collection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationModelsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/recommendation_models/{modelId}":{"get":{"tags":["recommendations"],"summary":"Retrieve a recommendation model","description":"Retrieves the configuration and build status of a recommendation model.","operationId":"getRecommendationModel","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"modelId","in":"path","description":"The id of the recommendation model","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Recommendation model","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationModel"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["recommendations"],"summary":"Create or update a recommendation model","description":"Creates a recommendation model on the collection, or replaces its configuration if the id already exists. `looking_similar` and `session` models need `vector_field`, a vector field of the collection; `trending`, `related_items` and `bought_together` are computed from ingested events and need none.\n","operationId":"upsertRecommendationModel","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"modelId","in":"path","description":"The id of the recommendation model","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationModelUpsertSchema"}}}},"responses":{"200":{"description":"Recommendation model saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationModel"}}}},"400":{"description":"Invalid configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["recommendations"],"summary":"Delete a recommendation model","description":"Deletes a recommendation model. Recommendations for it stop immediately.","operationId":"deleteRecommendationModel","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"modelId","in":"path","description":"The id of the recommendation model","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Recommendation model deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationModelDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/recommendations":{"post":{"tags":["recommendations"],"summary":"Get recommendations","description":"Returns documents recommended by a model. Pass `object_id` for item-to-item models (`looking_similar`, `related_items`, `bought_together`), `session_id` or `user_id` for `session`, and nothing for `trending`. Hits use the same shape as search results so they can be rendered by the same code.\n","operationId":"getRecommendations","x-nova-key-scope":"search","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationsRequest"}}}},"responses":{"200":{"description":"Recommended documents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationsResponse"}}}},"400":{"description":"Request does not match the model type","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Model not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/suggest":{"get":{"tags":["query_intelligence"],"summary":"Typeahead suggestions","description":"Suggestions for a prefix while the visitor types (TYPEAHEAD surface). Candidates come from the collection's popular queries, its documents, linked catalogue entities (brands, categories), the query graph continuing the session's last query, search-rule suggestions and the session's recent searches; they are ranked by expected downstream usefulness (not just count or CTR), de-duplicated semantically and filtered of queries known to return nothing. Every returned suggestion is logged as an impression with its position; report the chosen one as a `suggestion_select` event with `query_id` = `suggest_id`. Never calls a language model.\n","operationId":"suggestQueries","x-nova-key-scope":"search","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"q","in":"query","required":true,"description":"The prefix typed so far. Empty returns pre-search prompts (same as `presearch`).","schema":{"type":"string","maxLength":200}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"default":8}},{"name":"last_query","in":"query","required":false,"description":"The session's previous search, for contextual continuations.","schema":{"type":"string","maxLength":200}},{"name":"x_user_id","in":"query","required":false,"description":"The signed-in visitor's id, for recent searches.","schema":{"type":"string"}},{"name":"x_anonymous_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-NOVA-SESSION-ID","in":"header","required":false,"description":"The caller's session, for recent searches and impression attribution.","schema":{"type":"string"}}],"responses":{"200":{"description":"Ranked suggestions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuggestResponse"}}}},"400":{"description":"Bad request, see error message for details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/presearch":{"get":{"tags":["query_intelligence"],"summary":"Pre-search prompts","description":"What to show before the visitor types (PRESEARCH surface): the session's or user's recent searches, contextual continuations of the last query (from the query graph), and what is trending on the collection. Sections are omitted when empty. Report a chosen item as a `suggestion_select` event with `query_id` = `presearch_id`.\n","operationId":"presearchQueries","x-nova-key-scope":"search","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"description":"Items per section.","schema":{"type":"integer","minimum":1,"maximum":20,"default":5}},{"name":"last_query","in":"query","required":false,"schema":{"type":"string","maxLength":200}},{"name":"x_user_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"x_anonymous_id","in":"query","required":false,"schema":{"type":"string"}},{"name":"X-NOVA-SESSION-ID","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Pre-search sections","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresearchResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/voice/transcriptions":{"post":{"tags":["voice"],"summary":"Transcribe an audio clip","description":"Turns a short recording into text. Accepts what browsers and phones produce (webm/opus, mp4/m4a, ogg, wav, mp3, flac) up to 25 MB; no conversion to WAV is needed. The language is detected when not given.\n","operationId":"createTranscription","x-nova-key-scope":"search","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/TranscriptionRequest"}}}},"responses":{"200":{"description":"Transcription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Transcription"}}}},"400":{"description":"Unsupported or empty audio","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/documents/search/by_voice":{"post":{"tags":["voice"],"summary":"Search a collection by voice","description":"Transcribes the recording and runs a search with the text as `q`. Pass any search parameters (for example `query_by`, `filter_by`, `nl_query`) as a JSON object in the `params` field. The transcript is returned in `request_params.voice_query.transcribed_query`.\n","operationId":"searchByVoice","x-nova-key-scope":"search","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/VoiceSearchRequest"}}}},"responses":{"200":{"description":"Search results","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResult"}}}},"400":{"description":"Unsupported audio or invalid search parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/assistants":{"get":{"tags":["assistants"],"summary":"List assistants","description":"Lists the assistants of the calling organization.","operationId":"listAssistants","responses":{"200":{"description":"Assistants","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"tags":["assistants"],"summary":"Create an assistant","description":"Creates an assistant that answers questions from one or more collections. Each collection entry says which fields to search and how many documents to hand to the model.\n","operationId":"createAssistant","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantUpsertSchema"}}}},"responses":{"201":{"description":"Assistant created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Assistant"}}}},"400":{"description":"Invalid configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/assistants/{assistantId}":{"get":{"tags":["assistants"],"summary":"Retrieve an assistant","description":"Retrieves an assistant's configuration.","operationId":"getAssistant","parameters":[{"name":"assistantId","in":"path","description":"The id of the assistant","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Assistant","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Assistant"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Assistant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["assistants"],"summary":"Update an assistant","description":"Replaces an assistant's configuration. Existing conversations keep working.","operationId":"updateAssistant","parameters":[{"name":"assistantId","in":"path","description":"The id of the assistant","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantUpsertSchema"}}}},"responses":{"200":{"description":"Assistant updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Assistant"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Assistant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["assistants"],"summary":"Delete an assistant","description":"Deletes an assistant and its conversations.","operationId":"deleteAssistant","parameters":[{"name":"assistantId","in":"path","description":"The id of the assistant","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Assistant deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Assistant not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/assistants/{assistantId}/chat/completions":{"post":{"tags":["assistants"],"summary":"Ask the assistant","description":"Retrieves matching documents from the assistant's collections, answers with the model and returns the answer together with the documents it was based on. Pass the returned `conversation_id` in the next request to continue the conversation.\n","operationId":"createChatCompletion","x-nova-key-scope":"search","parameters":[{"name":"assistantId","in":"path","description":"The id of the assistant","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}}},"responses":{"200":{"description":"Answer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletion"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Assistant or conversation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/assistants/{assistantId}/chat/completions/stream":{"post":{"tags":["assistants"],"summary":"Ask the assistant (streaming)","description":"Same as `createChatCompletion`, but the answer arrives as Server-Sent Events: `sources` first, then `delta` chunks of the answer, then `usage` and `done` with the `conversation_id`.\n","operationId":"streamChatCompletion","x-nova-key-scope":"search","x-fern-streaming":{"format":"sse"},"parameters":[{"name":"assistantId","in":"path","description":"The id of the assistant","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}}},"responses":{"200":{"description":"Event stream","content":{"text/event-stream":{"schema":{"$ref":"#/components/schemas/ChatChunk"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Assistant or conversation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/assistants/{assistantId}/conversations/{conversationId}":{"get":{"tags":["assistants"],"summary":"Retrieve a conversation","description":"Returns the messages exchanged so far in a conversation.","operationId":"getConversation","x-nova-key-scope":"search","parameters":[{"name":"assistantId","in":"path","description":"The id of the assistant","required":true,"schema":{"type":"string"}},{"name":"conversationId","in":"path","description":"The id of the conversation","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Conversation"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Conversation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["assistants"],"summary":"Delete a conversation","description":"Deletes a conversation and its messages (for example on a user's request).","operationId":"deleteConversation","x-nova-key-scope":"search","parameters":[{"name":"assistantId","in":"path","description":"The id of the assistant","required":true,"schema":{"type":"string"}},{"name":"conversationId","in":"path","description":"The id of the conversation","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Conversation deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Conversation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/cms/installations":{"get":{"tags":["cms"],"summary":"List CMS installations","description":"List CMS installations. Runtime credentials are installation-scoped and cannot authenticate against the tenant API.","operationId":"listCmsInstallations","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsInstallationsResponse"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Configuration revision conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}}},"post":{"tags":["cms"],"summary":"Create an installation and return its key once","description":"Create an installation and return its key once. Runtime credentials are installation-scoped and cannot authenticate against the tenant API.","operationId":"createCmsInstallation","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsInstallationCreated"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Configuration revision conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsInstallationCreate"}}}}}},"/cms/installations/{installationId}/config":{"put":{"tags":["cms"],"summary":"Publish configuration using optimistic revision control","description":"Publish configuration using optimistic revision control. Runtime credentials are installation-scoped and cannot authenticate against the tenant API.","operationId":"updateCmsConfiguration","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsInstallation"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Configuration revision conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsConfigUpdate"}}}},"parameters":[{"name":"installationId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120}}]}},"/cms/installations/{installationId}":{"delete":{"tags":["cms"],"summary":"Revoke an installation key without deleting its audit state","description":"Revoke an installation key without deleting its audit state. Runtime credentials are installation-scoped and cannot authenticate against the tenant API.","operationId":"revokeCmsInstallation","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsRevoked"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Configuration revision conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}},"parameters":[{"name":"installationId","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":120}}]}},"/cms/runtime":{"get":{"tags":["cms"],"summary":"Read the configuration of this installation","description":"Read the configuration of this installation. Runtime credentials are installation-scoped and cannot authenticate against the tenant API.","operationId":"getCmsRuntime","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsRuntime"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Configuration revision conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}},"security":[],"parameters":[{"name":"X-AACSEARCH-INSTALLATION-KEY","in":"header","required":true,"description":"Dedicated installation credential, issued once in Console.","schema":{"type":"string","pattern":"^aac_install_[a-f0-9]{64}$"}},{"name":"X-AACSEARCH-INSTALLATION-ORIGIN","in":"header","required":true,"schema":{"type":"string","format":"uri"},"description":"HTTPS origin pinned to this installation; clones require another installation."}]}},"/cms/runtime/entitlement":{"get":{"tags":["cms"],"summary":"Read subscription and quota state for this installation","description":"Read subscription and quota state for this installation. Runtime credentials are installation-scoped and cannot authenticate against the tenant API.","operationId":"getCmsEntitlement","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Entitlement"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Configuration revision conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}},"security":[],"parameters":[{"name":"X-AACSEARCH-INSTALLATION-KEY","in":"header","required":true,"description":"Dedicated installation credential, issued once in Console.","schema":{"type":"string","pattern":"^aac_install_[a-f0-9]{64}$"}},{"name":"X-AACSEARCH-INSTALLATION-ORIGIN","in":"header","required":true,"schema":{"type":"string","format":"uri"},"description":"HTTPS origin pinned to this installation; clones require another installation."}]}},"/cms/runtime/heartbeat":{"post":{"tags":["cms"],"summary":"Report discovery and acknowledge an applied configuration","description":"Report discovery and acknowledge an applied configuration. Runtime credentials are installation-scoped and cannot authenticate against the tenant API.","operationId":"acknowledgeCmsConfiguration","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsRuntime"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"Configuration revision conflict"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsHeartbeat"}}}},"security":[],"parameters":[{"name":"X-AACSEARCH-INSTALLATION-KEY","in":"header","required":true,"description":"Dedicated installation credential, issued once in Console.","schema":{"type":"string","pattern":"^aac_install_[a-f0-9]{64}$"}},{"name":"X-AACSEARCH-INSTALLATION-ORIGIN","in":"header","required":true,"schema":{"type":"string","format":"uri"},"description":"HTTPS origin pinned to this installation; clones require another installation."}]}},"/cms/runtime/stores/{storeId}/sources/{sourceId}/schema":{"get":{"tags":["cms"],"summary":"Read the collection schema for an installation source","description":"Uses only the connector and collection explicitly bound to this installation source. The installation key never grants tenant-wide API access.","operationId":"getCmsSourceSchema","security":[],"parameters":[{"name":"X-AACSEARCH-INSTALLATION-KEY","in":"header","required":true,"description":"Dedicated installation credential, issued once in Console.","schema":{"type":"string","pattern":"^aac_install_[a-f0-9]{64}$"}},{"name":"X-AACSEARCH-INSTALLATION-ORIGIN","in":"header","required":true,"schema":{"type":"string","format":"uri"},"description":"HTTPS origin pinned to this installation; clones require another installation."},{"in":"path","name":"storeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"sourceId","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionResponse"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Source unavailable"},"409":{"description":"Configuration has not been applied or origin mismatch"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}}}},"/cms/runtime/stores/{storeId}/sources/{sourceId}/search":{"post":{"tags":["cms"],"summary":"Search an installation source with facets","description":"Uses only the connector and collection explicitly bound to this installation source. The installation key never grants tenant-wide API access.","operationId":"searchCmsSource","security":[],"parameters":[{"name":"X-AACSEARCH-INSTALLATION-KEY","in":"header","required":true,"description":"Dedicated installation credential, issued once in Console.","schema":{"type":"string","pattern":"^aac_install_[a-f0-9]{64}$"}},{"name":"X-AACSEARCH-INSTALLATION-ORIGIN","in":"header","required":true,"schema":{"type":"string","format":"uri"},"description":"HTTPS origin pinned to this installation; clones require another installation."},{"in":"path","name":"storeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"sourceId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsRuntimeSearch"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResult"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Source unavailable"},"409":{"description":"Configuration has not been applied or origin mismatch"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}}}},"/cms/runtime/stores/{storeId}/sources/{sourceId}/events":{"post":{"tags":["cms"],"summary":"Enqueue source changes","description":"Uses only the connector and collection explicitly bound to this installation source. The installation key never grants tenant-wide API access.","operationId":"ingestCmsSource","security":[],"parameters":[{"name":"X-AACSEARCH-INSTALLATION-KEY","in":"header","required":true,"description":"Dedicated installation credential, issued once in Console.","schema":{"type":"string","pattern":"^aac_install_[a-f0-9]{64}$"}},{"name":"X-AACSEARCH-INSTALLATION-ORIGIN","in":"header","required":true,"schema":{"type":"string","format":"uri"},"description":"HTTPS origin pinned to this installation; clones require another installation."},{"in":"path","name":"storeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"sourceId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorWebhookBody"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorWebhookResponse"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Source unavailable"},"409":{"description":"Configuration has not been applied or origin mismatch"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}}}},"/cms/runtime/stores/{storeId}/sources/{sourceId}/behavior":{"post":{"tags":["cms"],"summary":"Record source behavioral events","description":"Records clicks, cart and purchase signals through the existing analytics pipeline. The server overrides every event collection with the bound source collection. The installation key never grants tenant-wide API access. Batches are limited to 64 KiB.","operationId":"ingestCmsBehavior","security":[],"parameters":[{"name":"X-AACSEARCH-INSTALLATION-KEY","in":"header","required":true,"description":"Dedicated installation credential, issued once in Console.","schema":{"type":"string","pattern":"^aac_install_[a-f0-9]{64}$"}},{"name":"X-AACSEARCH-INSTALLATION-ORIGIN","in":"header","required":true,"schema":{"type":"string","format":"uri"},"description":"HTTPS origin pinned to this installation; clones require another installation."},{"in":"path","name":"storeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"sourceId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsBatch"}}}},"responses":{"202":{"description":"Batch accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventsAccepted"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Source unavailable"},"409":{"description":"Configuration has not been applied or origin mismatch"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}}}},"/cms/runtime/stores/{storeId}/sources/{sourceId}/recommendations":{"post":{"tags":["cms"],"summary":"Recommend from the configured source model","description":"Uses only the connector and collection explicitly bound to this installation source. The installation key never grants tenant-wide API access.","operationId":"recommendCmsSource","security":[],"parameters":[{"name":"X-AACSEARCH-INSTALLATION-KEY","in":"header","required":true,"description":"Dedicated installation credential, issued once in Console.","schema":{"type":"string","pattern":"^aac_install_[a-f0-9]{64}$"}},{"name":"X-AACSEARCH-INSTALLATION-ORIGIN","in":"header","required":true,"schema":{"type":"string","format":"uri"},"description":"HTTPS origin pinned to this installation; clones require another installation."},{"in":"path","name":"storeId","required":true,"schema":{"type":"string"}},{"in":"path","name":"sourceId","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsRuntimeRecommendations"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RecommendationsResponse"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Source unavailable"},"409":{"description":"Configuration has not been applied or origin mismatch"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy temporarily unavailable"}}}},"/cms/installations/{installationId}/commands":{"get":{"tags":["cms"],"summary":"List the last 100 commands for an installation","description":"List the last 100 commands for an installation. Commands are a fixed set of CMS actions; no remote code or arbitrary parameters can be executed.","operationId":"listCmsCommands","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsCommandsResponse"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Installation or command unavailable"},"409":{"description":"Idempotency conflict, lost lease, cancelled command or unapplied configuration"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy unavailable"}},"parameters":[{"in":"path","name":"installationId","required":true,"schema":{"type":"string","minLength":1,"maxLength":120}}]},"post":{"tags":["cms"],"summary":"Queue an idempotent CMS action","description":"Queue an idempotent CMS action. Commands are a fixed set of CMS actions; no remote code or arbitrary parameters can be executed.","operationId":"createCmsCommand","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsCommand"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Installation or command unavailable"},"409":{"description":"Idempotency conflict, lost lease, cancelled command or unapplied configuration"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy unavailable"}},"parameters":[{"in":"path","name":"installationId","required":true,"schema":{"type":"string","minLength":1,"maxLength":120}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsCommandCreate"}}}}}},"/cms/installations/{installationId}/commands/{commandId}/cancel":{"post":{"tags":["cms"],"summary":"Cancel a queued or running CMS action","description":"Cancel a queued or running CMS action. Commands are a fixed set of CMS actions; no remote code or arbitrary parameters can be executed.","operationId":"cancelCmsCommand","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsCommand"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Installation or command unavailable"},"409":{"description":"Idempotency conflict, lost lease, cancelled command or unapplied configuration"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy unavailable"}},"parameters":[{"in":"path","name":"installationId","required":true,"schema":{"type":"string","minLength":1,"maxLength":120}},{"in":"path","name":"commandId","required":true,"schema":{"type":"string","minLength":1,"maxLength":120}}]}},"/cms/runtime/commands/claim":{"post":{"tags":["cms"],"summary":"Lease the next CMS action for 120 seconds","description":"Lease the next CMS action for 120 seconds. Commands are a fixed set of CMS actions; no remote code or arbitrary parameters can be executed.","operationId":"claimCmsCommand","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsCommandClaim"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Installation or command unavailable"},"409":{"description":"Idempotency conflict, lost lease, cancelled command or unapplied configuration"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy unavailable"}},"security":[],"parameters":[{"in":"header","name":"X-AACSEARCH-INSTALLATION-KEY","required":true,"schema":{"type":"string","minLength":1,"maxLength":512}},{"in":"header","name":"X-AACSEARCH-INSTALLATION-ORIGIN","required":true,"schema":{"type":"string","minLength":1,"maxLength":512}}]}},"/cms/runtime/commands/{commandId}":{"put":{"tags":["cms"],"summary":"Renew a command lease or acknowledge its result","description":"Renew a command lease or acknowledge its result. Commands are a fixed set of CMS actions; no remote code or arbitrary parameters can be executed.","operationId":"reportCmsCommand","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsCommand"}}}},"400":{"description":"Invalid request"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"description":"Organization suspended"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Installation or command unavailable"},"409":{"description":"Idempotency conflict, lost lease, cancelled command or unapplied configuration"},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Access policy unavailable"}},"security":[],"parameters":[{"in":"path","name":"commandId","required":true,"schema":{"type":"string","minLength":1,"maxLength":120}},{"in":"header","name":"X-AACSEARCH-INSTALLATION-KEY","required":true,"schema":{"type":"string","minLength":1,"maxLength":512}},{"in":"header","name":"X-AACSEARCH-INSTALLATION-ORIGIN","required":true,"schema":{"type":"string","minLength":1,"maxLength":512}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CmsCommandProgress"}}}}}},"/connectors":{"get":{"tags":["connectors"],"summary":"List connectors","description":"Lists CMS/feed connectors for the calling organization.","operationId":"listConnectors","responses":{"200":{"description":"Connectors","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"tags":["connectors"],"summary":"Create a connector","description":"Creates a connector bound to one collection. The response includes the signing `secret` once — store it in the CMS module (`connector_id` / `connector_secret`). Catalogue writes then go through `POST /connectors/{id}/webhook`.\n","operationId":"createConnector","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorCreateSchema"}}}},"responses":{"201":{"description":"Connector created (includes secret)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorWithSecret"}}}},"400":{"description":"Invalid configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/connectors/handshake":{"post":{"tags":["connectors"],"summary":"Negotiate connector capabilities","description":"A CMS module declares what it is (`cms`, `version`), which marketplace edition it runs as (`sku`) and which capabilities it can provide. The response is the effective set: only the capabilities that are declared, allowed by the SKU and covered by the organization's cloud plan are returned in `effective`; everything else is listed in `denied` with the reason (`not_declared`, `sku`, `plan`) and, for plan denials, the minimum tier required. The set can never exceed SKU ∩ plan — treat the response as the server-side contract for which features to switch on. A SKU that the current plan cannot carry at all (a `shop`, `b2b` or `enterprise` edition on the free tier) is refused with `403` and a `ConnectorHandshakeRefused` body. Stateless: call it after install and on a schedule, the platform stores nothing.\n","operationId":"handshakeConnector","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorHandshakeSchema"}}}},"responses":{"200":{"description":"Effective capabilities for this connector on the current plan","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorHandshakeResponse"}}}},"400":{"description":"Unknown capability, SKU or CMS","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Either the API key lacks the scope (standard `Forbidden`), or the declared SKU cannot run on the organization's plan at all — then `data.sku` and `data.plan` identify the refused pair.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorHandshakeRefused"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/connectors/{connectorId}":{"parameters":[{"name":"connectorId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["connectors"],"summary":"Retrieve a connector","description":"Returns connector configuration (secret is not included; only `secret_preview`).","operationId":"getConnector","responses":{"200":{"description":"Connector","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Connector"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["connectors"],"summary":"Update a connector","description":"Updates name, schedule, pull settings, or enabled flag. Does not rotate the secret.","operationId":"updateConnector","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorUpdateSchema"}}}},"responses":{"200":{"description":"Connector updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Connector"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["connectors"],"summary":"Delete a connector","description":"Deletes the connector, its journal rows and jobs. Indexed documents in the search index are kept.","operationId":"deleteConnector","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/connectors/{connectorId}/webhook":{"post":{"tags":["connectors"],"summary":"Ingest connector events","description":"Canonical CMS write path. Authenticated by HMAC (`X-Signature-Timestamp` + `X-Signature` over `timestamp.body`), not by API key. Body is one event object or `{ \"events\": [ ... ] }` (max 500). Events need `external_id` (or `element_id` / `id`); `event: delete` removes the document. Returns counts and a `job_id` for the apply queue.\n","operationId":"ingestConnectorWebhook","security":[],"parameters":[{"name":"connectorId","in":"path","required":true,"schema":{"type":"string"}},{"name":"X-Signature-Timestamp","in":"header","required":true,"schema":{"type":"string"}},{"name":"X-Signature","in":"header","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorWebhookBody"}}}},"responses":{"200":{"description":"Events accepted into the journal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorWebhookResponse"}}}},"400":{"description":"Invalid body","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"description":"Bad signature","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Unknown connector","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/connectors/{connectorId}/jobs":{"get":{"tags":["connectors"],"summary":"List connector jobs","description":"Recent ingest / pull / reindex jobs for a connector (newest first).","operationId":"listConnectorJobs","parameters":[{"name":"connectorId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Jobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorJobsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/connectors/{connectorId}/documents":{"get":{"tags":["connectors"],"summary":"List journaled connector documents","description":"Rows in the connector journal (what will be / was applied to the collection). Use Documents search for the live index.\n","operationId":"listConnectorDocuments","parameters":[{"name":"connectorId","in":"path","required":true,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Journal page","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectorDocumentsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/profile":{"get":{"tags":["ingest"],"summary":"Read the confirmed dataset profile","description":"Returns confirmed field roles and the proposal for this collection. It contains no raw sample values. A stored proposal is not proof of runtime readiness.","operationId":"getDatasetProfile","parameters":[{"name":"collectionName","in":"path","required":true,"description":"Collection name","schema":{"type":"string"}}],"responses":{"200":{"description":"Confirmed profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestPreviewResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection or confirmed profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["ingest"],"summary":"Confirm dataset roles and proposed configuration","description":"Reanalyzes a bounded sample with explicit overrides and stores the result for an existing collection. Rejects mapping conflicts or fields absent from the collection. Does not import documents, change the engine schema or enable paid features. The same budgets as ingest preview apply.","operationId":"confirmDatasetProfile","parameters":[{"name":"collectionName","in":"path","required":true,"description":"Collection name","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestPreviewRequest"}}}},"responses":{"200":{"description":"Confirmed profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestPreviewResponse"}}}},"400":{"description":"Invalid sample or incompatible proposal","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection or confirmed profile not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/ingest/preview":{"post":{"tags":["ingest"],"summary":"Preview a dataset and proposed search configuration","description":"Inspects a bounded inline sample without creating a collection, writing documents, fetching remote URLs or generating embeddings. Suggestions describe observed data, not verified capabilities. Explicit field-role overrides take precedence. Documents sources require documents and forbid content; text sources require nonempty content and forbid documents. Invalid combinations return 400. The complete preview payload is limited to 2 MiB UTF-8, 200 fields per object, eight nested document levels and 20,000 inspected values. Exceeding a request budget returns 400; analysis truncation is reported explicitly.\n","operationId":"previewIngest","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestPreviewRequest"}}}},"responses":{"200":{"description":"Sample profile and proposed mapping","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestPreviewResponse"}}}},"400":{"description":"Invalid sample, limits or overrides","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/ingest-jobs":{"get":{"tags":["ingest"],"summary":"List ingest jobs","description":"Recent web/document ingest jobs for the organization (newest first).","operationId":"listIngestJobs","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}}],"responses":{"200":{"description":"Jobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJobsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"tags":["ingest"],"summary":"Create an ingest job","description":"Queues an asynchronous ingest. Returns immediately with `status: queued`. Poll `getIngestJob` until `ready` or `failed`. Sources: `url` (same-origin crawl), `sitemap`, `yml` (a Yandex Market feed by `url` — plain or gzip, any size, `windows-1251` or UTF-8 — or a small feed inline in `content`; the collection is created with a products schema when it does not exist), `youtube`, `documents` (inline JSON documents with `id`), or `markdown` / `csv` / `html` text in `content`. For a feed file use `uploadIngestFeed`.\n","operationId":"createIngestJob","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJobCreateSchema"}}}},"responses":{"201":{"description":"Job accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJob"}}}},"400":{"description":"Invalid configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/ingest-jobs/{jobId}":{"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["ingest"],"summary":"Get ingest job status","description":"Upload status for a document ingest job. Poll until `status` is `ready` or `failed`. Terminal jobs include `stats.fetched` / `imported` / `failed` and optional `error`.\n","operationId":"getIngestJob","responses":{"200":{"description":"Job","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJob"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["ingest"],"summary":"Delete an ingest job record","description":"Removes the job row. Does not delete documents already imported into the collection.","operationId":"deleteIngestJob","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJobDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/ingest-jobs/upload":{"post":{"tags":["ingest"],"summary":"Upload a YML feed file","description":"Streams a Yandex Market YML feed file (plain XML or gzip, up to 500 MB and the request body limit of the Workers plan; `Content-Length` required) to storage and queues a `yml` ingest job for it, exactly like `createIngestJob` with source `yml` but for a file instead of a URL. The feed is read in resumable passes, so any number of offers works; `stats.cursor` tracks how many were consumed. The target collection is created with the products schema (name, vendor, category, category_path, price, currency, available, picture, description, url, params) when it does not exist. The file is deleted once the job is `ready`; a failed job keeps it so `retryIngestJob` can read it again.\n","operationId":"uploadIngestFeed","parameters":[{"name":"collection","in":"query","required":true,"description":"Target collection (without tenant prefix); created if missing","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Optional label shown in the console","schema":{"type":"string"}},{"name":"action","in":"query","required":false,"schema":{"$ref":"#/components/schemas/IngestJobAction"}},{"name":"source_name","in":"query","required":false,"description":"The file name, kept on the job for display","schema":{"type":"string","maxLength":2048}}],"requestBody":{"required":true,"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"201":{"description":"Job accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJob"}}}},"400":{"description":"Invalid parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"413":{"description":"Feed larger than allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/ingest-jobs/{jobId}/retry":{"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["ingest"],"summary":"Retry a failed ingest job","description":"Re-queues a `failed` job with its original config. Resets `stats` and `error`, and returns the job with `status: queued`. Jobs that are `queued`, `processing`, or `ready` cannot be retried.\n","operationId":"retryIngestJob","responses":{"200":{"description":"Job re-queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJob"}}}},"400":{"description":"Job is not in a retryable state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/support/threads":{"post":{"tags":["support"],"summary":"Open a support thread","description":"Starts a thread with its first message from the visitor. Sticky per `X-NOVA-SESSION-ID`, the same identity a conversation uses — a `search` key reads and posts only to threads opened by its own session; a `full` key (server-side use) is not session-restricted.\n","operationId":"createSupportThread","x-nova-key-scope":"search","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportThreadCreateSchema"}}}},"responses":{"201":{"description":"The thread, with its first message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportThread"}}}},"400":{"description":"Invalid request (empty message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/support/threads/{threadId}":{"parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"get":{"tags":["support"],"summary":"Retrieve a support thread","description":"Returns the thread and every message exchanged so far — poll this for new replies.","operationId":"getSupportThread","x-nova-key-scope":"search","responses":{"200":{"description":"The thread and its messages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportThread"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Thread not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/support/threads/{threadId}/messages":{"parameters":[{"name":"threadId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["support"],"summary":"Send a support message","description":"Appends a message from the visitor and reopens the thread if it was closed.","operationId":"createSupportMessage","x-nova-key-scope":"search","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportMessageCreateSchema"}}}},"responses":{"201":{"description":"The message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SupportMessage"}}}},"400":{"description":"Invalid request (empty message)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Thread not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/media":{"post":{"tags":["media"],"summary":"Upload an image","description":"Stores an image (PNG, JPEG, WebP or GIF, up to 8 MB) and computes its embedding in the background: the image is described by a vision model and the description is embedded with the same multilingual text model used by `createEmbeddings`, so text queries in any language and other images land in one vector space. Pass `collection`, `document_id` and `vector_field` to have the embedding written into that document (the field must be a `float[]` with `num_dim: 1024`); the description is written into `caption_field` when given. Poll `getMedia` until `embedding.status` is `ready`.\n","operationId":"uploadMedia","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/MediaUploadRequest"}}}},"responses":{"202":{"description":"Stored; embedding in progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaAsset"}}}},"400":{"description":"Unsupported file","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/media/{mediaId}":{"get":{"tags":["media"],"summary":"Retrieve an image's metadata","description":"Metadata and embedding status of an uploaded image.","operationId":"getMedia","parameters":[{"name":"mediaId","in":"path","description":"The id of the media asset","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Media asset","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaAsset"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Media not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["media"],"summary":"Delete an image","description":"Deletes the stored image and its metadata. Vectors already written into documents stay.","operationId":"deleteMedia","parameters":[{"name":"mediaId","in":"path","description":"The id of the media asset","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Media deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Media not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/media/{mediaId}/content":{"get":{"tags":["media"],"summary":"Download an image","description":"The stored bytes, with the original content type.","operationId":"getMediaContent","parameters":[{"name":"mediaId","in":"path","description":"The id of the media asset","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image bytes","content":{"image/*":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Media not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["media"],"summary":"Stream the bytes of a large upload","description":"Sends the image bytes for an asset created with `createMediaUpload`. The body is the raw file (`Content-Type` image/png, image/jpeg, image/webp or image/gif; `Content-Length` required, up to 100 MB); it is streamed to storage without buffering. Returns 202 once stored and the embedding job is queued; 409 if the asset already has content.\n","operationId":"putMediaContent","parameters":[{"name":"mediaId","in":"path","description":"The id of the media asset","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"image/*":{"schema":{"type":"string","format":"binary"}}}},"responses":{"202":{"description":"Stored; embedding in progress","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaAsset"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Media not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"Content already uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/embeddings":{"post":{"tags":["media"],"summary":"Embed text","description":"Turns text into 1024-dimensional multilingual vectors (`@cf/baai/bge-m3`). Use it to fill a `float[]` field of your documents so `searchSemantic` and `searchByImage` can match them; the same model embeds queries and image descriptions.\n","operationId":"createEmbeddings","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingsRequest"}}}},"responses":{"200":{"description":"Vectors, in input order","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingsResponse"}}}},"400":{"description":"Empty or too large input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/documents/search/semantic":{"post":{"tags":["media"],"summary":"Search a collection by meaning","description":"Embeds the query text and returns the nearest documents by `vector_field`. Works in any language the embedding model understands; combine with `filter_by` for facets.\n","operationId":"searchSemantic","x-nova-key-scope":"search","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SemanticSearchRequest"}}}},"responses":{"200":{"description":"Nearest documents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResult"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/documents/search/by_image":{"post":{"tags":["media"],"summary":"Search a collection by image","description":"Finds documents whose `vector_field` is closest to the given image — an uploaded `media_id`, an `image_url`, or inline `image_base64`. The image is embedded the same way uploads are, so results are consistent with `uploadMedia`.\n","operationId":"searchByImage","x-nova-key-scope":"search","parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImageSearchRequest"}}}},"responses":{"200":{"description":"Nearest documents","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchResult"}}}},"400":{"description":"No usable image in the request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection or media not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/media/uploads":{"post":{"tags":["media"],"summary":"Start a large upload","description":"Registers an image whose bytes will be streamed separately with `putMediaContent` — use it instead of `uploadMedia` for files above a few megabytes (up to 100 MB). The embedding job starts once the bytes arrive. Same targeting fields as `uploadMedia`.\n","operationId":"createMediaUpload","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaUploadCreateSchema"}}}},"responses":{"201":{"description":"Asset registered; awaiting bytes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaAsset"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/media/{mediaId}/signed_url":{"post":{"tags":["media"],"summary":"Create a signed download URL","description":"Returns a time-limited URL for `getMediaContent` that needs no API key — for `<img src>` in storefronts and emails. Anyone with the URL can fetch the image until it expires.\n","operationId":"createMediaSignedUrl","parameters":[{"name":"mediaId","in":"path","description":"The id of the media asset","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignedUrlRequest"}}}},"responses":{"200":{"description":"Signed URL","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MediaSignedUrl"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Media not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_sets/{synonymSetName}/export":{"get":{"tags":["synonyms"],"summary":"Export a synonym set as CSV","description":"Downloads the items of a synonym set as CSV with the columns `id,synonyms,root,locale` (synonyms separated by `|`), ready for a spreadsheet. Import the edited file with `importSynonymSet`.\n","operationId":"exportSynonymSet","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"CSV file","content":{"text/csv":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Synonym set not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_sets/{synonymSetName}/import":{"post":{"tags":["synonyms"],"summary":"Import synonyms from CSV","description":"Upserts items from a CSV with the columns `id,synonyms,root,locale` (header row required, synonyms separated by `|`; `root` and `locale` optional) into the set, creating the set if it does not exist. Existing items with other ids are kept. Rows that cannot be parsed are reported and skipped.\n","operationId":"importSynonymSet","parameters":[{"name":"synonymSetName","in":"path","description":"The name of the synonym set","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"text/csv":{"schema":{"type":"string"}}}},"responses":{"200":{"description":"Import result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymImportResult"}}}},"400":{"description":"Not a CSV with the expected header","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/synonym_suggestions":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"get":{"tags":["synonym_suggestions"],"summary":"List synonym suggestions","description":"Suggestions for the collection, newest first; filter by `status`.","operationId":"listSynonymSuggestions","parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","accepted","rejected"]}}],"responses":{"200":{"description":"Suggestions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSuggestionsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/synonym_suggestions/generate":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"post":{"tags":["synonym_suggestions"],"summary":"Generate synonym suggestions for zero-hit queries","description":"Examines up to `limit` zero-hit queries and stores every candidate that finds documents as a `pending` suggestion. Candidates come from the same rewrites the search proxy uses (`layout`, `translit`, `homoglyph`) and, unless `use_llm` is false, from a language model asked for spelling fixes, brand spellings and synonyms. Each candidate is verified with a real search; the suggestion records the term the engine matched (so `девольт` yields `dewalt`, the catalogue's spelling, not the model's guess), the hit count and a few sample titles. Queries that already find something are skipped. Synchronous; keep `limit` small and call it again for the next batch.\n","operationId":"generateSynonymSuggestions","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSuggestionsGenerateSchema"}}}},"responses":{"200":{"description":"The suggestions created or refreshed by this run","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSuggestionsResponse"}}}},"400":{"description":"Invalid request (unknown collection, missing analytics collection, …)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_suggestions/{suggestionId}":{"parameters":[{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"tags":["synonym_suggestions"],"summary":"Delete a synonym suggestion","description":"Removes the suggestion; an accepted one keeps its synonym in the engine.","operationId":"deleteSynonymSuggestion","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSuggestionDeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Suggestion not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_suggestions/{suggestionId}/accept":{"parameters":[{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["synonym_suggestions"],"summary":"Accept a synonym suggestion","description":"Writes a one-way synonym `query → term` as item `sug_<id>` of the synonym set (the suggestion's own, or `synonym_set` from the body), creating the set and attaching it to the collection when needed, and marks the suggestion `accepted`. Takes effect on the next search.\n","operationId":"acceptSynonymSuggestion","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSuggestionAcceptSchema"}}}},"responses":{"200":{"description":"Accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSuggestion"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Suggestion not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"The suggestion was already decided","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/synonym_suggestions/{suggestionId}/reject":{"parameters":[{"name":"suggestionId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["synonym_suggestions"],"summary":"Reject a synonym suggestion","description":"Marks the suggestion `rejected`; later runs will not propose the same pair again.","operationId":"rejectSynonymSuggestion","responses":{"200":{"description":"Rejected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SynonymSuggestion"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Suggestion not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/graph/entities":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"get":{"tags":["graph"],"summary":"List extracted entities","description":"Entities extracted from this collection's documents so far, most recently updated first.","operationId":"listGraphEntities","x-nova-key-scope":"search","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"Entities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphEntitiesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/graph/entities/generate":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"post":{"tags":["graph"],"summary":"Extract entities and relations from documents","description":"Reads `text_fields` off each of `document_ids`, asks a model for the named entities it mentions and the relations between them, and upserts them: an entity already known by the exact same `name` gets this document added to its `source_doc_ids` instead of a duplicate row. A new name that doesn't match exactly is still resolved semantically against this collection's existing entities of the same `type` by embedding similarity — a close enough match (e.g. \"De Walt\" against \"DeWalt\") is folded in as an `alias` rather than creating a near-duplicate entity; only a name with no close match becomes a new entity. A relation already known between the same two resolved entities is left as-is. A second model call then extracts claims (\"covariates\") about that document's resolved entities — specific assertions like a capability, certification, or limitation, distinct from the relations between entities — see `GraphClaim`. Synchronous; keep `document_ids` small (50 at most) and call it again for the next batch. Entity extraction is the expensive step of this feature — nothing runs on a schedule, this is the only way new entities and claims appear.\n","operationId":"generateGraphEntities","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphEntitiesGenerateSchema"}}}},"responses":{"200":{"description":"What this run extracted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphEntitiesGenerateResponse"}}}},"400":{"description":"Invalid request (unknown collection, unknown text_fields, …)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/graph/entities/{entityId}":{"parameters":[{"name":"entityId","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"tags":["graph"],"summary":"Delete an extracted entity","description":"Also drops every relation naming this entity as either endpoint.","operationId":"deleteGraphEntity","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphEntityDeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Entity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/graph/communities":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"get":{"tags":["graph"],"summary":"List community reports","description":"Community reports generated for this collection so far, most recent first.","operationId":"listGraphCommunities","responses":{"200":{"description":"Community reports","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphCommunitiesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/graph/communities/generate":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"post":{"tags":["graph"],"summary":"Group entities into community reports","description":"Groups this collection's extracted entities into a hierarchy of communities (multi-level Louvain modularity optimization over the relation graph — level 0 finest, each higher level a coarser merge of the level below, up to `max_levels`), and for every group of at least `min_size` entities at every level, asks a model for a short title and summary covering what the group is about. Existing reports for this collection are replaced. Re-run after `generateGraphEntities` adds enough new entities to be worth regrouping.\n","operationId":"generateGraphCommunities","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphCommunitiesGenerateSchema"}}}},"responses":{"200":{"description":"What this run produced","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphCommunitiesGenerateResponse"}}}},"400":{"description":"Invalid request (unknown collection)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/graph/global-search":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"post":{"tags":["graph"],"summary":"Answer a broad question via community reports (map-reduce)","description":"GraphRAG's actual \"Global Search\": every community report at `level` (default: the coarsest level generated, for the fewest, broadest reports and the lowest cost) gets one model call asking it for the key points it offers toward answering `question`, each with a 0-100 relevance score (the \"map\" step, run in parallel, capped at `max_communities` reports — the most similar to the question by embedding, when there are more than that at the level). The point across every report above a relevance floor are then pooled and given to one more model call that synthesizes them into a final answer (the \"reduce\" step). Suited to thematic or corpus-wide questions (\"what are the main categories here?\") that per-document retrieval answers poorly; for a question about one specific item, `createChatCompletion`'s ordinary retrieval is cheaper and more precise. Requires at least one `generateGraphCommunities` run for this collection.\n","operationId":"globalSearchGraph","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphGlobalSearchSchema"}}}},"responses":{"200":{"description":"The synthesized answer and which reports contributed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphGlobalSearchResponse"}}}},"400":{"description":"Invalid request (unknown collection, no community reports generated yet)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/graph/drift-search":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"post":{"tags":["graph"],"summary":"Answer a question via a Global Search primer plus Local Search follow-ups (DRIFT)","description":"GraphRAG's \"DRIFT\" mode: a primer step (`globalSearchGraph`'s map-reduce over `level`'s community reports, at most `max_communities` of them) proposes an intermediate answer plus specific follow-up questions the reports can't answer on their own. Each of the first `max_follow_ups` follow-ups is then answered by a Local Search step — the entities most relevant to that follow-up by embedding similarity, their one-hop graph neighbors, and any claims about them (see `generateGraphEntities`) — and a final model call synthesizes the primer answer with every follow-up's local answer into one response. This is single-level DRIFT: follow-ups are answered but do not themselves spawn further follow-ups. Requires at least one `generateGraphCommunities` run; a collection with no entities yet still runs the primer step but every follow-up comes back with an empty `answer`.\n","operationId":"driftSearchGraph","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphDriftSearchSchema"}}}},"responses":{"200":{"description":"The synthesized answer, the primer answer, and each follow-up's local answer","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphDriftSearchResponse"}}}},"400":{"description":"Invalid request (unknown collection, no community reports generated yet)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/PaymentRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/graph/communities/{communityId}":{"parameters":[{"name":"communityId","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"tags":["graph"],"summary":"Delete a community report","description":"Does not delete the entities it grouped — only the summary.","operationId":"deleteGraphCommunity","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphCommunityDeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Community not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/graph/claims":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"get":{"tags":["graph"],"summary":"List extracted claims","description":"Structured factual assertions (\"covariates\") about this collection's entities, extracted alongside them by `generateGraphEntities` — see `GraphClaim`.","operationId":"listGraphClaims","parameters":[{"name":"subject_id","in":"query","description":"Only claims about this entity.","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":100}}],"responses":{"200":{"description":"Claims","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphClaimsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/graph/claims/{claimId}":{"parameters":[{"name":"claimId","in":"path","required":true,"schema":{"type":"string"}}],"delete":{"tags":["graph"],"summary":"Delete an extracted claim","description":"Does not touch the entity it was about.","operationId":"deleteGraphClaim","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphClaimDeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Claim not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/search_rules":{"get":{"tags":["search_rules"],"summary":"List search rules","description":"Lists the search rules of every collection that has some configured.","operationId":"listSearchRules","responses":{"200":{"description":"Search rules per collection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRulesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/search_rules":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"get":{"tags":["search_rules"],"summary":"Get a collection's search rules","description":"Returns the collection's search rules. A collection without configured rules returns the defaults (no exclusion, no fallback, empty boosts / redirects / suggestions) rather than 404, so `get → edit → put` needs no special case.\n","operationId":"getSearchRule","responses":{"200":{"description":"Search rules","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRule"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["search_rules"],"summary":"Replace a collection's search rules","description":"Creates or replaces the whole rule set for the collection. Fields left out reset to their defaults, so send the complete configuration (start from `getSearchRule`). Takes effect on the next search request.\n","operationId":"upsertSearchRule","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRuleUpsertSchema"}}}},"responses":{"200":{"description":"Search rules saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRule"}}}},"400":{"description":"Invalid rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["search_rules"],"summary":"Delete a collection's search rules","description":"Removes every rule for the collection; searches go to the engine unchanged.","operationId":"deleteSearchRule","responses":{"200":{"description":"Search rules deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchRuleDeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The collection has no search rules","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/search-profiles":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"get":{"tags":["search_profiles"],"summary":"List a collection's search profiles","description":"Returns every search profile configured for the collection, default first.","operationId":"listSearchProfiles","responses":{"200":{"description":"Search profiles","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfilesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"tags":["search_profiles"],"summary":"Create a search profile","description":"Creates a named profile for the collection. `name` is the stable identifier clients send as `profile=<name>`; it cannot be changed later. The plan caps how many profiles a collection may have — over the cap the request is refused with `403` and a message that names the plan and its limit. `is_default: true` clears the flag on the collection's other profiles.\n","operationId":"createSearchProfile","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfileCreateSchema"}}}},"responses":{"201":{"description":"Search profile created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfile"}}}},"400":{"description":"Invalid profile (unknown default sort, empty searchable fields, bad name)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Either the API key lacks the scope (standard `Forbidden`), or the collection already has as many profiles as the organization's plan allows — then `message` names the plan and its limit.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"A profile with this name already exists on the collection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/search-profiles/{profileName}":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"profileName","in":"path","description":"The profile's stable name","required":true,"schema":{"type":"string"}}],"get":{"tags":["search_profiles"],"summary":"Get a search profile","description":"Returns the full profile, including the engine sort expressions and the fixed filter.","operationId":"getSearchProfile","responses":{"200":{"description":"Search profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfile"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such profile on this collection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["search_profiles"],"summary":"Replace a search profile","description":"Replaces the whole profile (start from `getSearchProfile`); fields left out reset to their defaults. The name is fixed. Before the first publication, takes effect on the next search request. After publication, updates only the draft; publish it to affect searches.\n","operationId":"updateSearchProfile","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfileUpsertSchema"}}}},"responses":{"200":{"description":"Search profile saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfile"}}}},"400":{"description":"Invalid profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such profile on this collection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["search_profiles"],"summary":"Delete a search profile","description":"Removes the profile. Requests that still name it get `404`; browser keys pinned to it stop working until re-minted.\n","operationId":"deleteSearchProfile","responses":{"200":{"description":"Search profile deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfileDeleteResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such profile on this collection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/search-profiles/{profileName}/view":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}},{"name":"profileName","in":"path","description":"The profile's stable name","required":true,"schema":{"type":"string"}}],"get":{"tags":["search_profiles"],"summary":"Read what a storefront may show for a profile","description":"The browser-safe projection of a profile: the sorts a visitor may pick (by id and label), the facets to render, the default sort and the page-size ceiling. It never carries engine expressions or field lists, so a browser key may read it. Widgets call it once at start-up.\n","operationId":"getSearchProfileView","x-nova-key-scope":"search","responses":{"200":{"description":"Search profile view","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfileView"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No such profile on this collection","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/search-profiles/{profileName}/releases":{"parameters":[{"name":"collectionName","in":"path","description":"Collection name","required":true,"schema":{"type":"string"}},{"name":"profileName","in":"path","description":"Stable profile name","required":true,"schema":{"type":"string"}}],"get":{"tags":["search_profiles"],"operationId":"listSearchProfileReleases","summary":"List immutable profile releases","description":"Returns bounded release history, newest first, and the active release identifier. Requires a full key.\n","parameters":[{"name":"limit","in":"query","description":"Maximum releases returned","schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"before_version","in":"query","description":"Return versions strictly below this cursor","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Successful operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfileReleasesResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Profile or release not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"Revision conflict or unsupported change class","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Profile unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}}}},"post":{"tags":["search_profiles"],"operationId":"publishSearchProfile","summary":"Publish the profile draft","description":"Atomically snapshots and activates the current draft if expected_revision matches. The first publication enables release mode; subsequent PUT requests edit only the draft. Only HOT query-time changes are supported; WARM and COLD requests are rejected. External search_policy contents are not snapshotted.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfilePublishSchema"}}}},"responses":{"201":{"description":"Successful operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfileRelease"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Profile or release not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"Revision conflict or unsupported change class","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Profile unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}}}}},"/collections/{collectionName}/search-profiles/{profileName}/releases/{version}/activate":{"parameters":[{"name":"collectionName","in":"path","description":"Collection name","required":true,"schema":{"type":"string"}},{"name":"profileName","in":"path","description":"Stable profile name","required":true,"schema":{"type":"string"}},{"name":"version","in":"path","description":"Release version to activate","required":true,"schema":{"type":"integer","minimum":1}}],"post":{"tags":["search_profiles"],"operationId":"activateSearchProfileRelease","summary":"Activate a previous profile release","description":"Atomically activates an immutable release when expected_revision matches. The draft is preserved. Activating the current release is idempotent. External search_policy contents are not restored.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfileActivateSchema"}}}},"responses":{"200":{"description":"Successful operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SearchProfile"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Profile or release not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"Revision conflict or unsupported change class","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"},"503":{"description":"Profile unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}}}}},"/experiments":{"get":{"tags":["experiments"],"summary":"List experiments","description":"Lists the organization's experiments, newest first.","operationId":"listExperiments","responses":{"200":{"description":"Experiments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentsResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"tags":["experiments"],"summary":"Create an experiment","description":"Creates an experiment in `draft`; nothing is served until `startExperiment`. Each variant carries the search parameters merged over every search request it is assigned to (`sort_by`, `preset`, `curation_tags`, `synonym_sets`, `filter_by`, `query_by_weights`, …). Make the first variant the control with empty `search_params`.\n","operationId":"createExperiment","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentUpsertSchema"}}}},"responses":{"201":{"description":"Experiment created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}}},"400":{"description":"Invalid configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/experiments/{experimentId}":{"get":{"tags":["experiments"],"summary":"Retrieve an experiment","description":"Configuration and status of an experiment.","operationId":"getExperiment","parameters":[{"name":"experimentId","in":"path","description":"The id of the experiment","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Experiment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Experiment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["experiments"],"summary":"Update an experiment","description":"Replaces the configuration of a `draft` or `stopped` experiment; a running one is 409.","operationId":"updateExperiment","parameters":[{"name":"experimentId","in":"path","description":"The id of the experiment","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentUpsertSchema"}}}},"responses":{"200":{"description":"Experiment updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Experiment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"Experiment is running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["experiments"],"summary":"Delete an experiment","description":"Deletes an experiment and its assignments; a running one is stopped first.","operationId":"deleteExperiment","parameters":[{"name":"experimentId","in":"path","description":"The id of the experiment","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Experiment deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Experiment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/experiments/{experimentId}/start":{"post":{"tags":["experiments"],"summary":"Start an experiment","description":"Starts serving variants. From now on every `searchCollection` / `multiSearch` request on the collection that carries `X-NOVA-SESSION-ID` is assigned to a variant (sticky per session, `traffic` share enrolled) and answered with the `X-Nova-Experiment` header.\n","operationId":"startExperiment","parameters":[{"name":"experimentId","in":"path","description":"The id of the experiment","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Experiment running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Experiment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"Already running","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/experiments/{experimentId}/stop":{"post":{"tags":["experiments"],"summary":"Stop an experiment","description":"Stops serving variants; the report stays available.","operationId":"stopExperiment","parameters":[{"name":"experimentId","in":"path","description":"The id of the experiment","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Experiment stopped","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Experiment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/experiments/{experimentId}/promote":{"post":{"tags":["experiments"],"summary":"Promote a winning variant","description":"Locks in a winner: collapses `variants` to just `variant_id` (so every enrolled session gets it) and sets `traffic` to `1`. The experiment stays `running` — a promoted experiment keeps applying its winning params to all traffic rather than stopping.\n","operationId":"promoteExperiment","parameters":[{"name":"experimentId","in":"path","description":"The id of the experiment","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentPromoteSchema"}}}},"responses":{"200":{"description":"Winning variant promoted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}}},"400":{"description":"Unknown variant_id","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Experiment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/experiments/{experimentId}/promotion/rollback":{"post":{"tags":["experiments"],"summary":"Restore the configuration before promotion","description":"Restores the variants and traffic saved by the latest promotion and records a new revision. Rejects the request if no reversible promotion exists or the configuration has since changed. Experiment status is preserved.","operationId":"rollbackExperimentPromotion","parameters":[{"name":"experimentId","in":"path","required":true,"description":"Experiment id","schema":{"type":"string"}}],"responses":{"200":{"description":"Previous configuration restored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Experiment"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Experiment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"409":{"description":"No reversible promotion or concurrent configuration change","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/experiments/{experimentId}/report":{"get":{"tags":["experiments"],"summary":"Experiment report","description":"Per-variant metrics computed from events (`ingestEvents`) whose `session_id` equals the `X-NOVA-SESSION-ID` the variant was assigned to, within the experiment's running window: searches, clicks, add-to-carts, purchases, revenue, click-through and conversion rates.\n","operationId":"getExperimentReport","parameters":[{"name":"experimentId","in":"path","description":"The id of the experiment","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExperimentReport"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Experiment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/seo/rules":{"get":{"tags":["seo"],"summary":"List SEO rules","description":"Metatag rules for filter pages, newest first. Each rule renders one facet of a collection (`facet_field`) into metatags for every value of that facet. Paginated with `limit` and `offset`; `total` is the number of rules of the organization.\n","operationId":"listSeoRules","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"SEO rules","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoRulesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"post":{"tags":["seo"],"summary":"Create an SEO rule","description":"Creates a metatag rule for a collection's filter pages. The rule names the facet field whose values become pages (`facet_field`) and carries one template per metatag field. Templates use `#SECTION#` (collection), `#PROPERTY#` (the facet field), `#VALUE#` (the facet value), `#COUNT#` (how many documents carry the value) and `#SITE_NAME#` substitutions; an unknown placeholder is rejected rather than rendered literally onto live pages. At least one non-empty template is required.\n","operationId":"createSeoRule","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoRuleUpsertSchema"}}}},"responses":{"201":{"description":"Rule created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoRule"}}}},"400":{"description":"Invalid rule (no templates, unknown placeholder)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/seo/rules/{ruleId}":{"parameters":[{"name":"ruleId","in":"path","description":"The id of the SEO rule","required":true,"schema":{"type":"string"}}],"get":{"tags":["seo"],"summary":"Get an SEO rule","description":"Retrieves one metatag rule with its templates.","operationId":"getSeoRule","responses":{"200":{"description":"SEO rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoRule"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"put":{"tags":["seo"],"summary":"Update an SEO rule","description":"Replaces the editable fields of a rule. Send the complete configuration, as with `upsertSearchRule`: fields left out reset to their defaults. Changing templates does not rewrite already-generated pages — run `generateSeoPages` to re-render, or `auditSeoPages` to find the pages that went stale.\n","operationId":"updateSeoRule","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoRuleUpsertSchema"}}}},"responses":{"200":{"description":"Rule updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoRule"}}}},"400":{"description":"Invalid rule (no templates, unknown placeholder)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}},"delete":{"tags":["seo"],"summary":"Delete an SEO rule","description":"Deletes the rule. Already-generated pages are kept (they are materialized content) and `auditSeoPages` reports them as orphaned until they are regenerated from another rule or removed.\n","operationId":"deleteSeoRule","responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoRuleDeleteSchema"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Rule not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/seo/pages":{"get":{"tags":["seo"],"summary":"List generated SEO pages","description":"Filter pages materialized by `generateSeoPages`, newest first: url, title, robots directive and when the page was last rendered. Paginated with `limit` and `offset`; `collection` narrows the list to one collection.\n","operationId":"listSeoPages","parameters":[{"name":"collection","in":"query","description":"Only pages generated for this collection","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"Generated pages","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoPagesResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/seo/pages/generate":{"post":{"tags":["seo"],"summary":"Bulk-generate SEO pages for a collection","description":"Renders every active rule of the collection (or just the one `rule_id` names) against the live index: the engine's facet counts for the rule's `facet_field` supply one page per value, with `#COUNT#` set to the number of documents carrying it. Pages for values that already exist are re-rendered in place; the rest are created. The response is the generation report — list the pages themselves with `listSeoPages`.\n","operationId":"generateSeoPages","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoPageGenerateSchema"}}}},"responses":{"200":{"description":"Generation report","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoPageGenerateResponse"}}}},"400":{"description":"Invalid request or the engine rejected the facet query","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection has no active SEO rules, or rule_id names no rule","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/seo/pages/audit":{"post":{"tags":["seo"],"summary":"Audit generated SEO pages","description":"Re-checks the generated pages of the organization (or one `collection`) against their rules and returns per-page findings: an empty title or description, a rule that was deleted or deactivated, templates changed after the page was rendered (the page is stale), and the robots directive the page deserves. Findings are advisory — nothing is rewritten; run `generateSeoPages` to fix what the audit found.\n","operationId":"auditSeoPages","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoPageAuditSchema"}}}},"responses":{"200":{"description":"Per-page audit findings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoPageAuditResponse"}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/seo/pages/sitemap":{"get":{"tags":["seo"],"summary":"Export a sitemap of the generated SEO pages","description":"The active, indexable pages as an XML urlset. The contract is JSON-only, so the XML is returned as a string: store it at the sitemap URL your storefront serves and give it to the webmaster consoles. `collection` narrows the export to one collection.\n","operationId":"exportSeoSitemap","parameters":[{"name":"collection","in":"query","description":"Only pages generated for this collection","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Sitemap XML","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeoSitemapResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/collections/{collectionName}/reindex":{"parameters":[{"name":"collectionName","in":"path","description":"The name of the collection","required":true,"schema":{"type":"string"}}],"post":{"tags":["collections"],"summary":"Start a full reindex of a collection","description":"Queues a `reindex` ingest job: the queue consumer exports every document of the collection from the engine and imports it back (`action`, default `upsert`), so field mapping changes and re-embedding picked up on the way through. Poll `getIngestJob` until `status` is `ready` or `failed`, exactly like any other ingest job.\n","operationId":"reindexCollection","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CollectionReindexSchema"}}}},"responses":{"201":{"description":"Reindex job accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJob"}}}},"400":{"description":"Invalid action","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Collection not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/ingest-jobs/retry-failed":{"post":{"tags":["ingest"],"summary":"Retry every failed ingest job","description":"Re-queues every `failed` ingest job of the organization (newest first, up to 50) with its original config — the bulk form of `retryIngestJob`. Jobs that are `queued`, `processing` or `ready` are not touched. Returns how many were re-queued and the jobs themselves with `status: queued`.\n","operationId":"retryFailedIngestJobs","responses":{"200":{"description":"Failed jobs re-queued","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJobsRetryFailedResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/ingest-jobs/{jobId}/cancel":{"parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string"}}],"post":{"tags":["ingest"],"summary":"Cancel an ingest job","description":"Best-effort cancellation: the job is marked `failed` with `error: \"Canceled by request\"` and the queue consumer skips it on its next pickup. A job that is already `processing` may still finish its current pass — a running Worker cannot be interrupted — in which case its own result stands. Jobs that are `ready` or `failed` cannot be canceled.\n","operationId":"cancelIngestJob","responses":{"200":{"description":"Job canceled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestJob"}}}},"400":{"description":"Job is not in a cancelable state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"429":{"$ref":"#/components/responses/TooManyRequests"}}}},"/analytics/events/batch":{"post":{"tags":["analytics"],"summary":"Ingest a batch of storefront search events","description":"Records up to 20 storefront search events per call — the search / click / conversion subset of `POST /events` with a small fixed shape, sized and keyed for untrusted browser clients (`x-nova-key-scope: search`). Events land in the same behavioural event store, so they are visible to insights and rollups like any other event. A `search` event needs `query`; `click` and `conversion` need `document_id`. Use the server-side `POST /events` for revenue events, larger batches and idempotency keys.\n","operationId":"ingestAnalyticsEvents","x-nova-key-scope":"search","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontEventBatch"}}}},"responses":{"202":{"description":"Batch accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorefrontEventsAccepted"}}}},"400":{"description":"Malformed batch","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/TooManyRequests"}}}}},"components":{"schemas":{"CmsCommandCreate":{"type":"object","additionalProperties":false,"required":["kind","idempotency_key"],"properties":{"kind":{"type":"string","enum":["reindex","resync","refresh_capabilities"]},"idempotency_key":{"type":"string","minLength":1,"maxLength":128},"store_id":{"type":"string","minLength":1,"maxLength":120},"source_id":{"type":"string","minLength":1,"maxLength":120}}},"CmsCommand":{"type":"object","additionalProperties":false,"required":["id","installation_id","kind","store_id","source_id","status","progress","attempts","lease_expires_at","error","created_at","updated_at"],"properties":{"id":{"type":"string","minLength":1,"maxLength":120},"installation_id":{"type":"string","minLength":1,"maxLength":120},"kind":{"type":"string","enum":["reindex","resync","refresh_capabilities"]},"store_id":{"type":"string","nullable":true},"source_id":{"type":"string","nullable":true},"status":{"type":"string","enum":["queued","running","completed","failed","cancelled"]},"progress":{"type":"integer","minimum":0,"maximum":100},"attempts":{"type":"integer","minimum":0},"lease_expires_at":{"type":"integer","nullable":true},"error":{"type":"string","nullable":true},"created_at":{"type":"integer"},"updated_at":{"type":"integer"}}},"CmsCommandsResponse":{"type":"object","additionalProperties":false,"required":["commands"],"properties":{"commands":{"type":"array","items":{"$ref":"#/components/schemas/CmsCommand"}}}},"CmsCommandClaim":{"type":"object","additionalProperties":false,"required":["command","lease_token"],"properties":{"command":{"type":"object","nullable":true,"allOf":[{"$ref":"#/components/schemas/CmsCommand"}]},"lease_token":{"type":"string","nullable":true}}},"CmsCommandProgress":{"type":"object","additionalProperties":false,"required":["lease_token","status","progress"],"properties":{"lease_token":{"type":"string","minLength":1,"maxLength":128},"status":{"type":"string","enum":["running","completed","failed"]},"progress":{"type":"integer","minimum":0,"maximum":100},"error":{"type":"string","nullable":true,"maxLength":1000}}},"CmsRuntimeSearch":{"description":"Standard search parameters. Collection and preset are bound by Console, never selected by the module.","allOf":[{"$ref":"#/components/schemas/SearchParameters"}]},"CmsRuntimeRecommendations":{"type":"object","additionalProperties":false,"properties":{"filter_by":{"type":"string","maxLength":4000,"description":"Stock, access and other storefront constraints, combined with the configured model filter."},"include_fields":{"type":"string","maxLength":1000},"exclude_fields":{"type":"string","maxLength":1000},"query":{"type":"string","maxLength":1000},"object_ids":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":256}},"exclude_ids":{"type":"array","maxItems":100,"items":{"type":"string","maxLength":256}},"object_id":{"type":"string","maxLength":256},"user_id":{"type":"string","maxLength":256},"anonymous_id":{"type":"string","maxLength":256},"session_id":{"type":"string","maxLength":256},"k":{"type":"integer","minimum":1,"maximum":100}}},"CmsSourceBinding":{"type":"object","additionalProperties":false,"required":["local_id","connector_id","collection"],"properties":{"local_id":{"type":"string","minLength":1,"maxLength":120},"connector_id":{"type":"string","minLength":1,"maxLength":120},"collection":{"type":"string","minLength":1,"maxLength":120},"search_preset":{"type":"string","nullable":true},"recommendation_model":{"type":"string","nullable":true}}},"CmsStoreConfig":{"type":"object","additionalProperties":false,"required":["local_id","locale","currency","native_search","native_filters","native_recommendations","widgets_enabled","sources"],"properties":{"local_id":{"type":"string","minLength":1,"maxLength":120},"locale":{"type":"string","minLength":1,"maxLength":35},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"native_search":{"type":"boolean"},"native_filters":{"type":"boolean"},"native_recommendations":{"type":"boolean"},"widgets_enabled":{"type":"boolean"},"sources":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/CmsSourceBinding"}}}},"CmsConfig":{"type":"object","additionalProperties":false,"required":["protocol_version","stores"],"properties":{"protocol_version":{"type":"integer","enum":[1]},"stores":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/CmsStoreConfig"}}}},"CmsDiscoveredStore":{"type":"object","additionalProperties":false,"required":["local_id","name","source_ids"],"properties":{"source_schemas":{"type":"object","description":"Collection schema for each local source, keyed by source_ids. Never include secrets.","additionalProperties":{"$ref":"#/components/schemas/CollectionSchema"}},"locale":{"type":"string","maxLength":35,"description":"Actual storefront language or locale reported by the CMS."},"currency":{"type":"string","pattern":"^[A-Z]{3}$","description":"Actual default currency of this store."},"local_id":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","minLength":1,"maxLength":120},"source_ids":{"type":"array","maxItems":100,"items":{"type":"string","minLength":1,"maxLength":120}}}},"CmsDiscovery":{"type":"object","additionalProperties":false,"required":["module_version","cms_version","capabilities","stores"],"properties":{"module_version":{"type":"string","minLength":1,"maxLength":64},"cms_version":{"type":"string","minLength":1,"maxLength":64},"capabilities":{"type":"array","maxItems":6,"items":{"type":"string","enum":["native_search","native_filters","native_recommendations","widgets","push","pull"]}},"stores":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/CmsDiscoveredStore"}}}},"CmsInstallationCreate":{"type":"object","additionalProperties":false,"required":["name","provider","environment","origin"],"properties":{"name":{"type":"string","minLength":1,"maxLength":120},"provider":{"type":"string","enum":["bitrix","prestashop","woocommerce","zencart","custom"]},"environment":{"type":"string","enum":["production","staging"]},"origin":{"type":"string","format":"uri","maxLength":512}}},"CmsConfigUpdate":{"type":"object","additionalProperties":false,"required":["expected_revision","config"],"properties":{"expected_revision":{"type":"integer","minimum":0},"config":{"$ref":"#/components/schemas/CmsConfig"}}},"CmsSyncHealth":{"type":"object","additionalProperties":false,"description":"Live sync telemetry from a CMS connector outbox (Bitrix/PrestaShop agents) or mirrored from platform ConnectorJob stats for feed/YML sources. Optional on heartbeat; stored on the installation and shown in Console Sources / CMS.\n","properties":{"pending":{"type":"integer","minimum":0,"description":"Jobs waiting in the local CMS outbox (or platform queue depth)."},"failed":{"type":"integer","minimum":0},"processing":{"type":"integer","minimum":0},"done_1h":{"type":"integer","minimum":0,"description":"Successfully completed jobs in the last hour."},"throughput_per_min":{"type":"number","minimum":0,"description":"Recent completion rate (jobs per minute)."},"eta_seconds":{"type":"integer","minimum":0,"nullable":true,"description":"Estimated seconds to drain pending at current throughput; null when unknown."},"catalog_size":{"type":"string","enum":["empty","small","medium","large","xlarge"],"description":"Auto-detected catalog size band used for batch sizing."},"auto_profile":{"type":"string","maxLength":64,"description":"Active auto-tune profile id (e.g. medium_commerce, xlarge_start)."},"batch_size":{"type":"integer","minimum":1,"maximum":500},"workers":{"type":"integer","minimum":1,"maximum":32},"reindex_active":{"type":"boolean","description":"True while a full catalog reindex seed/drain is in progress."},"last_error":{"type":"string","maxLength":2000,"nullable":true},"reported_at":{"type":"integer","minimum":0,"description":"Unix seconds when the connector sampled this snapshot."}}},"CmsHeartbeat":{"type":"object","additionalProperties":false,"required":["origin","protocol_version","applied_revision","discovery"],"properties":{"origin":{"type":"string","format":"uri","maxLength":512},"protocol_version":{"type":"integer","enum":[1]},"applied_revision":{"type":"integer","minimum":0},"error":{"type":"string","nullable":true,"maxLength":1000},"discovery":{"$ref":"#/components/schemas/CmsDiscovery"},"sync_health":{"$ref":"#/components/schemas/CmsSyncHealth"}}},"CmsInstallation":{"type":"object","additionalProperties":false,"required":["id","name","provider","environment","origin","desired_revision","applied_revision","config","discovery","sync_health","last_error","last_seen_at","revoked_at","created_at","updated_at"],"properties":{"id":{"type":"string","minLength":1,"maxLength":120},"name":{"type":"string","minLength":1,"maxLength":120},"provider":{"type":"string","minLength":1,"maxLength":120},"environment":{"type":"string","minLength":1,"maxLength":120},"origin":{"type":"string","minLength":1,"maxLength":512},"desired_revision":{"type":"integer","minimum":0},"applied_revision":{"type":"integer","minimum":0},"config":{"$ref":"#/components/schemas/CmsConfig"},"discovery":{"type":"object","nullable":true,"allOf":[{"$ref":"#/components/schemas/CmsDiscovery"}]},"sync_health":{"type":"object","nullable":true,"allOf":[{"$ref":"#/components/schemas/CmsSyncHealth"}],"description":"Latest connector outbox / auto-tune snapshot from heartbeat."},"last_error":{"type":"string","nullable":true},"last_seen_at":{"type":"integer","nullable":true},"revoked_at":{"type":"integer","nullable":true},"created_at":{"type":"integer","minimum":0},"updated_at":{"type":"integer","minimum":0}}},"CmsInstallationCreated":{"type":"object","additionalProperties":false,"required":["installation","installation_key"],"properties":{"installation":{"$ref":"#/components/schemas/CmsInstallation"},"installation_key":{"type":"string","minLength":1,"maxLength":128}}},"CmsInstallationsResponse":{"type":"object","additionalProperties":false,"required":["installations"],"properties":{"installations":{"type":"array","maxItems":1000,"items":{"$ref":"#/components/schemas/CmsInstallation"}}}},"CmsRuntime":{"type":"object","additionalProperties":false,"required":["installation","protocol_version"],"properties":{"installation":{"$ref":"#/components/schemas/CmsInstallation"},"protocol_version":{"type":"integer","enum":[1]}}},"CmsRevoked":{"type":"object","additionalProperties":false,"required":["id","revoked"],"properties":{"id":{"type":"string","minLength":1,"maxLength":120},"revoked":{"type":"boolean"}}},"CollectionSchema":{"required":["name","fields"],"type":"object","properties":{"name":{"type":"string","description":"Name of the collection","example":"companies"},"fields":{"type":"array","description":"A list of fields for querying, filtering and faceting","example":[{"name":"num_employees","type":"int32","facet":false},{"name":"company_name","type":"string","facet":false},{"name":"country","type":"string","facet":true}],"items":{"$ref":"#/components/schemas/Field"}},"default_sorting_field":{"type":"string","description":"The name of an int32 / float field that determines the order in which the search results are ranked when a sort_by clause is not provided during searching. This field must indicate some kind of popularity.","example":"num_employees","default":""},"token_separators":{"type":"array","description":"List of symbols or special characters to be used for splitting the text into individual words in addition to space and new-line characters.\n","items":{"type":"string","minLength":1,"maxLength":1},"default":[]},"curation_sets":{"type":"array","description":"List of curation set names to associate with this collection","items":{"type":"string","example":"curation_set_1"}},"synonym_sets":{"type":"array","description":"List of synonym set names to associate with this collection","items":{"type":"string","example":"synonym_set_1"}},"enable_nested_fields":{"type":"boolean","description":"Enables experimental support at a collection level for nested object or object array fields. This field is only available if the AACSearch node is version `0.24.0.rcn34` or later.","default":false,"example":true},"symbols_to_index":{"type":"array","description":"List of symbols or special characters to be indexed.\n","items":{"type":"string","minLength":1,"maxLength":1},"default":[]},"voice_query_model":{"$ref":"#/components/schemas/VoiceQueryModelCollectionConfig"},"metadata":{"type":"object","description":"Optional details about the collection, e.g., when it was created, who created it etc.\n"}}},"CollectionUpdateSchema":{"type":"object","minProperties":1,"properties":{"fields":{"type":"array","description":"A list of fields for querying, filtering and faceting","example":[{"name":"company_name","type":"string","facet":false},{"name":"num_employees","type":"int32","facet":false},{"name":"country","type":"string","facet":true}],"items":{"$ref":"#/components/schemas/Field"}},"curation_sets":{"type":"array","description":"List of curation set names to associate with this collection","items":{"type":"string","example":"curation_set_1"}},"synonym_sets":{"type":"array","description":"List of synonym set names to associate with this collection","items":{"type":"string","example":"synonym_set_1"}},"metadata":{"type":"object","description":"Optional details about the collection, e.g., when it was created, who created it etc.\n"}}},"CollectionResponse":{"allOf":[{"$ref":"#/components/schemas/CollectionSchema"},{"type":"object","required":["num_documents","created_at"],"properties":{"num_documents":{"type":"integer","description":"Number of documents in the collection","format":"int64","readOnly":true},"created_at":{"type":"integer","description":"Timestamp of when the collection was created (Unix epoch in seconds)","x-fern-type":"long","readOnly":true}}}]},"Field":{"required":["name","type"],"type":"object","properties":{"name":{"type":"string","example":"company_name"},"type":{"type":"string","description":"Field data type. Scalar types: `string`, `int32`, `int64`, `float`, `bool`, `geopoint`, `object`; array variants add `[]` (for example `string[]`, `float[]`). `float[]` with `num_dim` is a vector field (set `embed` for auto-embedding). `image` holds a base64 encoded BMP/JPG/PNG used as an `embed.from` source (combine with `store: false` to keep the embedding but drop the bytes). `string*` indexes a string or string array, `auto` infers the type from the first document.\n","enum":["string","string[]","int32","int32[]","int64","int64[]","float","float[]","bool","bool[]","geopoint","geopoint[]","object","object[]","string*","image","auto"],"example":"string"},"optional":{"type":"boolean","example":true},"facet":{"type":"boolean","example":false},"index":{"type":"boolean","example":true,"default":true},"locale":{"type":"string","example":"el"},"sort":{"type":"boolean","example":true},"infix":{"type":"boolean","example":true,"default":false},"reference":{"type":"string","description":"Name of a field in another collection that should be linked to this collection so that it can be joined during query.\n"},"async_reference":{"type":"boolean","description":"Allow documents to be indexed successfully even when the referenced document doesn't exist yet.\n"},"num_dim":{"type":"integer","example":256},"drop":{"type":"boolean","example":true},"store":{"type":"boolean","description":"When set to false, the field value will not be stored on disk. Default: true.\n"},"vec_dist":{"type":"string","description":"The distance metric to be used for vector search. Default: `cosine`. You can also use `ip` for inner product.\n"},"range_index":{"type":"boolean","description":"Enables an index optimized for range filtering on numerical fields (e.g. rating:>3.5). Default: false.\n"},"stem":{"type":"boolean","description":"Values are stemmed before indexing in-memory. Default: false.\n"},"stem_dictionary":{"type":"string","description":"Name of the stemming dictionary to use for this field","example":"irregular-plurals"},"token_separators":{"type":"array","description":"List of symbols or special characters to be used for splitting the text into individual words in addition to space and new-line characters.\n","items":{"type":"string","minLength":1,"maxLength":1},"default":[]},"symbols_to_index":{"type":"array","description":"List of symbols or special characters to be indexed.\n","items":{"type":"string","minLength":1,"maxLength":1},"default":[]},"embed":{"type":"object","required":["from","model_config"],"properties":{"from":{"type":"array","items":{"type":"string"}},"model_config":{"type":"object","required":["model_name"],"properties":{"model_name":{"type":"string"},"api_key":{"type":"string"},"url":{"type":"string"},"access_token":{"type":"string"},"refresh_token":{"type":"string"},"client_id":{"type":"string"},"client_secret":{"type":"string"},"project_id":{"type":"string"},"indexing_prefix":{"type":"string"},"query_prefix":{"type":"string"}}}}}}},"VoiceQueryModelCollectionConfig":{"type":"object","description":"Configuration for the voice query model\n","properties":{"model_name":{"type":"string","description":"Built-in speech-to-text model used to transcribe `voice_query`. Only `ts/whisper/base.en` is available in the engine: English only, runs on GPU when the node has one.\n","example":"ts/whisper/base.en"}}},"CollectionAliasSchema":{"type":"object","required":["collection_name"],"properties":{"collection_name":{"type":"string","description":"Name of the collection you wish to map the alias to"}}},"CollectionAlias":{"type":"object","required":["collection_name","name"],"properties":{"name":{"type":"string","readOnly":true,"description":"Name of the collection alias"},"collection_name":{"type":"string","description":"Name of the collection the alias mapped to"}}},"CollectionAliasesResponse":{"type":"object","required":["aliases"],"properties":{"aliases":{"type":"array","x-go-type":"[]*CollectionAlias","items":{"$ref":"#/components/schemas/CollectionAlias"}}}},"SearchResult":{"type":"object","properties":{"_trace":{"type":"object","description":"AACSearch extension, debug requests only (`debug=true` / `X-NOVA-DEBUG: 1`). The request trace: `id` (the `X-Nova-Trace-Id`), `timings` per stage in ms, `rule` (which search-rule fields applied: exclusion filter, compiled boost clause, pins matched, redirect, banners, suggestions, diversity drops), `experiments`, `rewrite` (strategies attempted and applied), `fallback`, `engine` (status, `search_time_ms`, `found`) and the top `hitIds`.\n","additionalProperties":true},"facet_counts":{"type":"array","items":{"$ref":"#/components/schemas/FacetCounts"}},"found":{"type":"integer","description":"The number of documents found"},"found_docs":{"type":"integer"},"search_time_ms":{"type":"integer","description":"The number of milliseconds the search took"},"out_of":{"type":"integer","description":"The total number of documents in the collection"},"search_cutoff":{"type":"boolean","description":"Whether the search was cut off"},"page":{"type":"integer","description":"The search result page number"},"grouped_hits":{"type":"array","items":{"$ref":"#/components/schemas/SearchGroupedHit"}},"hits":{"type":"array","description":"The documents that matched the search query","items":{"$ref":"#/components/schemas/SearchResultHit"}},"request_params":{"$ref":"#/components/schemas/SearchRequestParams"},"conversation":{"$ref":"#/components/schemas/SearchResultConversation"},"union_request_params":{"type":"array","description":"Returned only for union query response.","items":{"$ref":"#/components/schemas/SearchRequestParams"}},"metadata":{"type":"object","description":"Custom JSON object that can be returned in the search response","additionalProperties":true},"parsed_nl_query":{"$ref":"#/components/schemas/ParsedNLQuery"},"query_rewrite":{"$ref":"#/components/schemas/QueryRewrite"},"rerank":{"$ref":"#/components/schemas/SearchRerank"},"redirect":{"$ref":"#/components/schemas/SearchRedirect"},"suggestions":{"type":"array","description":"AACSearch extension. Refinements for `q` from the collection's search rules — manual entries and top facet values; absent when there are none.\n","items":{"$ref":"#/components/schemas/SearchSuggestion"}},"query_understanding":{"$ref":"#/components/schemas/QueryUnderstanding"},"correction":{"$ref":"#/components/schemas/QueryCorrection"},"refinements":{"type":"array","description":"AACSearch extension. Post-search refinement chips (facet values, ranges, query refinements, requirement chips) ranked by expected usefulness and diversified across dimensions; absent when `refinements=off` or nothing scored. Report clicks as `chip_click` events with `metadata.refinement_id`.\n","items":{"$ref":"#/components/schemas/Refinement"}}}},"QueryUnderstanding":{"type":"object","description":"AACSearch extension. How the platform read `q` before searching: intent, protected identifier tokens, linked catalogue entities, extracted constraints and the search policy that was applied. Cheap, always present on `searchCollection` responses.\n","required":["intent","strategy","policy","protected_tokens"],"properties":{"intent":{"type":"string","enum":["navigational","transactional","informational","browse"]},"relation":{"type":"string","enum":["SUBSTITUTE","COMPATIBLE_WITH","COMPLEMENT"],"description":"Relationship intent detected (`вместо X`, `для X`, `к X`), when any."},"strategy":{"type":"string","description":"The retrieval strategy the policy selected (`EXACT_IDENTIFIER`, `FUZZY_LEXICAL`, `HYBRID`, …)."},"policy":{"type":"string","description":"Name of the search policy that matched."},"search_text":{"type":"string","description":"The text actually searched after constraints and negations were lifted out of `q`."},"protected_tokens":{"type":"array","description":"Tokens treated as exact identifiers (SKU, MPN, EAN, model codes) — never corrected or dropped.","items":{"type":"string"}},"entities":{"type":"array","items":{"$ref":"#/components/schemas/LinkedEntity"}},"constraints":{"type":"array","items":{"$ref":"#/components/schemas/QueryConstraint"}},"confidence":{"type":"number","description":"0..1 — how confidently the query was understood."}}},"LinkedEntity":{"type":"object","required":["entity_id","type","canonical"],"properties":{"entity_id":{"type":"string"},"type":{"type":"string","enum":["brand","category","product_type","model","series","attribute"]},"canonical":{"type":"string"},"alias":{"type":"string","description":"The alias in `q` that matched."},"confidence":{"type":"number"}}},"QueryConstraint":{"type":"object","required":["kind","op","hardness","text"],"properties":{"kind":{"type":"string","description":"`price`, `storage`, `memory`, `length`, `weight`, `volume`, `power`, `screen`, `quantity`, `brand`, `color` or `generic`."},"op":{"type":"string","enum":["eq","neq","lte","gte","between","in","not_in"]},"value":{"description":"Canonical value (number in the canonical unit, string, list, or `[min, max]`)."},"unit":{"type":"string"},"currency":{"type":"string"},"hardness":{"type":"string","enum":["hard","soft","negative"]},"text":{"type":"string","description":"The span of `q` the constraint came from."},"filter_by":{"type":"string","description":"The engine filter applied for it, when the policy maps the constraint kind to a field."}}},"QueryCorrection":{"type":"object","description":"AACSearch extension. Outcome of the correction state machine. `AUTO_CORRECT` means the results are for `applied.q` (also reported in `query_rewrite`); `SUGGEST_CORRECTION` means the results are for the original `q` and `suggestions` are worth offering (\"did you mean\"); `PROTECTED` means the query is an identifier and no correction was attempted; `AMBIGUOUS` means several readings scored alike.\n","required":["state"],"properties":{"state":{"type":"string","enum":["NO_CORRECTION","SUGGEST_CORRECTION","AUTO_CORRECT","AMBIGUOUS","PROTECTED"]},"applied":{"$ref":"#/components/schemas/QueryHypothesis"},"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/QueryHypothesis"}},"reason":{"type":"string"}}},"QueryHypothesis":{"type":"object","required":["q","type","score"],"properties":{"q":{"type":"string"},"type":{"type":"string","enum":["RAW","KEYBOARD_LAYOUT","TYPO","SPLIT_JOIN","TRANSLITERATION","HOMOGLYPH","ALIAS","SYNONYM","TOKEN_DROP","REWRITE","SEMANTIC"]},"score":{"type":"number"},"found":{"type":"integer","description":"Documents the hypothesis found when probed."}}},"Refinement":{"type":"object","required":["id","type","label","score"],"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["facet","range","query","requirement","intent","discovery"]},"label":{"type":"string"},"query":{"type":"string","description":"For `query`/`intent` chips, the query to run."},"filter_by":{"type":"string","description":"For `facet`/`range`/`requirement` chips, the filter to add to the current search."},"field":{"type":"string"},"value":{"type":"string"},"count":{"type":"integer"},"score":{"type":"number"},"dimension":{"type":"string","description":"The facet field or `query`/`intent` — chips are diversified per dimension."}}},"SuggestResponse":{"type":"object","required":["suggest_id","q","suggestions","took_ms"],"properties":{"suggest_id":{"type":"string","description":"Id of this suggestion list; send it as `query_id` on `suggestion_select` events."},"q":{"type":"string","description":"The prefix as received."},"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/Suggestion"}},"took_ms":{"type":"integer"}}},"Suggestion":{"type":"object","required":["id","text","source","position","score"],"properties":{"id":{"type":"string"},"text":{"type":"string","description":"The query to run when chosen."},"display":{"type":"string","description":"Label to render when different from `text` (product title, brand label)."},"source":{"type":"string","enum":["query","product","brand","category","entity","graph","rule","recent","trending"]},"position":{"type":"integer","description":"0-based position in the list, for the selection event."},"score":{"type":"number"},"filter_by":{"type":"string","description":"Filter to apply instead of (or with) the text, for entity/category suggestions."},"doc_id":{"type":"string","description":"The document, for product suggestions."},"found":{"type":"integer","description":"Known result count of the suggested query, when available."}}},"PresearchResponse":{"type":"object","required":["presearch_id","sections","took_ms"],"properties":{"presearch_id":{"type":"string","description":"Id of this list; send it as `query_id` on `suggestion_select` events."},"sections":{"type":"array","items":{"$ref":"#/components/schemas/PresearchSection"}},"took_ms":{"type":"integer"}}},"PresearchSection":{"type":"object","required":["type","title","items"],"properties":{"type":{"type":"string","enum":["recent","contextual","trending","popular"]},"title":{"type":"string"},"items":{"type":"array","items":{"$ref":"#/components/schemas/Suggestion"}}}},"SearchRerank":{"type":"object","description":"AACSearch extension. Present when the collection's search rules (or the request's `rerank` parameter) asked for reranking: what ran, over how many hits, and how long it took — or why it was skipped.\n","required":["applied","model"],"properties":{"applied":{"type":"boolean"},"model":{"type":"string","enum":["bge-reranker-base","llm"]},"scored":{"type":"integer","description":"How many leading hits the model scored."},"ms":{"type":"integer","description":"Wall time of the model call."},"skipped":{"type":"string","description":"Why nothing was reranked (`timeout`, `error`, `credits`, `too_few_hits`, `no_query`)."}}},"SearchRedirect":{"type":"object","description":"AACSearch extension. Present when `q` matched a redirect in the collection's search rules. The hits are still returned; a storefront should navigate to `url` instead of rendering them.\n","required":["url","query"],"properties":{"url":{"type":"string"},"query":{"type":"string","description":"The rule's query pattern that matched."}}},"SearchSuggestion":{"type":"object","required":["query","source"],"properties":{"query":{"type":"string","description":"Suggested query text, e.g. \"phone Apple\"."},"source":{"type":"string","enum":["manual","facet"]},"filter_by":{"type":"string","description":"For `facet` suggestions, the filter selecting that value (`brand:=Apple`) — send it with the original `q` instead of searching the longer text.\n"},"facet":{"type":"object","required":["field","value","count"],"properties":{"field":{"type":"string"},"value":{"type":"string"},"count":{"type":"integer"}}}}},"QueryRewrite":{"type":"object","description":"AACSearch extension. Present only when the original `q` found nothing and one of the rewrites selected by the `query_rewrite` search parameter did; `hits`, `found` and `request_params` then describe the search for the rewritten `q`. Use it for a \"showing results for … instead\" message.\n","required":["strategy","original_q","q"],"properties":{"strategy":{"type":"string","enum":["layout","translit","homoglyph","split_join","alias","token_drop"],"description":"Which rewrite produced the results. `split_join` re-spaced tokens (`rtx 5090` ↔ `rtx5090`), `alias` replaced a linked entity alias with its canonical label, `token_drop` dropped low-value segments (modifiers, colour) keeping identifiers and models.\n"},"original_q":{"type":"string","description":"The query as the caller sent it"},"q":{"type":"string","description":"The query that was actually searched"}}},"ParsedNLQuery":{"type":"object","description":"Returned when `nl_query` is enabled. Shows how the natural language model translated the query into search parameters.\n","properties":{"parse_time_ms":{"type":"integer","description":"Time spent in the natural language model, in milliseconds"},"generated_params":{"type":"object","description":"Parameters produced by the model (`q`, `filter_by`, `sort_by`)","additionalProperties":true},"augmented_params":{"type":"object","description":"Final parameters used for the search after merging generated params with the request","additionalProperties":true},"llm_response":{"type":"object","description":"Raw model response; only present when `nl_query_debug` is true","additionalProperties":true}}},"SearchRequestParams":{"type":"object","required":["collection_name","q","per_page"],"properties":{"collection_name":{"type":"string"},"first_q":{"type":"string"},"q":{"type":"string"},"per_page":{"type":"integer"},"voice_query":{"type":"object","properties":{"transcribed_query":{"type":"string"}}}}},"SearchResultConversation":{"type":"object","required":["answer","conversation_history","conversation_id","query"],"properties":{"answer":{"type":"string"},"conversation_history":{"type":"array","items":{"type":"object"}},"conversation_id":{"type":"string"},"query":{"type":"string"}}},"SearchGroupedHit":{"type":"object","required":["group_key","hits"],"properties":{"found":{"type":"integer"},"group_key":{"type":"array","items":{}},"hits":{"type":"array","description":"The documents that matched the search query","items":{"$ref":"#/components/schemas/SearchResultHit"}}}},"SearchResultHit":{"type":"object","properties":{"_explain":{"type":"object","description":"AACSearch extension, debug requests only. The engine's scoring signals for this hit (`text_match`, `text_match_info`, `vector_distance`, `hybrid_search_info`, `geo_distance_meters`) and `boosts` — each configured search-rule boost with whether this document matched its filter (`true`, `false`, or `\"unknown\"` for filters too complex to evaluate here).\n","additionalProperties":true},"rerank_score":{"type":"number","format":"float","description":"AACSearch extension. Relevance of the hit as judged by the reranker (see `SearchRuleRerank`); present only on hits the reranker scored.\n"},"highlights":{"type":"array","description":"(Deprecated) Contains highlighted portions of the search fields","items":{"$ref":"#/components/schemas/SearchHighlight"}},"highlight":{"type":"object","description":"Highlighted version of the matching document","additionalProperties":true},"document":{"type":"object","description":"The matching document; field values are whatever the collection schema defines","additionalProperties":true},"text_match":{"type":"integer","format":"int64"},"text_match_info":{"type":"object","properties":{"best_field_score":{"type":"string"},"best_field_weight":{"type":"integer"},"fields_matched":{"type":"integer"},"num_tokens_dropped":{"type":"integer","format":"int64","x-go-type":"uint64"},"score":{"type":"string"},"tokens_matched":{"type":"integer"},"typo_prefix_score":{"type":"integer"}}},"geo_distance_meters":{"type":"object","description":"Can be any key-value pair","additionalProperties":{"type":"integer"}},"vector_distance":{"type":"number","format":"float","description":"Distance between the query vector and matching document's vector value"},"hybrid_search_info":{"type":"object","description":"Information about hybrid search scoring","properties":{"rank_fusion_score":{"type":"number","format":"float","description":"Combined score from rank fusion of text and vector search"}}},"search_index":{"type":"integer","description":"Returned only for union query response. Indicates the index of the query which this document matched to."}},"example":{"highlights":[{"field":"company_name","snippet":"<mark>Stark</mark> Industries"}],"document":{"id":"124","company_name":"Stark Industries","num_employees":5215,"country":"USA"},"text_match":1234556}},"SearchHighlight":{"type":"object","properties":{"field":{"type":"string","example":"company_name"},"snippet":{"type":"string","description":"Present only for (non-array) string fields","example":"<mark>Stark</mark> Industries"},"snippets":{"type":"array","description":"Present only for (array) string[] fields","example":["<mark>Stark</mark> Industries","<mark>Stark</mark> Corp"],"items":{"type":"string"}},"value":{"type":"string","description":"Full field value with highlighting, present only for (non-array) string fields","example":"<mark>Stark</mark> Industries is a major supplier of space equipment."},"values":{"type":"array","description":"Full field value with highlighting, present only for (array) string[] fields","example":["<mark>Stark</mark> Industries","<mark>Stark</mark> Corp"],"items":{"type":"string"}},"indices":{"type":"array","description":"The indices property will be present only for string[] fields and will contain the corresponding indices of the snippets in the search field","example":[1],"items":{"type":"integer"}},"matched_tokens":{"type":"array","description":"Query tokens that matched in this field: strings for a string field, arrays of strings (one per element) for a string[] field.\n","items":{"x-go-type":"interface{}"}}}},"SearchSynonymSchema":{"type":"object","required":["synonyms"],"properties":{"root":{"type":"string","description":"For 1-way synonyms, indicates the root word that words in the `synonyms` parameter map to."},"synonyms":{"type":"array","description":"Array of words that should be considered as synonyms.","items":{"type":"string"}},"locale":{"type":"string","description":"Locale for the synonym, leave blank to use the standard tokenizer."},"symbols_to_index":{"type":"array","description":"By default, special characters are dropped from synonyms. Use this attribute to specify which special characters should be indexed as is.","items":{"type":"string"}}}},"SearchSynonym":{"allOf":[{"$ref":"#/components/schemas/SearchSynonymSchema"},{"type":"object","required":["id"],"properties":{"id":{"type":"string","readOnly":true}}}]},"SearchSynonymDeleteResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"The id of the synonym that was deleted"}}},"SearchSynonymsResponse":{"type":"object","required":["synonyms"],"properties":{"synonyms":{"type":"array","x-go-type":"[]*SearchSynonym","items":{"$ref":"#/components/schemas/SearchSynonym"}}}},"HealthStatus":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}},"SchemaChangeStatus":{"type":"object","properties":{"collection":{"type":"string","description":"Name of the collection being modified"},"validated_docs":{"type":"integer","description":"Number of documents that have been validated"},"altered_docs":{"type":"integer","description":"Number of documents that have been altered"}}},"SuccessStatus":{"type":"object","required":["success"],"properties":{"success":{"type":"boolean"}}},"ApiResponse":{"type":"object","required":["message"],"properties":{"message":{"type":"string"}}},"ApiKeySchema":{"type":"object","required":["actions","collections","description"],"properties":{"value":{"type":"string"},"description":{"type":"string"},"actions":{"type":"array","items":{"type":"string"}},"collections":{"type":"array","items":{"type":"string"}},"expires_at":{"type":"integer","x-fern-type":"long"}}},"ApiKey":{"allOf":[{"$ref":"#/components/schemas/ApiKeySchema"},{"type":"object","properties":{"id":{"type":"integer","format":"int64","readOnly":true},"value_prefix":{"type":"string","readOnly":true}}}]},"ApiKeyDeleteResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"integer","format":"int64","description":"The id of the API key that was deleted"}}},"ApiKeysResponse":{"type":"object","required":["keys"],"properties":{"keys":{"type":"array","x-go-type":"[]*ApiKey","items":{"$ref":"#/components/schemas/ApiKey"}}}},"MultiSearchResult":{"type":"object","required":["results"],"properties":{"results":{"type":"array","items":{"$ref":"#/components/schemas/MultiSearchResultItem"}},"conversation":{"$ref":"#/components/schemas/SearchResultConversation"}}},"MultiSearchResultItem":{"allOf":[{"$ref":"#/components/schemas/SearchResult"},{"type":"object","properties":{"code":{"type":"integer","description":"HTTP error code","x-fern-type":"long"},"error":{"type":"string","description":"Error description"}}}]},"SearchParameters":{"type":"object","properties":{"q":{"description":"The query text to search for in the collection. Use * as the search string to return all documents. This is typically useful when used in conjunction with filter_by.","type":"string"},"query_rewrite":{"description":"AACSearch extension. When the search returns 0 hits, `q` is retried with these rewrites, in the given order, and the first one that finds documents is returned together with a `query_rewrite` object describing what was applied. `layout` re-types text entered on the wrong keyboard layout (`,typjgbkf` → `бензопила`, `2ч16пи` → `2x16gb`); `translit` transliterates between Cyrillic and Latin (`девольт` → `devolt`, `samsung` → `самсунг`); `homoglyph` folds look-alike letters in mixed-script tokens such as article numbers (`RD-С80ТL` → `RD-C80TL`). Comma-separated. Default `layout,translit,homoglyph`; `off` disables the retry.\n","type":"string","example":"layout,translit"},"refinements":{"description":"AACSearch extension. Post-search refinement chips returned as `refinements`: `facets` (default, from the response's facet counts, ranked by information gain and availability), `full` (also query refinements from the query graph and requirement chips from the parsed constraints; one extra lookup), or `off`.\n","type":"string","enum":["off","facets","full"]},"search_policy":{"description":"AACSearch extension. Name of a search policy to apply instead of the one the query's frame matches — for debugging and A/B experiments (a variant's `search_params` may set it).\n","type":"string"},"x_user_id":{"description":"AACSearch extension. The signed-in visitor's id (your own stable id) for personalization: when the collection has personalization enabled, the visitor's affinity profile (built from `POST /events`) becomes `_eval` boosts in front of `sort_by`, and personalization rules matching their segments fire. Alternative to the `x-nova-user-id` header. Never forwarded to the engine.\n","type":"string"},"x_anonymous_id":{"description":"AACSearch extension. The anonymous visitor's id (cookie/device id) for personalization, used when `x_user_id` is absent. Alternative to the `x-nova-anonymous-id` header.\n","type":"string"},"x_personalization_strength":{"description":"AACSearch extension. Overrides the collection's configured personalization strength (0 = off, 1 = full) for this request only — for simulation and A/B tests.\n","type":"number","minimum":0,"maximum":1},"x_surface":{"description":"AACSearch extension. `autocomplete` marks a typeahead request so the collection's \"apply to autocomplete\" personalization switch can gate it; anything else is a search.\n","type":"string","enum":["search","autocomplete"]},"debug":{"description":"AACSearch extension. When true, the response includes `_trace` (what the platform did to the request) and every hit an `_explain` object (scoring signals and matched boosts). Never forwarded to the engine. The `X-NOVA-DEBUG: 1` header is equivalent.\n","type":"boolean","example":true},"rerank":{"description":"AACSearch extension. `true` reranks the leading hits with the model configured in the collection's search rules (defaults apply when the rule has none), `false` skips a rule-enabled reranker for this request. See `SearchRuleRerank`.\n","type":"boolean"},"rerank_top_k":{"description":"AACSearch extension. Overrides how many leading hits the reranker scores (1–100).","type":"integer","minimum":1,"maximum":100},"rerank_model":{"description":"AACSearch extension. Overrides the reranker model for this request.","type":"string","enum":["bge-reranker-base","llm"]},"query_by":{"description":"A list of `string` fields that should be queried against. Multiple fields are separated with a comma.","type":"string"},"validate_field_names":{"description":"Controls whether AACSearch should validate if the fields exist in the schema. When set to false, AACSearch will not throw an error if a field is missing. This is useful for programmatic grouping where not all fields may exist.\n","type":"boolean"},"nl_query":{"description":"Whether to use natural language processing to parse the query.","type":"boolean"},"nl_model_id":{"description":"The ID of the natural language model to use.","type":"string"},"nl_query_debug":{"description":"When true, the raw model response is returned in `parsed_nl_query.llm_response`.","type":"boolean"},"nl_query_prompt_cache_ttl":{"description":"Seconds to cache the schema prompt built for the natural language model. Default: 86400.\n","type":"integer"},"query_by_weights":{"description":"The relative weight to give each `query_by` field when ranking results. This can be used to boost fields in priority, when looking for matches. Multiple fields are separated with a comma.","type":"string"},"text_match_type":{"description":"In a multi-field matching context, this parameter determines how the representative text match score of a record is calculated. Possible values are max_score (default) or max_weight.","type":"string"},"prefix":{"description":"Boolean field to indicate that the last word in the query should be treated as a prefix, and not as a whole word. This is used for building autocomplete and instant search interfaces. Defaults to true.","type":"string"},"infix":{"description":"If infix index is enabled for this field, infix searching can be done on a per-field basis by sending a comma separated string parameter called infix to the search query. This parameter can have 3 values; `off` infix search is disabled, which is default `always` infix search is performed along with regular search `fallback` infix search is performed if regular search does not produce results","type":"string"},"max_extra_prefix":{"description":"There are also 2 parameters that allow you to control the extent of infix searching max_extra_prefix and max_extra_suffix which specify the maximum number of symbols before or after the query that can be present in the token. For example query \"K2100\" has 2 extra symbols in \"6PK2100\". By default, any number of prefixes/suffixes can be present for a match.","type":"integer"},"max_extra_suffix":{"description":"There are also 2 parameters that allow you to control the extent of infix searching max_extra_prefix and max_extra_suffix which specify the maximum number of symbols before or after the query that can be present in the token. For example query \"K2100\" has 2 extra symbols in \"6PK2100\". By default, any number of prefixes/suffixes can be present for a match.","type":"integer"},"filter_by":{"description":"Filter conditions for refining your open api validator search results. Separate multiple conditions with &&.","type":"string","example":"num_employees:>100 && country: [USA, UK]"},"max_filter_by_candidates":{"description":"Controls the number of similar words that AACSearch considers during fuzzy search on filter_by values. Useful for controlling prefix matches like company_name:Acm*.","type":"integer"},"sort_by":{"description":"A list of numerical fields and their corresponding sort orders that will be used for ordering your results. Up to 3 sort fields can be specified. The text similarity score is exposed as a special `_text_match` field that you can use in the list of sorting fields. If no `sort_by` parameter is specified, results are sorted by `_text_match:desc,default_sorting_field:desc`.\nConditional ranking (\"optional filtering\"): use a scoring function with a filter expression to put matching documents first, e.g. scoring by `in_stock:true` combined with `_text_match:desc`; apply weighted scores to clauses like `brand:Nike (weight 3)` and `brand:Adidas (weight 2)`. The collection's search rules can add such clauses for you (`boosts`).\n","type":"string","example":"num_employees:desc"},"facet_by":{"description":"A list of fields that will be used for faceting your results on. Separate multiple fields with a comma.","type":"string"},"max_facet_values":{"description":"Maximum number of facet values to be returned.","type":"integer"},"facet_query":{"description":"Facet values that are returned can now be filtered via this parameter. The matching facet text is also highlighted. For example, when faceting by `category`, you can set `facet_query=category:shoe` to return only facet values that contain the prefix \"shoe\".","type":"string"},"facet_query_num_typos":{"description":"Controls the number of typographical errors (0 to 2) tolerated when matching facet_query against facet values. Default: 2\n","type":"integer"},"num_typos":{"description":"The number of typographical errors (1 or 2) that would be tolerated. Default: 2\n","type":"string"},"page":{"description":"Results from this specific page number would be fetched.","type":"integer"},"per_page":{"description":"Number of results to fetch per page. Default: 10","type":"integer"},"limit":{"description":"Number of hits to fetch. Can be used as an alternative to the per_page parameter. Default: 10.\n","type":"integer"},"offset":{"description":"Identifies the starting point to return hits from a result set. Can be used as an alternative to the page parameter.","type":"integer"},"group_by":{"description":"You can aggregate search results into groups or buckets by specify one or more `group_by` fields. Separate multiple fields with a comma. To group on a particular field, it must be a faceted field.","type":"string"},"group_limit":{"description":"Maximum number of hits to be returned for every group. If the `group_limit` is set as `K` then only the top K hits in each group are returned in the response. Default: 3\n","type":"integer"},"group_missing_values":{"description":"Setting this parameter to true will place all documents that have a null value in the group_by field, into a single group. Setting this parameter to false, will cause each document with a null value in the group_by field to not be grouped with other documents. Default: true\n","type":"boolean"},"include_fields":{"description":"List of fields from the document to include in the search result","type":"string"},"exclude_fields":{"description":"List of fields from the document to exclude in the search result","type":"string"},"highlight_full_fields":{"description":"List of fields which should be highlighted fully without snippeting","type":"string"},"highlight_affix_num_tokens":{"description":"The number of tokens that should surround the highlighted text on each side. Default: 4\n","type":"integer"},"highlight_start_tag":{"description":"The start tag used for the highlighted snippets. Default: `<mark>`\n","type":"string"},"highlight_end_tag":{"description":"The end tag used for the highlighted snippets. Default: `</mark>`\n","type":"string"},"enable_highlight_v1":{"description":"Flag for enabling/disabling the deprecated, old highlight structure in the response. Default: true\n","type":"boolean","default":true},"enable_analytics":{"description":"Flag for enabling/disabling analytics aggregation for specific search queries (for e.g. those originating from a test script).\n","type":"boolean","default":true},"snippet_threshold":{"description":"Field values under this length will be fully highlighted, instead of showing a snippet of relevant portion. Default: 30\n","type":"integer"},"synonym_sets":{"type":"string","description":"List of synonym set names to associate with this search query","example":"synonym_set_1,synonym_set_2"},"drop_tokens_threshold":{"description":"If the number of results found for a specific query is less than this number, AACSearch will attempt to drop the tokens in the query until enough results are found. Tokens that have the least individual hits are dropped first. Set to 0 to disable. Default: 10\n","type":"integer"},"drop_tokens_mode":{"$ref":"#/components/schemas/DropTokensMode"},"typo_tokens_threshold":{"description":"If the number of results found for a specific query is less than this number, AACSearch will attempt to look for tokens with more typos until enough results are found. Default: 100\n","type":"integer"},"enable_typos_for_alpha_numerical_tokens":{"type":"boolean","description":"Set this parameter to false to disable typos on alphanumerical query tokens. Default: true.\n"},"filter_curated_hits":{"type":"boolean","description":"Whether the filter_by condition of the search query should be applicable to curated results (curation definitions, pinned hits, hidden hits, etc.). Default: false\n"},"enable_synonyms":{"type":"boolean","description":"If you have some synonyms defined but want to disable all of them for a particular search query, set enable_synonyms to false. Default: true\n"},"synonym_prefix":{"type":"boolean","description":"Allow synonym resolution on word prefixes in the query. Default: false\n"},"synonym_num_typos":{"type":"integer","description":"Allow synonym resolution on typo-corrected words in the query. Default: 0\n"},"pinned_hits":{"description":"A list of records to unconditionally include in the search results at specific positions. An example use case would be to feature or promote certain items on the top of search results. A list of `record_id:hit_position`. Eg: to include a record with ID 123 at Position 1 and another record with ID 456 at Position 5, you'd specify `123:1,456:5`.\nYou could also use the Curation feature to override search results based on rules. Curations are applied first, followed by `pinned_hits` and finally `hidden_hits`.\n","type":"string"},"hidden_hits":{"description":"A list of records to unconditionally hide from search results. A list of `record_id`s to hide. Eg: to hide records with IDs 123 and 456, you'd specify `123,456`.\nYou could also use the Curation feature to override search results based on rules. Curations are applied first, followed by `pinned_hits` and finally `hidden_hits`.\n","type":"string"},"curation_tags":{"description":"Comma separated list of tags to trigger the curations rules that match the tags.","type":"string"},"highlight_fields":{"description":"A list of custom fields that must be highlighted even if you don't query for them\n","type":"string"},"split_join_tokens":{"description":"Treat space as typo: search for q=basket ball if q=basketball is not found or vice-versa. Splitting/joining of tokens will only be attempted if the original query produces no results. To always trigger this behavior, set value to `always``. To disable, set value to `off`. Default is `fallback`.\n","type":"string"},"pre_segmented_query":{"description":"You can index content from any logographic language into AACSearch if you are able to segment / split the text into space-separated words yourself before indexing and querying.\nSet this parameter to true to do the same\n","type":"boolean"},"preset":{"description":"Search using a bunch of search parameters by setting this parameter to the name of the existing Preset.\n","type":"string"},"profile":{"description":"AACSearch extension. Name of a search profile on the collection: the platform compiles it into `query_by`, `facet_by`, `sort_by`, `highlight_fields` and the fixed filter before the request reaches the engine, and rejects a request that also sets those parameters itself (`400`). A browser key pinned to a profile applies it without this parameter. Never forwarded to the engine.\n","type":"string"},"sort":{"description":"AACSearch extension. Id of one of the profile's sorts (see `getSearchProfileView`); defaults to the profile's `default_sort_id`. Only meaningful with `profile`. Never forwarded to the engine.\n","type":"string"},"enable_curations":{"description":"If you have some curation sets defined but want to disable all of them during query time, you can do that by setting this parameter to false\n","type":"boolean","default":false},"prioritize_exact_match":{"description":"Set this parameter to true to ensure that an exact match is ranked above the others\n","type":"boolean","default":true},"max_candidates":{"description":"Control the number of words that AACSearch considers for typo and prefix searching.\n","type":"integer"},"prioritize_token_position":{"description":"Make AACSearch prioritize documents where the query words appear earlier in the text.\n","type":"boolean","default":false},"prioritize_num_matching_fields":{"description":"Make AACSearch prioritize documents where the query words appear in more number of fields.\n","type":"boolean","default":true},"enable_typos_for_numerical_tokens":{"description":"Make AACSearch disable typos for numerical tokens.\n","type":"boolean","default":true},"exhaustive_search":{"description":"Setting this to true will make AACSearch consider all prefixes and typo corrections of the words in the query without stopping early when enough results are found (drop_tokens_threshold and typo_tokens_threshold configurations are ignored).\n","type":"boolean"},"search_cutoff_ms":{"description":"AACSearch will attempt to return results early if the cutoff time has elapsed. This is not a strict guarantee and facet computation is not bound by this parameter.\n","type":"integer"},"use_cache":{"description":"Enable server side caching of search query results. By default, caching is disabled.\n","type":"boolean"},"cache_ttl":{"description":"The duration (in seconds) that determines how long the search query is cached. This value can be set on a per-query basis. Default: 60.\n","type":"integer"},"min_len_1typo":{"description":"Minimum word length for 1-typo correction to be applied. The value of num_typos is still treated as the maximum allowed typos.\n","type":"integer"},"min_len_2typo":{"description":"Minimum word length for 2-typo correction to be applied. The value of num_typos is still treated as the maximum allowed typos.\n","type":"integer"},"vector_query":{"description":"Vector query expression for fetching documents \"closest\" to a given query/document vector, in the form `field:([values], option: value, ...)`. Provide the vector inline (`embedding:([0.1, 0.2, ...])`), reference a document to find similar ones (`embedding:([], id: doc_id)`), or pass a base64 image for a CLIP-embedded field (`embedding:([], image: BASE64)`). Options: `k` (number of nearest neighbours), `distance_threshold`, `alpha` (weight of the vector score in hybrid search), `ef` (HNSW search depth), `flat_search_cutoff`.\n","type":"string"},"remote_embedding_timeout_ms":{"description":"Timeout (in milliseconds) for fetching remote embeddings.\n","type":"integer"},"remote_embedding_num_tries":{"description":"Number of times to retry fetching remote embeddings.\n","type":"integer"},"facet_strategy":{"description":"Choose the underlying faceting strategy used. Comma separated string of allows values: exhaustive, top_values or automatic (default).\n","type":"string"},"stopwords":{"description":"Name of the stopwords set to apply for this search, the keywords present in the set will be removed from the search query.\n","type":"string"},"facet_return_parent":{"description":"Comma separated string of nested facet fields whose parent object should be returned in facet response.\n","type":"string"},"voice_query":{"description":"Low-level engine path: a base64 encoded audio file in 16 kHz 16-bit WAV format, English only. Prefer `POST /collections/{collectionName}/documents/search/by_voice`, which accepts what browsers actually record (webm/opus, m4a, wav), detects the language, and returns the transcript alongside the results. This parameter is forwarded to the engine unchanged and requires a voice query model to be configured for your account.\n","type":"string","deprecated":true},"conversation":{"description":"Enable conversational search.\n","type":"boolean"},"conversation_model_id":{"description":"The Id of Conversation Model to be used.\n","type":"string"},"conversation_id":{"description":"The Id of a previous conversation to continue, this tells AACSearch to include prior context when communicating with the LLM.\n","type":"string"},"conversation_stream":{"description":"When true, the conversational answer is streamed as Server-Sent Events. Each event is `data: {\"conversation\": {\"message\": \"...\", \"conversation_id\": \"...\"}}`; the stream ends with `data: [DONE]` after a final event carrying the complete search response. Supported on `POST /multi_search` only.\n","type":"boolean"}}},"MultiSearchParameters":{"description":"Parameters for the multi search API.\n","type":"object","properties":{"q":{"description":"The query text to search for in the collection. Use * as the search string to return all documents. This is typically useful when used in conjunction with filter_by.","type":"string"},"query_rewrite":{"description":"AACSearch extension. Per-search override of the zero-hit query rewrite (see the same parameter on `SearchParameters`): comma-separated subset of `layout`, `translit`, `homoglyph`, or `off`. Applies to every search in the batch when given in the query string. Not applied to `union` searches.\n","type":"string","example":"layout,translit"},"x_user_id":{"description":"AACSearch extension. See the same parameter on `SearchParameters`; read from the query string for the whole batch.","type":"string"},"x_anonymous_id":{"description":"AACSearch extension. See the same parameter on `SearchParameters`.","type":"string"},"x_personalization_strength":{"description":"AACSearch extension. See the same parameter on `SearchParameters`.","type":"number","minimum":0,"maximum":1},"x_surface":{"description":"AACSearch extension. See the same parameter on `SearchParameters`.","type":"string","enum":["search","autocomplete"]},"debug":{"description":"AACSearch extension. When true, the response includes `_trace` and every hit an `_explain` object (see the same parameter on `SearchParameters`). Never forwarded to the engine.\n","type":"boolean","example":true},"query_by":{"description":"A list of `string` fields that should be queried against. Multiple fields are separated with a comma.","type":"string"},"query_by_weights":{"description":"The relative weight to give each `query_by` field when ranking results. This can be used to boost fields in priority, when looking for matches. Multiple fields are separated with a comma.","type":"string"},"text_match_type":{"description":"In a multi-field matching context, this parameter determines how the representative text match score of a record is calculated. Possible values are max_score (default) or max_weight.","type":"string"},"prefix":{"description":"Boolean field to indicate that the last word in the query should be treated as a prefix, and not as a whole word. This is used for building autocomplete and instant search interfaces. Defaults to true.","type":"string"},"infix":{"description":"If infix index is enabled for this field, infix searching can be done on a per-field basis by sending a comma separated string parameter called infix to the search query. This parameter can have 3 values; `off` infix search is disabled, which is default `always` infix search is performed along with regular search `fallback` infix search is performed if regular search does not produce results","type":"string"},"max_extra_prefix":{"description":"There are also 2 parameters that allow you to control the extent of infix searching max_extra_prefix and max_extra_suffix which specify the maximum number of symbols before or after the query that can be present in the token. For example query \"K2100\" has 2 extra symbols in \"6PK2100\". By default, any number of prefixes/suffixes can be present for a match.","type":"integer"},"max_extra_suffix":{"description":"There are also 2 parameters that allow you to control the extent of infix searching max_extra_prefix and max_extra_suffix which specify the maximum number of symbols before or after the query that can be present in the token. For example query \"K2100\" has 2 extra symbols in \"6PK2100\". By default, any number of prefixes/suffixes can be present for a match.","type":"integer"},"filter_by":{"description":"Filter conditions for refining youropen api validator search results. Separate multiple conditions with &&.","type":"string","example":"num_employees:>100 && country: [USA, UK]"},"sort_by":{"description":"A list of numerical fields and their corresponding sort orders that will be used for ordering your results. Up to 3 sort fields can be specified. The text similarity score is exposed as a special `_text_match` field that you can use in the list of sorting fields. If no `sort_by` parameter is specified, results are sorted by `_text_match:desc,default_sorting_field:desc`","type":"string"},"facet_by":{"description":"A list of fields that will be used for faceting your results on. Separate multiple fields with a comma.","type":"string"},"max_facet_values":{"description":"Maximum number of facet values to be returned.","type":"integer"},"facet_query":{"description":"Facet values that are returned can now be filtered via this parameter. The matching facet text is also highlighted. For example, when faceting by `category`, you can set `facet_query=category:shoe` to return only facet values that contain the prefix \"shoe\".","type":"string"},"facet_query_num_typos":{"description":"Controls the number of typographical errors (0 to 2) tolerated when matching facet_query against facet values. Default: 2\n","type":"integer"},"num_typos":{"description":"The number of typographical errors (1 or 2) that would be tolerated. Default: 2\n","type":"string"},"page":{"description":"Results from this specific page number would be fetched.","type":"integer"},"per_page":{"description":"Number of results to fetch per page. Default: 10","type":"integer"},"limit":{"description":"Number of hits to fetch. Can be used as an alternative to the per_page parameter. Default: 10.\n","type":"integer"},"offset":{"description":"Identifies the starting point to return hits from a result set. Can be used as an alternative to the page parameter.","type":"integer"},"group_by":{"description":"You can aggregate search results into groups or buckets by specify one or more `group_by` fields. Separate multiple fields with a comma. To group on a particular field, it must be a faceted field.","type":"string"},"group_limit":{"description":"Maximum number of hits to be returned for every group. If the `group_limit` is set as `K` then only the top K hits in each group are returned in the response. Default: 3\n","type":"integer"},"group_missing_values":{"description":"Setting this parameter to true will place all documents that have a null value in the group_by field, into a single group. Setting this parameter to false, will cause each document with a null value in the group_by field to not be grouped with other documents. Default: true\n","type":"boolean"},"include_fields":{"description":"List of fields from the document to include in the search result","type":"string"},"exclude_fields":{"description":"List of fields from the document to exclude in the search result","type":"string"},"highlight_full_fields":{"description":"List of fields which should be highlighted fully without snippeting","type":"string"},"highlight_affix_num_tokens":{"description":"The number of tokens that should surround the highlighted text on each side. Default: 4\n","type":"integer"},"highlight_start_tag":{"description":"The start tag used for the highlighted snippets. Default: `<mark>`\n","type":"string"},"highlight_end_tag":{"description":"The end tag used for the highlighted snippets. Default: `</mark>`\n","type":"string"},"snippet_threshold":{"description":"Field values under this length will be fully highlighted, instead of showing a snippet of relevant portion. Default: 30\n","type":"integer"},"drop_tokens_threshold":{"description":"If the number of results found for a specific query is less than this number, AACSearch will attempt to drop the tokens in the query until enough results are found. Tokens that have the least individual hits are dropped first. Set to 0 to disable. Default: 10\n","type":"integer"},"drop_tokens_mode":{"$ref":"#/components/schemas/DropTokensMode"},"typo_tokens_threshold":{"description":"If the number of results found for a specific query is less than this number, AACSearch will attempt to look for tokens with more typos until enough results are found. Default: 100\n","type":"integer"},"enable_typos_for_alpha_numerical_tokens":{"type":"boolean","description":"Set this parameter to false to disable typos on alphanumerical query tokens. Default: true.\n"},"filter_curated_hits":{"type":"boolean","description":"Whether the filter_by condition of the search query should be applicable to curated results (curation definitions, pinned hits, hidden hits, etc.). Default: false\n"},"enable_synonyms":{"type":"boolean","description":"If you have some synonyms defined but want to disable all of them for a particular search query, set enable_synonyms to false. Default: true\n"},"enable_analytics":{"description":"Flag for enabling/disabling analytics aggregation for specific search queries (for e.g. those originating from a test script).\n","type":"boolean","default":true},"synonym_prefix":{"type":"boolean","description":"Allow synonym resolution on word prefixes in the query. Default: false\n"},"synonym_num_typos":{"type":"integer","description":"Allow synonym resolution on typo-corrected words in the query. Default: 0\n"},"pinned_hits":{"description":"A list of records to unconditionally include in the search results at specific positions. An example use case would be to feature or promote certain items on the top of search results. A list of `record_id:hit_position`. Eg: to include a record with ID 123 at Position 1 and another record with ID 456 at Position 5, you'd specify `123:1,456:5`.\nYou could also use the Curation feature to override search results based on rules. Curations are applied first, followed by `pinned_hits` and finally `hidden_hits`.\n","type":"string"},"hidden_hits":{"description":"A list of records to unconditionally hide from search results. A list of `record_id`s to hide. Eg: to hide records with IDs 123 and 456, you'd specify `123,456`.\nYou could also use the Curation feature to override search results based on rules. Curations are applied first, followed by `pinned_hits` and finally `hidden_hits`.\n","type":"string"},"curation_tags":{"description":"Comma separated list of tags to trigger the curations rules that match the tags.","type":"string"},"highlight_fields":{"description":"A list of custom fields that must be highlighted even if you don't query for them\n","type":"string"},"pre_segmented_query":{"description":"You can index content from any logographic language into AACSearch if you are able to segment / split the text into space-separated words yourself before indexing and querying.\nSet this parameter to true to do the same\n","type":"boolean","default":false},"preset":{"description":"Search using a bunch of search parameters by setting this parameter to the name of the existing Preset.\n","type":"string"},"profile":{"description":"AACSearch extension. Name of a search profile on the collection: the platform compiles it into `query_by`, `facet_by`, `sort_by`, `highlight_fields` and the fixed filter before the request reaches the engine, and rejects a request that also sets those parameters itself (`400`). A browser key pinned to a profile applies it without this parameter. Never forwarded to the engine.\n","type":"string"},"sort":{"description":"AACSearch extension. Id of one of the profile's sorts (see `getSearchProfileView`); defaults to the profile's `default_sort_id`. Only meaningful with `profile`. Never forwarded to the engine.\n","type":"string"},"enable_curations":{"description":"If you have some curation sets defined but want to disable all of them during query time, you can do that by setting this parameter to false\n","type":"boolean","default":false},"prioritize_exact_match":{"description":"Set this parameter to true to ensure that an exact match is ranked above the others\n","type":"boolean","default":true},"prioritize_token_position":{"description":"Make AACSearch prioritize documents where the query words appear earlier in the text.\n","type":"boolean","default":false},"prioritize_num_matching_fields":{"description":"Make AACSearch prioritize documents where the query words appear in more number of fields.\n","type":"boolean","default":true},"enable_typos_for_numerical_tokens":{"description":"Make AACSearch disable typos for numerical tokens.\n","type":"boolean","default":true},"exhaustive_search":{"description":"Setting this to true will make AACSearch consider all prefixes and typo corrections of the words in the query without stopping early when enough results are found (drop_tokens_threshold and typo_tokens_threshold configurations are ignored).\n","type":"boolean"},"search_cutoff_ms":{"description":"AACSearch will attempt to return results early if the cutoff time has elapsed. This is not a strict guarantee and facet computation is not bound by this parameter.\n","type":"integer"},"use_cache":{"description":"Enable server side caching of search query results. By default, caching is disabled.\n","type":"boolean"},"cache_ttl":{"description":"The duration (in seconds) that determines how long the search query is cached. This value can be set on a per-query basis. Default: 60.\n","type":"integer"},"min_len_1typo":{"description":"Minimum word length for 1-typo correction to be applied. The value of num_typos is still treated as the maximum allowed typos.\n","type":"integer"},"min_len_2typo":{"description":"Minimum word length for 2-typo correction to be applied. The value of num_typos is still treated as the maximum allowed typos.\n","type":"integer"},"vector_query":{"description":"Vector query expression for fetching documents \"closest\" to a given query/document vector, in the form `field:([values], option: value, ...)`. Provide the vector inline (`embedding:([0.1, 0.2, ...])`), reference a document to find similar ones (`embedding:([], id: doc_id)`), or pass a base64 image for a CLIP-embedded field (`embedding:([], image: BASE64)`). Options: `k` (number of nearest neighbours), `distance_threshold`, `alpha` (weight of the vector score in hybrid search), `ef` (HNSW search depth), `flat_search_cutoff`.\n","type":"string"},"remote_embedding_timeout_ms":{"description":"Timeout (in milliseconds) for fetching remote embeddings.\n","type":"integer"},"remote_embedding_num_tries":{"description":"Number of times to retry fetching remote embeddings.\n","type":"integer"},"facet_strategy":{"description":"Choose the underlying faceting strategy used. Comma separated string of allows values: exhaustive, top_values or automatic (default).\n","type":"string"},"stopwords":{"description":"Name of the stopwords set to apply for this search, the keywords present in the set will be removed from the search query.\n","type":"string"},"facet_return_parent":{"description":"Comma separated string of nested facet fields whose parent object should be returned in facet response.\n","type":"string"},"voice_query":{"description":"Low-level engine path: a base64 encoded audio file in 16 kHz 16-bit WAV format, English only. Prefer `POST /collections/{collectionName}/documents/search/by_voice`, which accepts what browsers actually record (webm/opus, m4a, wav), detects the language, and returns the transcript alongside the results. This parameter is forwarded to the engine unchanged and requires a voice query model to be configured for your account.\n","type":"string","deprecated":true},"conversation":{"description":"Enable conversational search.\n","type":"boolean"},"conversation_model_id":{"description":"The Id of Conversation Model to be used.\n","type":"string"},"conversation_id":{"description":"The Id of a previous conversation to continue, this tells AACSearch to include prior context when communicating with the LLM.\n","type":"string"},"conversation_stream":{"description":"When true, the conversational answer is streamed as Server-Sent Events. Each event is `data: {\"conversation\": {\"message\": \"...\", \"conversation_id\": \"...\"}}`; the stream ends with `data: [DONE]` after a final event carrying the complete search response. Supported on `POST /multi_search` only.\n","type":"boolean"},"validate_field_names":{"description":"Controls whether AACSearch should validate if the fields exist in the schema. When set to false, AACSearch will not throw an error if a field is missing. This is useful for programmatic grouping where not all fields may exist.\n","type":"boolean"},"nl_query":{"description":"Whether to use natural language processing to parse the query.","type":"boolean"},"nl_model_id":{"description":"The ID of the natural language model to use.","type":"string"},"nl_query_debug":{"description":"When true, the raw model response is returned in `parsed_nl_query.llm_response`.","type":"boolean"},"nl_query_prompt_cache_ttl":{"description":"Seconds to cache the schema prompt built for the natural language model. Default: 86400.\n","type":"integer"}}},"MultiSearchSearchesParameter":{"type":"object","required":["searches"],"properties":{"union":{"type":"boolean","default":false,"description":"When true, merges the search results from each search query into a single ordered set of hits."},"searches":{"type":"array","items":{"$ref":"#/components/schemas/MultiSearchCollectionParameters"}}}},"MultiSearchCollectionParameters":{"allOf":[{"$ref":"#/components/schemas/MultiSearchParameters"},{"type":"object","properties":{"collection":{"type":"string","description":"The collection to search in.\n"},"rerank_hybrid_matches":{"type":"boolean","description":"When true, computes both text match and vector distance scores for all matches in hybrid search. Documents found only through keyword search will get a vector distance score, and documents found only through vector search will get a text match score.\n","default":false}}}]},"FacetCounts":{"type":"object","properties":{"counts":{"type":"array","items":{"type":"object","properties":{"count":{"type":"integer"},"highlighted":{"type":"string"},"value":{"type":"string"},"parent":{"type":"object"}}}},"field_name":{"type":"string"},"sampled":{"type":"boolean"},"stats":{"type":"object","properties":{"max":{"type":"number","format":"double"},"min":{"type":"number","format":"double"},"sum":{"type":"number","format":"double"},"total_values":{"type":"integer"},"avg":{"type":"number","format":"double"}}}}},"AnalyticsEventCreateResponse":{"type":"object","required":["ok"],"properties":{"ok":{"type":"boolean"}}},"AnalyticsEvent":{"type":"object","required":["name","event_type","data"],"properties":{"name":{"type":"string","description":"Name of the analytics rule this event corresponds to"},"event_type":{"type":"string","description":"Type of event","enum":["search","click","conversion","visit"]},"data":{"type":"object","description":"Event payload","properties":{"user_id":{"type":"string"},"doc_id":{"type":"string"},"doc_ids":{"type":"array","items":{"type":"string"}},"q":{"type":"string"},"filter_by":{"type":"string","description":"Filter expression that was active when the event happened"},"analytics_tag":{"type":"string"}}}}},"AnalyticsEventsResponse":{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"event_type":{"type":"string"},"collection":{"type":"string"},"timestamp":{"type":"integer","x-fern-type":"long"},"user_id":{"type":"string"},"doc_id":{"type":"string"},"doc_ids":{"type":"array","items":{"type":"string"}},"query":{"type":"string"}}}}}},"AnalyticsRuleCreate":{"type":"object","required":["name","type","collection","event_type"],"properties":{"name":{"type":"string"},"type":{"$ref":"#/components/schemas/AnalyticsRuleType"},"collection":{"type":"string"},"event_type":{"type":"string"},"rule_tag":{"type":"string"},"params":{"type":"object","properties":{"destination_collection":{"type":"string"},"limit":{"type":"integer"},"capture_search_requests":{"type":"boolean"},"meta_fields":{"type":"array","items":{"type":"string"}},"expand_query":{"type":"boolean"},"counter_field":{"type":"string"},"weight":{"type":"integer"}}}}},"AnalyticsRuleType":{"type":"string","enum":["popular_queries","nohits_queries","counter","log"]},"AnalyticsRuleUpdate":{"type":"object","description":"Fields allowed to update on an analytics rule","properties":{"name":{"type":"string"},"rule_tag":{"type":"string"},"params":{"type":"object","properties":{"destination_collection":{"type":"string"},"limit":{"type":"integer"},"capture_search_requests":{"type":"boolean"},"meta_fields":{"type":"array","items":{"type":"string"}},"expand_query":{"type":"boolean"},"counter_field":{"type":"string"},"weight":{"type":"integer"}}}}},"AnalyticsRule":{"allOf":[{"$ref":"#/components/schemas/AnalyticsRuleCreate"},{"type":"object"}]},"AnalyticsStatus":{"type":"object","properties":{"popular_prefix_queries":{"type":"integer"},"nohits_prefix_queries":{"type":"integer"},"log_prefix_queries":{"type":"integer"},"query_log_events":{"type":"integer"},"query_counter_events":{"type":"integer"},"doc_log_events":{"type":"integer"},"doc_counter_events":{"type":"integer"}}},"APIStatsResponse":{"type":"object","properties":{"delete_latency_ms":{"type":"number","format":"double"},"delete_requests_per_second":{"type":"number","format":"double"},"import_latency_ms":{"type":"number","format":"double"},"import_requests_per_second":{"type":"number","format":"double"},"latency_ms":{"type":"object","x-go-type":"map[string]float64"},"overloaded_requests_per_second":{"type":"number","format":"double"},"pending_write_batches":{"type":"number","format":"double"},"requests_per_second":{"type":"object","x-go-type":"map[string]float64"},"search_latency_ms":{"type":"number","format":"double"},"search_requests_per_second":{"type":"number","format":"double"},"total_requests_per_second":{"type":"number","format":"double"},"write_latency_ms":{"type":"number","format":"double"},"write_requests_per_second":{"type":"number","format":"double"}}},"StopwordsSetUpsertSchema":{"type":"object","properties":{"stopwords":{"type":"array","items":{"type":"string"}},"locale":{"type":"string"}},"required":["stopwords"],"example":{"stopwords":["Germany","France","Italy"],"locale":"en"}},"StopwordsSetSchema":{"type":"object","properties":{"id":{"type":"string"},"stopwords":{"type":"array","items":{"type":"string"}},"locale":{"type":"string"}},"required":["id","stopwords"],"example":{"id":"countries","stopwords":["Germany","France","Italy"],"locale":"en"}},"StopwordsSetRetrieveSchema":{"type":"object","properties":{"stopwords":{"$ref":"#/components/schemas/StopwordsSetSchema"}},"required":["stopwords"],"example":{"stopwords":{"id":"countries","stopwords":["Germany","France","Italy"],"locale":"en"}}},"StopwordsSetsRetrieveAllSchema":{"type":"object","properties":{"stopwords":{"type":"array","items":{"$ref":"#/components/schemas/StopwordsSetSchema"}}},"required":["stopwords"],"example":{"stopwords":[{"id":"countries","stopwords":["Germany","France","Italy"],"locale":"en"}]}},"PresetUpsertSchema":{"properties":{"value":{"oneOf":[{"$ref":"#/components/schemas/SearchParameters"},{"$ref":"#/components/schemas/MultiSearchSearchesParameter"}]}},"required":["value"]},"PresetSchema":{"allOf":[{"$ref":"#/components/schemas/PresetUpsertSchema"},{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}]},"PresetsRetrieveSchema":{"type":"object","required":["presets"],"properties":{"presets":{"type":"array","items":{"$ref":"#/components/schemas/PresetSchema"},"x-go-type":"[]*PresetSchema"}}},"PresetDeleteSchema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"DirtyValues":{"type":"string","enum":["coerce_or_reject","coerce_or_drop","drop","reject"]},"IndexAction":{"type":"string","enum":["create","update","upsert","emplace"]},"DropTokensMode":{"type":"string","enum":["right_to_left","left_to_right","both_sides:3"],"description":"Dictates the direction in which the words in the query must be dropped when the original words in the query do not appear in any document. Values: right_to_left (default), left_to_right, both_sides:3 A note on both_sides:3 - for queries up to 3 tokens (words) in length, this mode will drop tokens from both sides and exhaustively rank all matching results. If query length is greater than 3 words, AACSearch will just fallback to default behavior of right_to_left\n"},"ConversationModelCreateSchema":{"required":["model_name","max_bytes"],"allOf":[{"$ref":"#/components/schemas/ConversationModelUpdateSchema"},{"type":"object","required":["model_name","max_bytes","history_collection"],"properties":{"model_name":{"description":"Name of the LLM model offered by OpenAI, Cloudflare or vLLM. Must be a model the platform's catalog offers for the `conversation` role; when the catalog lists none, any name is accepted (pre-catalog behaviour).\n","type":"string"},"max_bytes":{"description":"The maximum number of bytes to send to the LLM in every API call. Consult the LLM's documentation on the number of bytes supported in the context window.\n","type":"integer"},"history_collection":{"type":"string","description":"AACSearch collection that stores the historical conversations"}}}]},"ConversationModelUpdateSchema":{"type":"object","properties":{"id":{"type":"string","description":"An explicit id for the model, otherwise the API will return a response with an auto-generated conversation model id."},"model_name":{"description":"Name of the LLM model, prefixed by provider: `openai/` (OpenAI and Azure OpenAI), `cloudflare/` (Workers AI, requires `account_id`) or `vllm/` (requires `vllm_url`).\n","type":"string"},"api_key":{"description":"The LLM service's API Key","type":"string"},"history_collection":{"type":"string","description":"AACSearch collection that stores the historical conversations"},"account_id":{"description":"LLM service's account ID (only applicable for Cloudflare)","type":"string"},"system_prompt":{"description":"The system prompt that contains special instructions to the LLM","type":"string"},"ttl":{"type":"integer","description":"Time interval in seconds after which the messages would be deleted. Default: 86400 (24 hours)\n"},"max_bytes":{"description":"The maximum number of bytes to send to the LLM in every API call. Consult the LLM's documentation on the number of bytes supported in the context window.\n","type":"integer"},"vllm_url":{"description":"URL of vLLM service","type":"string"},"url":{"description":"Azure OpenAI deployment URL (only applicable for Azure OpenAI)","type":"string"},"openai_url":{"description":"Custom base URL for an OpenAI-compatible endpoint (only applicable for OpenAI)","type":"string"},"openai_path":{"description":"Custom path for an OpenAI-compatible endpoint, appended to `openai_url` (only applicable for OpenAI)","type":"string"}}},"ConversationModelSchema":{"allOf":[{"$ref":"#/components/schemas/ConversationModelCreateSchema"},{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"An explicit id for the model, otherwise the API will return a response with an auto-generated conversation model id."}}}]},"StemmingDictionary":{"type":"object","required":["id","words"],"properties":{"id":{"type":"string","description":"Unique identifier for the dictionary","example":"irregular-plurals"},"words":{"type":"array","description":"List of word mappings in the dictionary","items":{"type":"object","required":["word","root"],"properties":{"word":{"type":"string","description":"The word form to be stemmed","example":"people"},"root":{"type":"string","description":"The root form of the word","example":"person"}}}}}},"NLSearchModelBase":{"type":"object","properties":{"model_name":{"type":"string","description":"Name of the NL model to use"},"api_key":{"type":"string","description":"API key for the NL model service"},"api_url":{"type":"string","description":"Custom API URL for the NL model service"},"max_bytes":{"type":"integer","description":"Maximum number of bytes to process"},"temperature":{"type":"number","description":"Temperature parameter for the NL model"},"system_prompt":{"type":"string","description":"System prompt for the NL model"},"top_p":{"type":"number","description":"Top-p parameter for the NL model (Google-specific)"},"top_k":{"type":"integer","description":"Top-k parameter for the NL model (Google-specific)"},"stop_sequences":{"type":"array","items":{"type":"string"},"description":"Stop sequences for the NL model (Google-specific)"},"api_version":{"type":"string","description":"API version for the NL model service"},"project_id":{"type":"string","description":"Project ID for GCP Vertex AI"},"access_token":{"type":"string","description":"Access token for GCP Vertex AI"},"refresh_token":{"type":"string","description":"Refresh token for GCP Vertex AI"},"client_id":{"type":"string","description":"Client ID for GCP Vertex AI"},"client_secret":{"type":"string","description":"Client secret for GCP Vertex AI"},"region":{"type":"string","description":"Region for GCP Vertex AI"},"max_output_tokens":{"type":"integer","description":"Maximum output tokens for GCP Vertex AI"},"account_id":{"type":"string","description":"Account ID for Cloudflare-specific models"}}},"NLSearchModelCreateSchema":{"allOf":[{"$ref":"#/components/schemas/NLSearchModelBase"},{"type":"object","properties":{"id":{"type":"string","description":"Optional ID for the NL search model"}}}]},"NLSearchModelSchema":{"allOf":[{"$ref":"#/components/schemas/NLSearchModelCreateSchema"},{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"ID of the NL search model"}}}]},"NLSearchModelUpdateSchema":{"$ref":"#/components/schemas/NLSearchModelCreateSchema"},"NLSearchModelDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"ID of the deleted NL search model"}}},"SynonymItemUpsertSchema":{"type":"object","required":["synonyms"],"properties":{"synonyms":{"type":"array","description":"Array of words that should be considered as synonyms","items":{"type":"string"}},"root":{"type":"string","description":"For 1-way synonyms, indicates the root word that words in the synonyms parameter map to"},"locale":{"type":"string","description":"Locale for the synonym, leave blank to use the standard tokenizer"},"symbols_to_index":{"type":"array","description":"By default, special characters are dropped from synonyms. Use this attribute to specify which special characters should be indexed as is","items":{"type":"string"}}}},"SynonymItemSchema":{"allOf":[{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Unique identifier for the synonym item"}}},{"$ref":"#/components/schemas/SynonymItemUpsertSchema"}]},"SynonymSetCreateSchema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","description":"Array of synonym items","items":{"$ref":"#/components/schemas/SynonymItemSchema"}}}},"SynonymSetSchema":{"allOf":[{"$ref":"#/components/schemas/SynonymSetCreateSchema"},{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Name of the synonym set"}}}]},"SynonymSetsRetrieveSchema":{"type":"object","required":["synonym_sets"],"properties":{"synonym_sets":{"type":"array","description":"Array of synonym sets","items":{"$ref":"#/components/schemas/SynonymSetSchema"}}}},"SynonymSetDeleteSchema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Name of the deleted synonym set"}}},"SynonymItemDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"ID of the deleted synonym item"}}},"CurationItemCreateSchema":{"type":"object","required":["rule"],"properties":{"rule":{"$ref":"#/components/schemas/CurationRule"},"includes":{"type":"array","description":"List of document `id`s that should be included in the search results with their corresponding `position`s.","items":{"$ref":"#/components/schemas/CurationInclude"}},"excludes":{"type":"array","description":"List of document `id`s that should be excluded from the search results.","items":{"$ref":"#/components/schemas/CurationExclude"}},"filter_by":{"type":"string","description":"A filter by clause that is applied to any search query that matches the curation rule.\n"},"remove_matched_tokens":{"type":"boolean","description":"Indicates whether search query tokens that exist in the curation's rule should be removed from the search query.\n"},"metadata":{"type":"object","description":"Return a custom JSON object in the Search API response, when this rule is triggered. This can can be used to display a pre-defined message (eg: a promotion banner) on the front-end when a particular rule is triggered.\n"},"sort_by":{"type":"string","description":"A sort by clause that is applied to any search query that matches the curation rule.\n"},"replace_query":{"type":"string","description":"Replaces the current search query with this value, when the search query matches the curation rule.\n"},"filter_curated_hits":{"type":"boolean","description":"When set to true, the filter conditions of the query is applied to the curated records as well. Default: false.\n"},"effective_from_ts":{"type":"integer","description":"A Unix timestamp that indicates the date/time from which the curation will be active. You can use this to create rules that start applying from a future point in time.\n"},"effective_to_ts":{"type":"integer","description":"A Unix timestamp that indicates the date/time until which the curation will be active. You can use this to create rules that stop applying after a period of time.\n"},"stop_processing":{"type":"boolean","description":"When set to true, curation processing will stop at the first matching rule. When set to false curation processing will continue and multiple curation actions will be triggered in sequence. Curations are processed in the lexical sort order of their id field.\n"},"id":{"type":"string","description":"ID of the curation item"}}},"CurationItemSchema":{"allOf":[{"$ref":"#/components/schemas/CurationItemCreateSchema"},{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}}]},"CurationSetCreateSchema":{"type":"object","required":["items"],"properties":{"items":{"type":"array","description":"Array of curation items","items":{"$ref":"#/components/schemas/CurationItemCreateSchema"}},"description":{"type":"string","description":"Optional description for the curation set"}}},"CurationSetSchema":{"allOf":[{"$ref":"#/components/schemas/CurationSetCreateSchema"},{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}}]},"CurationRule":{"type":"object","properties":{"tags":{"type":"array","description":"List of tag values to associate with this curation rule.","items":{"type":"string"}},"query":{"type":"string","description":"Indicates what search queries should be curated"},"match":{"type":"string","description":"Indicates whether the match on the query term should be `exact` or `contains`. If we want to match all queries that contained the word `apple`, we will use the `contains` match instead.\n","enum":["exact","contains"]},"filter_by":{"type":"string","description":"Indicates that the curation should apply when the filter_by parameter in a search query exactly matches the string specified here (including backticks, spaces, brackets, etc).\n"}}},"CurationInclude":{"type":"object","required":["id","position"],"properties":{"id":{"type":"string","description":"document id that should be included"},"position":{"type":"integer","description":"position number where document should be included in the search results"}}},"CurationExclude":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"document id that should be excluded from the search results."}}},"CurationSetDeleteSchema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Name of the deleted curation set"}}},"CurationItemDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"ID of the deleted curation item"}}},"EventType":{"type":"string","description":"What the user did. `impression` records the documents shown (with `positions`); `favorite`, `wishlist`, `share` and `dismiss` are per-document intent signals. `suggestion_select` (with `query_id` = the `suggest_id` of the typeahead response and `metadata.candidate_id` / `metadata.position`), `chip_click` (`metadata.refinement_id`), `correction_accept` / `correction_reject` (`query_id` = the search trace id) feed the query-intelligence learning loop; `suggestion_impression` is recorded server-side and only needs sending from clients that render suggestions they fetched elsewhere.\n","enum":["search","view","click","add_to_cart","purchase","conversion","impression","favorite","wishlist","share","dismiss","suggestion_impression","suggestion_select","chip_click","correction_accept","correction_reject"]},"EventObject":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Document id"},"price":{"type":"number","description":"Unit price in `currency`"},"quantity":{"type":"integer","description":"Units involved in the event","default":1},"discount":{"type":"number","description":"Discount applied to the unit price in `currency`"}}},"Event":{"type":"object","required":["type","collection"],"properties":{"type":{"$ref":"#/components/schemas/EventType"},"collection":{"type":"string","description":"Collection the documents belong to"},"user_id":{"type":"string","description":"Stable id of a signed-in user"},"session_id":{"type":"string","description":"Browsing session the event belongs to; required for session and co-visitation models"},"anonymous_id":{"type":"string","description":"Device or cookie id for users who are not signed in"},"query_id":{"type":"string","description":"Id of the search or recommendations response the user acted on, for attribution"},"doc_ids":{"type":"array","description":"Documents involved, in the order they were shown or bought","items":{"type":"string"}},"positions":{"type":"array","description":"1-based positions of `doc_ids` in the result list they were shown in","items":{"type":"integer"}},"q":{"type":"string","description":"Search text, for `search` events"},"found":{"type":"integer","description":"How many hits the search returned, for `search` events. Zero-hit queries are the input of `generateSynonymSuggestions` (source `events`), so report it when you can.\n"},"filter_by":{"type":"string","description":"Filter expression that was active"},"value":{"type":"number","description":"Total monetary value of the event in `currency`"},"currency":{"type":"string","description":"ISO 4217 currency code","example":"RUB"},"objects":{"type":"array","description":"Per-document price and quantity, for `add_to_cart` and `purchase`","items":{"$ref":"#/components/schemas/EventObject"}},"timestamp":{"type":"integer","x-fern-type":"long","description":"When the event happened, Unix time in milliseconds. Defaults to receipt time."},"analytics_tag":{"type":"string","description":"Free-form label to segment analytics (for example the surface the event came from)"},"event_id":{"type":"string","maxLength":128,"description":"Client-generated idempotency key (a UUID). A batch entry whose `event_id` was already stored for the organization is dropped and counted in `deduplicated` instead of stored twice.\n"},"schema_version":{"type":"integer","default":1,"description":"Version of this event shape; only `1` is accepted today."},"device":{"type":"string","maxLength":32,"description":"Device class the event came from (`desktop`, `mobile`, `tablet`), for breakdowns"},"country":{"type":"string","maxLength":8,"description":"ISO 3166-1 alpha-2 country of the visitor, for breakdowns"},"language":{"type":"string","maxLength":16,"description":"BCP 47 language tag of the visitor, for breakdowns"},"referrer":{"type":"string","maxLength":2048,"description":"Referrer URL of the page the event happened on"},"page":{"type":"string","maxLength":2048,"description":"URL or path of the page the event happened on"},"metadata":{"type":"object","additionalProperties":true,"description":"Free-form JSON, at most 2 KB serialized. `metadata.category` is read by the category breakdown.\n"}}},"EventsBatch":{"type":"object","required":["events"],"properties":{"events":{"type":"array","minItems":1,"maxItems":500,"items":{"$ref":"#/components/schemas/Event"}}}},"EventsAccepted":{"type":"object","required":["accepted","rejected"],"properties":{"accepted":{"type":"integer","description":"Number of events stored"},"deduplicated":{"type":"integer","description":"Entries dropped because their `event_id` was already stored (or repeated within the batch)"},"rejected":{"type":"array","description":"Events that failed validation, by index in the batch","items":{"type":"object","required":["index","reason"],"properties":{"index":{"type":"integer"},"reason":{"type":"string"}}}}}},"BrowserKeyRequest":{"type":"object","properties":{"expires_in_seconds":{"type":"integer","minimum":60,"maximum":604800,"default":604800,"description":"Lifetime of the key; capped at seven days."},"allowed_collections":{"type":"array","items":{"type":"string"},"maxItems":200,"description":"Collections the key may search; omitted — every collection the parent key may."},"allowed_origins":{"type":"array","items":{"type":"string"},"maxItems":200,"description":"Page origins (`scheme://host[:port]`, wildcard subdomain allowed) the key accepts requests from; omitted — any origin.\n"},"rate_limit_per_minute":{"type":"integer","minimum":1,"maximum":1000000,"description":"Requests per minute for this key across all visitors."},"user_token":{"type":"string","maxLength":200,"description":"Opaque visitor identifier echoed on the key (analytics, personalization); never a login."},"profile":{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,63}$","description":"Pins every search made with the key to this search profile (the key's collections must carry a profile of that name). Requests may not name a different profile, and the raw `query_by` / `sort_by` / `facet_by` parameters are refused. The parent key must be unbound or bound to the same profile.\n"}}},"BrowserKey":{"type":"object","required":["key","scope","expires_at","parent_key_id"],"properties":{"key":{"type":"string","description":"The `nssk_…` token to send as `X-NOVA-API-KEY` from the browser."},"scope":{"type":"string","enum":["search"]},"expires_at":{"type":"string","format":"date-time"},"parent_key_id":{"type":"string","description":"The full key the browser key derives from."}}},"Entitlement":{"type":"object","required":["plan","features","quota","credits"],"properties":{"plan":{"$ref":"#/components/schemas/EntitlementPlan"},"features":{"type":"array","description":"Capabilities the plan covers, by name — the integration hides the rest.","items":{"type":"string"},"example":["search","synonyms","curation","recommendations","assistants","voice","image_search"]},"quota":{"$ref":"#/components/schemas/EntitlementQuota"},"credits":{"$ref":"#/components/schemas/EntitlementCredits"},"suspended":{"type":"boolean","description":"The organization's API access is paused: every other operation answers 402 until the subscription payment is settled (`suspension_reason: payment`) or the owner resumes it (`manual`). Show the reason; do not retry.\n"},"suspension_reason":{"type":"string","enum":["payment","manual"]}}},"EntitlementPlan":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string","description":"Plan identifier, e.g. `free`, `pro`, `enterprise`."},"name":{"type":"string"},"status":{"type":"string","description":"`active` and `trialing` work; `past_due` still works but payment failed; `canceled` keeps working until `expires_at`; `expired` and `none` do not. An integration that treats anything other than `active`/`trialing` as \"read-only from now on\" is wrong — use `expires_at`.\n","enum":["none","trialing","active","past_due","canceled","expired"]},"expires_at":{"type":"integer","x-fern-type":"long","description":"When access ends, epoch milliseconds. Absent for a plan that does not end."},"trial_ends_at":{"type":"integer","x-fern-type":"long"},"cancel_at_period_end":{"type":"boolean","description":"Renewal is off; the plan ends at `expires_at`."},"days_left":{"type":"integer","description":"Whole days until `expires_at`, floored; absent when there is no end date."}}},"EntitlementQuota":{"type":"object","description":"Search requests for the current period. Exhausted quota answers 429.","required":["used","limit","remaining"],"properties":{"used":{"type":"integer"},"limit":{"type":"integer"},"remaining":{"type":"integer"},"exhausted":{"type":"boolean"},"resets_at":{"type":"integer","x-fern-type":"long","description":"When `used` returns to zero, epoch milliseconds — the subscription's period end, or the next calendar month on the free tier."}}},"EntitlementCredits":{"type":"object","description":"AI credits — what assistants, voice, image and semantic search spend. `reserved` is held by requests in flight and is already subtracted from `available`.\n","required":["balance","reserved","available"],"properties":{"balance":{"type":"integer"},"reserved":{"type":"integer"},"available":{"type":"integer"},"exhausted":{"type":"boolean","description":"Nothing left — AI operations answer 402 until the wallet is topped up."}}},"RecommendationModelType":{"type":"string","description":"`looking_similar`: nearest neighbours of a document in `vector_field`. `related_items`: documents viewed in the same sessions. `bought_together`: documents bought in the same sessions. `trending`: documents with the most recent weighted interactions. `session`: nearest neighbours of the average vector of what the session interacted with. `popular`: plain weighted counts over the window, no decay. `query_to_item`: documents clicked/bought within 10 minutes after searching `query` (exact match on normalized tokens, then prefix). `upsell`: same-category items priced above the anchor, up to `upsell_max_ratio` × its price, by popularity then vector similarity. `cross_sell` / `complementary`: items the product graph (`requires`/`bought_with` edges) and mined co-purchases link to the anchor; `complementary_only` drops the anchor's own category. `substitutes` / `alternatives`: same-category items within `price_tolerance` of the anchor's price, by vector similarity (`alternatives` defaults to a wider ±50% band). `recently_viewed`: what the subject (`user_id`/`anonymous_id`/`session_id`) last engaged with. `recently_searched`: the subject's recent queries, returned in `queries` rather than `hits`. `sequential`: next items, from A→B transitions counted within sessions, seeded by the anchors or the subject's last `sequence_length` items. `graph`: walks `edge_kinds` edges 1–`hops` hops from the anchors, scores multiplied by edge weight.\n","enum":["looking_similar","related_items","bought_together","trending","session","popular","query_to_item","upsell","cross_sell","complementary","substitutes","alternatives","recently_viewed","recently_searched","sequential","graph"]},"RecommendationBlend":{"type":"object","description":"Hybrid scoring for anchored models: candidates from each source are min-max normalized and combined with these weights. A source with weight 0 (or omitted) is not queried. Without `blend`, a model uses its own single source.\n","properties":{"behavioral":{"type":"number","minimum":0,"description":"Co-visitation / co-purchase evidence from events. Default 0.7."},"vector":{"type":"number","minimum":0,"description":"Nearest neighbours in `vector_field`. Default 0.3."},"graph":{"type":"number","minimum":0,"description":"Product-graph edges (`edge_kinds`). Default 0."}}},"RecommendationColdStart":{"type":"object","description":"What to serve when the model itself yields fewer than `min_results` candidates.","properties":{"fallback":{"type":"string","enum":["trending","popular","looking_similar","none"],"default":"none"},"min_results":{"type":"integer","minimum":1,"default":3}}},"RecommendationPin":{"type":"object","description":"Forces document `id` into `position` (0-based) of the returned hits — it is fetched and inserted even when the model did not produce it, subject to the model/request filters. When `filter_by` is set, the pin only applies to requests whose own `filter_by` contains it verbatim (e.g. `category:=shoes`).\n","required":["id","position"],"properties":{"id":{"type":"string"},"position":{"type":"integer","minimum":0},"filter_by":{"type":"string"}}},"RecommendationParams":{"type":"object","description":"Overrides an experiment variant applies to `getRecommendations` calls on the collection.","properties":{"model_id":{"type":"string","description":"Serve this model instead of the requested one."},"blend":{"$ref":"#/components/schemas/RecommendationBlend"},"k":{"type":"integer","minimum":1,"maximum":100,"description":"Overrides the request's `k`."}}},"RecommendationModelUpsertSchema":{"type":"object","required":["type"],"properties":{"type":{"$ref":"#/components/schemas/RecommendationModelType"},"vector_field":{"type":"string","description":"Vector field of the collection used by `looking_similar` and `session`"},"event_weights":{"type":"object","description":"Weight of each event type when scoring; unset types count 0","properties":{"view":{"type":"number"},"click":{"type":"number"},"add_to_cart":{"type":"number"},"purchase":{"type":"number"},"conversion":{"type":"number"}}},"decay_half_life_hours":{"type":"number","description":"For `trending`, hours after which an interaction counts half as much. Default 72."},"window_days":{"type":"integer","description":"Only events newer than this many days are used. Default 30."},"filter_by":{"type":"string","description":"Filter applied to every recommendation from this model"},"exclude_filter_by":{"type":"string","description":"Documents matching this filter are never recommended by this model (merchandising exclusion)."},"pins":{"type":"array","description":"Guaranteed placements in this model's results (see `RecommendationPin`).","items":{"$ref":"#/components/schemas/RecommendationPin"}},"blend":{"$ref":"#/components/schemas/RecommendationBlend"},"cold_start":{"$ref":"#/components/schemas/RecommendationColdStart"},"category_field":{"type":"string","description":"Field holding a document's category, for `upsell`, `cross_sell`/`complementary` and `substitutes`/`alternatives`."},"price_field":{"type":"string","description":"Numeric price field, for `upsell` and `substitutes`/`alternatives`. Default `price`."},"upsell_max_ratio":{"type":"number","minimum":1,"description":"For `upsell`, the highest price offered as a multiple of the anchor's. Default 2."},"price_tolerance":{"type":"number","minimum":0,"description":"For `substitutes`/`alternatives`, the accepted price band around the anchor's price as a fraction (0.3 = ±30%). Default 0.3 / 0.5."},"complementary_only":{"type":"boolean","description":"For `cross_sell`/`complementary`, drop candidates in the anchor's own category. Default true for `complementary`."},"edge_kinds":{"type":"array","description":"For `graph` and `cross_sell`, which product-graph edges to follow. Default `requires` and `bought_with`.","items":{"type":"string","enum":["requires","excludes","bought_with","category_map","consumption","related_to","part_of","mentions"]}},"hops":{"type":"integer","minimum":1,"maximum":2,"description":"For `graph`, how far to walk. Default 1."},"sequence_length":{"type":"integer","minimum":1,"maximum":10,"description":"For `sequential`, how many of the subject's latest items seed the transitions. Default 3."}}},"RecommendationModel":{"allOf":[{"$ref":"#/components/schemas/RecommendationModelUpsertSchema"},{"type":"object","required":["id","status"],"properties":{"id":{"type":"string"},"status":{"type":"string","description":"Whether the model can serve recommendations","enum":["ready","building","failed"]},"last_built_at":{"type":"integer","x-fern-type":"long","description":"Unix time in milliseconds of the last successful build, for models that are built offline"}}}]},"RecommendationModelsResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/RecommendationModel"}}}},"RecommendationModelDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Id of the deleted recommendation model"}}},"RecommendationsRequest":{"type":"object","required":["model_id"],"properties":{"model_id":{"type":"string"},"object_id":{"type":"string","description":"Anchor document for item-to-item models"},"object_ids":{"type":"array","description":"Several anchor documents; their recommendations are merged","items":{"type":"string"}},"user_id":{"type":"string"},"anonymous_id":{"type":"string","description":"Anonymous visitor id for personalization when `user_id` is absent (see the collection's personalization settings)"},"session_id":{"type":"string"},"query":{"type":"string","description":"The search query for `query_to_item`"},"k":{"type":"integer","description":"Number of recommendations to return","default":10,"minimum":1,"maximum":100},"filter_by":{"type":"string","description":"Additional filter, combined with the model's own `filter_by`"},"exclude_ids":{"type":"array","description":"Documents to leave out, for example items already in the cart","items":{"type":"string"}},"include_fields":{"type":"string","description":"Comma-separated list of fields to include in each hit's document"},"exclude_fields":{"type":"string","description":"Comma-separated list of fields to exclude from each hit's document"}}},"RecommendationsResponse":{"type":"object","required":["model_id","hits","took_ms"],"properties":{"model_id":{"type":"string"},"hits":{"type":"array","items":{"$ref":"#/components/schemas/SearchResultHit"}},"took_ms":{"type":"integer"},"queries":{"type":"array","description":"For `recently_searched` models, the subject's recent queries (newest first); `hits` is empty.","items":{"type":"string"}},"experiment":{"type":"string","description":"`<experimentId>:<variantId>` of the running experiment(s) this request was enrolled in, when any."}}},"TranscriptionRequest":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Audio clip (webm, mp4, m4a, ogg, wav, mp3 or flac; up to 25 MB)"},"language":{"type":"string","description":"ISO 639-1 code of the spoken language; detected when omitted","example":"ru"},"model":{"type":"string","description":"Speech model","enum":["whisper-large-v3-turbo","whisper"],"default":"whisper-large-v3-turbo"}}},"VoiceSearchRequest":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"Audio clip (webm, mp4, m4a, ogg, wav, mp3 or flac; up to 25 MB)"},"language":{"type":"string","description":"ISO 639-1 code of the spoken language; detected when omitted","example":"ru"},"params":{"type":"string","description":"JSON object of search parameters applied to the transcribed query, e.g. `{\"query_by\":\"title\",\"nl_query\":true}`","example":"{\"query_by\":\"title\"}"}}},"TranscriptionSegment":{"type":"object","required":["start_ms","end_ms","text"],"properties":{"start_ms":{"type":"integer"},"end_ms":{"type":"integer"},"text":{"type":"string"}}},"Transcription":{"type":"object","required":["text"],"properties":{"text":{"type":"string","description":"Full transcript"},"language":{"type":"string","description":"Detected or requested language, ISO 639-1"},"duration_ms":{"type":"integer","description":"Length of the audio in milliseconds"},"segments":{"type":"array","items":{"$ref":"#/components/schemas/TranscriptionSegment"}},"model":{"type":"string","description":"Speech model that produced the transcript"}}},"AssistantCollection":{"type":"object","required":["name","query_by"],"properties":{"name":{"type":"string","description":"Collection to retrieve from"},"query_by":{"type":"string","description":"Comma-separated fields to search; add an auto-embedding field for hybrid retrieval"},"filter_by":{"type":"string","description":"Filter applied to every retrieval from this collection"},"k":{"type":"integer","description":"Documents handed to the model from this collection","default":5,"minimum":1,"maximum":20},"include_fields":{"type":"string","description":"Comma-separated fields the model sees and that are returned in `sources`"},"exclude_fields":{"type":"string","description":"Comma-separated fields hidden from the model (vectors, internal ids)"}}},"ModelRole":{"type":"string","description":"What a catalog model is used for. `chat` — assistant answers and conversation; `embedding` — text/image vectors; `vision` — image understanding; `rerank` — cross-encoder re-ranking of search hits; `speller` — query-suggestion candidates; `query_rewrite` — assistant retrieval query rewriting; `graph_extract` — GraphRAG entity and claim extraction; `graph_map` / `graph_reduce` — GraphRAG global search map-reduce; `asr` — speech-to-text for voice search; `conversation` — engine-side conversational and NL-search models (`conversations/models`, `nl_search_models`).\n","enum":["chat","embedding","vision","rerank","speller","query_rewrite","graph_extract","graph_map","graph_reduce","asr","conversation"]},"ModelCatalogEntry":{"type":"object","required":["id","role","model_id","provider","is_default","enabled"],"properties":{"id":{"type":"string","description":"Catalog entry id (not the provider model id)"},"role":{"$ref":"#/components/schemas/ModelRole"},"model_id":{"type":"string","description":"Provider-prefixed model id, e.g. `@cf/meta/llama-3.3-70b-instruct-fp8-fast`"},"provider":{"type":"string","description":"Model provider, currently always `workers_ai`"},"label":{"type":"string","nullable":true,"description":"Human label for the console picker"},"description":{"type":"string","nullable":true},"is_default":{"type":"boolean","description":"The model this role resolves to. At most one per role."},"enabled":{"type":"boolean","description":"A disabled entry can neither be selected by a tenant nor resolved"},"notes":{"type":"string","nullable":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"ModelCatalogUpsertSchema":{"type":"object","required":["role","model_id"],"properties":{"role":{"$ref":"#/components/schemas/ModelRole"},"model_id":{"type":"string","minLength":1,"maxLength":200,"description":"Provider-prefixed model id"},"provider":{"type":"string","default":"workers_ai"},"label":{"type":"string","maxLength":200},"description":{"type":"string","maxLength":2000},"is_default":{"type":"boolean","default":false,"description":"Promote to the role's default, demoting the previous one"},"enabled":{"type":"boolean","default":true},"notes":{"type":"string","maxLength":2000}}},"ModelCatalogUpdateSchema":{"type":"object","properties":{"role":{"$ref":"#/components/schemas/ModelRole"},"provider_model_id":{"type":"string","minLength":1,"maxLength":200,"description":"Provider-prefixed model id (the entry's own id stays the path parameter)"},"provider":{"type":"string"},"label":{"type":"string","maxLength":200,"nullable":true},"description":{"type":"string","maxLength":2000,"nullable":true},"is_default":{"type":"boolean"},"enabled":{"type":"boolean"},"notes":{"type":"string","maxLength":2000,"nullable":true}}},"ModelCatalogResponse":{"type":"object","required":["models"],"properties":{"models":{"type":"array","items":{"$ref":"#/components/schemas/ModelCatalogEntry"}}}},"ModelsResolvedResponse":{"type":"object","required":["roles"],"properties":{"roles":{"type":"array","description":"One entry per role, in the contract's role order","items":{"type":"object","required":["role","model","source","candidates"],"properties":{"role":{"$ref":"#/components/schemas/ModelRole"},"model":{"type":"string","description":"The model id the role currently runs"},"source":{"type":"string","enum":["default","fallback"],"description":"`default` when a catalog entry with `is_default` set chose it; `fallback` when the role runs the platform's built-in model.\n"},"candidates":{"type":"array","description":"Enabled catalog model ids for this role, for the picker","items":{"type":"string"}}}}}}},"ModelDeleted":{"type":"object","required":["deleted","id"],"properties":{"deleted":{"type":"boolean"},"id":{"type":"string"}}},"AssistantModel":{"type":"object","properties":{"provider":{"type":"string","enum":["workers_ai"],"default":"workers_ai"},"name":{"type":"string","description":"Model id at the provider. Must be a model the platform's catalog offers for the `chat` role; when the catalog lists none, any id is accepted (pre-catalog behaviour) unless the platform runs with `MODEL_CATALOG_STRICT`, which refuses.\n","default":"@cf/meta/llama-3.3-70b-instruct-fp8-fast"},"temperature":{"type":"number","minimum":0,"maximum":2},"max_output_tokens":{"type":"integer","minimum":1,"maximum":4096}}},"AssistantUpsertSchema":{"type":"object","required":["name","collections"],"properties":{"name":{"type":"string"},"collections":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/AssistantCollection"}},"model":{"$ref":"#/components/schemas/AssistantModel"},"system_prompt":{"type":"string","description":"Instructions prepended to every conversation"},"memory_ttl_seconds":{"type":"integer","description":"How long a conversation can be continued. Default 86400.","minimum":60},"max_sources":{"type":"integer","description":"Upper bound on documents handed to the model per answer, across collections. Default 5.","minimum":1,"maximum":40},"retrieval_mode":{"$ref":"#/components/schemas/AssistantRetrievalMode"}}},"AssistantRetrievalMode":{"type":"string","enum":["single","agentic"],"default":"single","description":"How retrieval runs before the answer. `single` rewrites the question once and searches. `agentic` may run one extra keyword search when the first sources look incomplete (higher latency and AI credit use). Default `single`.\n"},"Assistant":{"allOf":[{"$ref":"#/components/schemas/AssistantUpsertSchema"},{"type":"object","required":["id","created_at","updated_at"],"properties":{"id":{"type":"string"},"created_at":{"type":"integer","x-fern-type":"long","description":"Unix time in milliseconds"},"updated_at":{"type":"integer","x-fern-type":"long","description":"Unix time in milliseconds"}}}]},"AssistantsResponse":{"type":"object","required":["assistants"],"properties":{"assistants":{"type":"array","items":{"$ref":"#/components/schemas/Assistant"}}}},"ConnectorProvider":{"type":"string","enum":["bitrix","bitrix24","prestashop","woocommerce","yml","sitemap","custom"]},"ConnectorSyncMode":{"type":"string","enum":["push","pull"],"default":"push"},"ConnectorStatus":{"type":"string","enum":["idle","syncing","error","paused"]},"ConnectorCms":{"type":"string","description":"CMS platforms that ship a connector module (feeds and crawlers do not handshake)","enum":["bitrix","bitrix24","prestashop","woocommerce"]},"ConnectorSku":{"type":"string","description":"Marketplace edition the CMS module runs as. Narrows the capability set; the cloud plan is the ceiling.","enum":["site","shop","b2b","enterprise"]},"ConnectorCapability":{"type":"string","description":"What a connector can provide. `full_export` — initial catalogue load; `events` — incremental change events (webhook / outbox); `seo_facets` — SEO facet landing pages; `sku_join` — trade offers (SKU) joined to their parent products; `b2b_prices` — per-user-group B2B prices and rights-based hidden hits.\n","enum":["events","full_export","seo_facets","b2b_prices","sku_join"]},"ConnectorHandshakeSchema":{"type":"object","required":["cms","version","sku","capabilities"],"properties":{"cms":{"$ref":"#/components/schemas/ConnectorCms"},"version":{"type":"string","description":"CMS module version","example":"1.8.0"},"sku":{"$ref":"#/components/schemas/ConnectorSku"},"capabilities":{"type":"array","description":"Capabilities the module can provide on this installation","uniqueItems":true,"maxItems":5,"items":{"$ref":"#/components/schemas/ConnectorCapability"},"example":["full_export","events","sku_join"]}}},"ConnectorHandshakeDenial":{"type":"object","required":["capability","reason"],"properties":{"capability":{"$ref":"#/components/schemas/ConnectorCapability"},"reason":{"type":"string","description":"`not_declared` — allowed here but the module did not declare it; `sku` — outside the declared edition; `plan` — above the organization's cloud plan.\n","enum":["not_declared","sku","plan"]},"requires":{"type":"string","description":"Minimum plan identifier (`EntitlementPlan.id`, for `plan`) or edition (for `sku`) that would grant the capability\n","example":"pro"}}},"ConnectorHandshakeRefused":{"type":"object","description":"403 body when the declared SKU cannot run on the organization's plan at all","required":["message","data"],"properties":{"message":{"type":"string","example":"SKU 'shop' requires at least the starter plan; the organization is on free."},"data":{"type":"object","required":["sku","plan"],"properties":{"sku":{"$ref":"#/components/schemas/ConnectorSku"},"plan":{"type":"string","description":"The organization's current plan identifier (`EntitlementPlan.id`)","example":"free"}}}}},"ConnectorHandshakeResponse":{"type":"object","required":["plan","sku","effective","denied"],"properties":{"plan":{"type":"string","description":"The organization's current plan identifier (`EntitlementPlan.id`)","example":"starter"},"sku":{"$ref":"#/components/schemas/ConnectorSku"},"effective":{"type":"array","description":"Capabilities to switch on — declared ∩ SKU ∩ plan","items":{"$ref":"#/components/schemas/ConnectorCapability"},"example":["full_export","events"]},"denied":{"type":"array","items":{"$ref":"#/components/schemas/ConnectorHandshakeDenial"},"example":[{"capability":"sku_join","reason":"plan","requires":"pro"}]}}},"ConnectorCreateSchema":{"type":"object","required":["name","collection"],"properties":{"name":{"type":"string"},"collection":{"type":"string","description":"Target collection name (without tenant prefix)"},"provider":{"$ref":"#/components/schemas/ConnectorProvider"},"sync_mode":{"$ref":"#/components/schemas/ConnectorSyncMode"},"schedule_cron":{"type":"string","description":"Cron expression matching a Worker trigger (`*/15 * * * *` or `0 3 * * *`). Empty = every */15 pull tick."},"pull_url":{"type":"string","description":"Shop journal URL for pull mode"},"pull_token":{"type":"string","description":"Bearer token for pull_url (not the API key)"},"enabled":{"type":"boolean","default":true}}},"ConnectorUpdateSchema":{"type":"object","properties":{"name":{"type":"string"},"sync_mode":{"$ref":"#/components/schemas/ConnectorSyncMode"},"schedule_cron":{"type":"string","nullable":true},"pull_url":{"type":"string","nullable":true},"pull_token":{"type":"string","nullable":true},"enabled":{"type":"boolean"}}},"Connector":{"type":"object","required":["id","name","collection","provider","sync_mode","status","enabled","secret_preview","pull_token_set","created_at","updated_at"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"collection":{"type":"string"},"provider":{"$ref":"#/components/schemas/ConnectorProvider"},"sync_mode":{"$ref":"#/components/schemas/ConnectorSyncMode"},"schedule_cron":{"type":"string","nullable":true},"pull_url":{"type":"string","nullable":true},"pull_token_set":{"type":"boolean","description":"Whether a pull_token is stored (token itself is never returned)"},"status":{"$ref":"#/components/schemas/ConnectorStatus"},"last_sync_at":{"type":"integer","x-fern-type":"long","nullable":true},"last_error":{"type":"string","nullable":true},"enabled":{"type":"boolean"},"secret_preview":{"type":"string"},"created_at":{"type":"integer","x-fern-type":"long"},"updated_at":{"type":"integer","x-fern-type":"long"}}},"ConnectorWithSecret":{"allOf":[{"$ref":"#/components/schemas/Connector"},{"type":"object","required":["secret"],"properties":{"secret":{"type":"string","description":"Signing secret — shown only on create"}}}]},"ConnectorsResponse":{"type":"object","required":["connectors"],"properties":{"connectors":{"type":"array","items":{"$ref":"#/components/schemas/Connector"}}}},"ConnectorDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"ConnectorWebhookBody":{"description":"One event or a batch. Each event may reserve event_id (a stable string up to 128 characters) and source_revision (a nonnegative safe integer, increasing per source document, including deletions). Repeated or older revisions are ignored; an unversioned event cannot overwrite an already versioned document. These metadata fields are not indexed as document attributes.\n","oneOf":[{"type":"object","additionalProperties":true},{"type":"object","required":["events"],"properties":{"events":{"type":"array","items":{"type":"object","additionalProperties":true}}}}]},"ConnectorWebhookResponse":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"received":{"type":"integer"},"upserted":{"type":"integer"},"deleted":{"type":"integer"},"job_id":{"type":"string"}}}}},"ConnectorJob":{"type":"object","required":["id","connector_id","kind","status","created_at","updated_at"],"properties":{"id":{"type":"string"},"connector_id":{"type":"string"},"kind":{"type":"string","enum":["ingest_batch","full_reindex","pull"]},"status":{"type":"string","enum":["queued","processing","ready","error"]},"stats":{"type":"object","additionalProperties":true,"nullable":true},"error":{"type":"string","nullable":true},"created_at":{"type":"integer","x-fern-type":"long"},"updated_at":{"type":"integer","x-fern-type":"long"},"finished_at":{"type":"integer","x-fern-type":"long","nullable":true}}},"ConnectorJobsResponse":{"type":"object","required":["jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/ConnectorJob"}}}},"ConnectorDocument":{"type":"object","required":["id","external_id","document_id","deleted","updated_at"],"properties":{"id":{"type":"string"},"external_id":{"type":"string"},"document_id":{"type":"string"},"deleted":{"type":"boolean"},"updated_at":{"type":"integer","x-fern-type":"long"}}},"ConnectorDocumentsResponse":{"type":"object","required":["documents","found"],"properties":{"documents":{"type":"array","items":{"$ref":"#/components/schemas/ConnectorDocument"}},"found":{"type":"integer"}}},"IngestJobSource":{"type":"string","description":"`url`, `sitemap`, `yml` and `youtube` fetch `url`; `documents` takes inline JSON documents; `markdown`, `csv` and `html` take the text itself in `content` — one document per heading section, per row, or for the page. `yml` also accepts a small feed in `content`, or a feed file through `uploadIngestFeed`; a feed of any size is imported in resumable passes, one document per `<offer>`. `reindex` (created by `reindexCollection`, not by `createIngestJob`) exports every document of the collection from the engine and imports it back.\n","enum":["url","sitemap","yml","youtube","documents","markdown","csv","html","reindex"]},"IngestJobStatus":{"type":"string","enum":["queued","processing","ready","failed"]},"IngestJobAction":{"type":"string","enum":["upsert","create","update","emplace"],"default":"upsert"},"DatasetFieldRole":{"type":"string","enum":["id","title","text","url","image","category","price","date","boolean","unknown"]},"IngestPreviewRequest":{"type":"object","example":{"source":"documents","documents":[{"id":"example-1","title":"Example document"}]},"required":["source"],"properties":{"source":{"type":"string","enum":["documents","markdown","csv","html"]},"documents":{"type":"array","minItems":1,"maxItems":100,"items":{"type":"object","additionalProperties":true}},"content":{"type":"string","maxLength":2097152},"source_name":{"type":"string","maxLength":1024},"total_count":{"type":"integer","minimum":1,"description":"Known source size, if available; must not be smaller than the sample."},"roles":{"type":"object","maxProperties":200,"additionalProperties":{"$ref":"#/components/schemas/DatasetFieldRole"},"description":"Explicit roles keyed by observed field path; unknown disables an inferred role."}}},"FieldProfile":{"type":"object","required":["name","types","present_count","null_count","coverage","role","role_source","reasons"],"properties":{"name":{"type":"string"},"types":{"type":"array","items":{"type":"string"},"description":"Observed scalar or array types; multiple types indicate a conflict."},"present_count":{"type":"integer"},"null_count":{"type":"integer"},"coverage":{"type":"number","minimum":0,"maximum":1},"role":{"$ref":"#/components/schemas/DatasetFieldRole"},"role_source":{"type":"string","enum":["inferred","explicit"]},"reasons":{"type":"array","items":{"type":"string"}}}},"DatasetProfile":{"type":"object","required":["version","sample_count","truncated","fields","domain_candidates","warnings"],"properties":{"version":{"type":"integer","enum":[1]},"sample_count":{"type":"integer"},"total_count":{"type":"integer","description":"Omitted when the full source size is unknown."},"truncated":{"type":"boolean"},"fields":{"type":"array","items":{"$ref":"#/components/schemas/FieldProfile"}},"domain_candidates":{"type":"array","items":{"type":"string","enum":["commerce","content","knowledge","generic"]}},"warnings":{"type":"array","items":{"type":"string"}}}},"CapabilityAssessment":{"type":"object","required":["id","data","configuration","entitlement","verification","reasons"],"properties":{"id":{"type":"string","enum":["keyword_search","facets","semantic_search","image_search","assistant","recommendations"]},"data":{"type":"string","enum":["candidate","insufficient"]},"configuration":{"type":"string","enum":["unknown"]},"entitlement":{"type":"string","enum":["unknown"]},"verification":{"type":"string","enum":["unverified"]},"reasons":{"type":"array","items":{"type":"string"}}}},"MappingProposal":{"type":"object","required":["fields","query_by","roles","enable_nested_fields","conflicts"],"properties":{"fields":{"type":"array","items":{"$ref":"#/components/schemas/Field"}},"query_by":{"type":"array","items":{"type":"string"}},"roles":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/DatasetFieldRole"}},"enable_nested_fields":{"type":"boolean"},"conflicts":{"type":"array","items":{"type":"string"}}}},"IngestPreviewResponse":{"type":"object","required":["profile","proposal","capabilities"],"properties":{"profile":{"$ref":"#/components/schemas/DatasetProfile"},"proposal":{"$ref":"#/components/schemas/MappingProposal"},"capabilities":{"type":"array","items":{"$ref":"#/components/schemas/CapabilityAssessment"}}}},"IngestJobCreateSchema":{"type":"object","required":["collection","source"],"properties":{"name":{"type":"string","description":"Optional label shown in the console"},"collection":{"type":"string","description":"Target collection (without tenant prefix)"},"source":{"$ref":"#/components/schemas/IngestJobSource"},"url":{"type":"string","description":"Required for url, sitemap, youtube; for yml unless `content` is given"},"max_pages":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"Pages to fetch for url / sitemap. Not applied to yml — a feed is imported whole."},"action":{"$ref":"#/components/schemas/IngestJobAction"},"documents":{"type":"array","description":"Inline documents for source=documents (each needs id)","maxItems":100,"items":{"type":"object","additionalProperties":true,"required":["id"],"properties":{"id":{"type":"string"}}}},"content":{"type":"string","maxLength":2097152,"description":"The text for source=markdown, csv, html or yml (at most 2 MB). Markdown becomes one document per heading section (`title`, `heading`, `heading_path`, `text`); CSV one per row, the header naming the fields, an `id` column used as the document id, numbers and booleans typed, `a|b` cells as lists; HTML one page document, the same shape the `url` source builds; YML one document per offer (larger feeds: `uploadIngestFeed` or `url`).\n"},"source_name":{"type":"string","maxLength":2048,"description":"Where `content` came from (a file name, a URL) — the base of generated document ids, so re-ingesting the same source upserts."},"field_mapping":{"type":"object","description":"For text sources, renames fields on the way in (source field → collection field, for example `text` → `content`); an empty target drops the field.\n","additionalProperties":{"type":"string"}}}},"IngestJobStats":{"type":"object","required":["fetched","imported","failed","errors"],"properties":{"fetched":{"type":"integer"},"imported":{"type":"integer"},"failed":{"type":"integer"},"cursor":{"type":"integer","description":"yml jobs — offers consumed from the feed so far (the resume point while `processing`)"},"passes":{"type":"integer","description":"yml jobs — passes made over the feed"},"errors":{"type":"array","items":{"type":"object","required":["id","error"],"properties":{"id":{"type":"string"},"error":{"type":"string"}}}}}},"IngestJob":{"type":"object","required":["id","name","collection","source","status","config","stats","created_at","updated_at"],"properties":{"id":{"type":"string"},"name":{"type":"string"},"collection":{"type":"string"},"source":{"$ref":"#/components/schemas/IngestJobSource"},"status":{"$ref":"#/components/schemas/IngestJobStatus"},"config":{"type":"object","additionalProperties":true},"stats":{"$ref":"#/components/schemas/IngestJobStats"},"error":{"type":"string","nullable":true},"created_at":{"type":"integer","x-fern-type":"long"},"updated_at":{"type":"integer","x-fern-type":"long"},"finished_at":{"type":"integer","x-fern-type":"long","nullable":true}}},"IngestJobsResponse":{"type":"object","required":["jobs"],"properties":{"jobs":{"type":"array","items":{"$ref":"#/components/schemas/IngestJob"}}}},"IngestJobDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"AssistantDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"ChatMessage":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","enum":["system","user","assistant"]},"content":{"type":"string"}}},"ChatRequest":{"type":"object","required":["messages"],"properties":{"messages":{"type":"array","minItems":1,"description":"New messages for this turn; earlier turns are loaded from `conversation_id`","items":{"$ref":"#/components/schemas/ChatMessage"}},"conversation_id":{"type":"string","description":"Continue an existing conversation"},"user_id":{"type":"string","description":"Your id of the end user, for analytics"},"filter_by":{"type":"string","description":"Extra filter for this turn's retrieval, combined with each collection's own"},"max_sources":{"type":"integer","minimum":1,"maximum":40},"retrieval_mode":{"$ref":"#/components/schemas/AssistantRetrievalMode","description":"Override the assistant's retrieval mode for this turn only"}}},"ChatSource":{"type":"object","required":["collection","document"],"properties":{"collection":{"type":"string"},"document":{"type":"object","additionalProperties":true},"score":{"type":"number","description":"Retrieval score (text match, or rank-fusion score for hybrid retrieval)"},"snippet":{"type":"string","description":"Highlighted fragment that matched the question"}}},"ChatUsage":{"type":"object","required":["input_tokens","output_tokens"],"properties":{"input_tokens":{"type":"integer"},"output_tokens":{"type":"integer"}}},"ChatCompletion":{"type":"object","required":["id","conversation_id","message","sources","model"],"properties":{"id":{"type":"string"},"conversation_id":{"type":"string"},"message":{"$ref":"#/components/schemas/ChatMessage"},"sources":{"type":"array","description":"Documents the answer was based on, in the order the model saw them ([1], [2], …)","items":{"$ref":"#/components/schemas/ChatSource"}},"usage":{"$ref":"#/components/schemas/ChatUsage"},"model":{"type":"string"}}},"ChatChunk":{"type":"object","required":["type"],"properties":{"type":{"type":"string","enum":["sources","delta","usage","done","error"]},"conversation_id":{"type":"string","description":"Sent with `sources` and `done`"},"sources":{"type":"array","items":{"$ref":"#/components/schemas/ChatSource"}},"delta":{"type":"string","description":"Next fragment of the answer"},"usage":{"$ref":"#/components/schemas/ChatUsage"},"message":{"type":"string","description":"Error description for `error` chunks"}}},"Conversation":{"type":"object","required":["id","assistant_id","messages","created_at","expires_at"],"properties":{"id":{"type":"string"},"assistant_id":{"type":"string"},"messages":{"type":"array","items":{"$ref":"#/components/schemas/ChatMessage"}},"created_at":{"type":"integer","x-fern-type":"long"},"expires_at":{"type":"integer","x-fern-type":"long"}}},"ConversationDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SupportMessage":{"type":"object","required":["id","sender","body","created_at"],"properties":{"id":{"type":"integer","x-fern-type":"long"},"sender":{"type":"string","enum":["visitor","owner"]},"body":{"type":"string"},"created_at":{"type":"integer","x-fern-type":"long"}}},"SupportThread":{"type":"object","required":["id","status","messages","created_at","updated_at"],"properties":{"id":{"type":"string"},"subject":{"type":"string"},"status":{"type":"string","enum":["open","closed"]},"messages":{"type":"array","items":{"$ref":"#/components/schemas/SupportMessage"}},"created_at":{"type":"integer","x-fern-type":"long"},"updated_at":{"type":"integer","x-fern-type":"long"}}},"SupportThreadCreateSchema":{"type":"object","required":["message"],"properties":{"subject":{"type":"string"},"message":{"type":"string","minLength":1}}},"SupportMessageCreateSchema":{"type":"object","required":["message"],"properties":{"message":{"type":"string","minLength":1}}},"MediaUploadRequest":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"PNG, JPEG, WebP or GIF, up to 8 MB"},"collection":{"type":"string","description":"Collection whose document receives the embedding"},"document_id":{"type":"string","description":"Document to write the embedding into"},"vector_field":{"type":"string","description":"`float[]` field with `num_dim: 1024` that receives the embedding"},"caption_field":{"type":"string","description":"Optional string field that receives the generated description"}}},"MediaEmbedding":{"type":"object","required":["status"],"properties":{"status":{"type":"string","enum":["pending","ready","failed"]},"model":{"type":"string"},"num_dim":{"type":"integer"},"error":{"type":"string","description":"Why embedding failed, for `failed`"}}},"MediaUploadCreateSchema":{"type":"object","required":["mime"],"properties":{"mime":{"type":"string","description":"Content type the bytes will have","enum":["image/png","image/jpeg","image/webp","image/gif"]},"collection":{"type":"string"},"document_id":{"type":"string"},"vector_field":{"type":"string"},"caption_field":{"type":"string"}}},"SignedUrlRequest":{"type":"object","properties":{"expires_in_seconds":{"type":"integer","description":"Lifetime of the URL. Default 3600, at most 604800 (7 days).","minimum":60,"maximum":604800}}},"MediaSignedUrl":{"type":"object","required":["url","expires_at"],"properties":{"url":{"type":"string"},"expires_at":{"type":"integer","x-fern-type":"long"}}},"ExperimentVariant":{"type":"object","required":["id","search_params"],"properties":{"id":{"type":"string","description":"Short identifier, letters/digits/_/-; unique within the experiment","example":"control"},"name":{"type":"string"},"weight":{"type":"number","description":"Relative share of enrolled sessions. Default 1.","minimum":0},"search_params":{"type":"object","description":"Search parameters merged over the request for sessions in this variant, e.g. `{\"sort_by\": \"popularity:desc,_text_match:desc\"}` or `{\"preset\": \"promo\"}`. Empty for the control variant.\n","additionalProperties":true},"recommendation_params":{"$ref":"#/components/schemas/RecommendationParams"}}},"ExperimentUpsertSchema":{"type":"object","required":["name","collection","variants"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"collection":{"type":"string","description":"Collection whose searches take part"},"traffic":{"type":"number","description":"Share of sessions enrolled at all (the rest get the untouched request). Default 1.","minimum":0,"maximum":1},"variants":{"type":"array","minItems":2,"items":{"$ref":"#/components/schemas/ExperimentVariant"}}}},"ExperimentPromoteSchema":{"type":"object","required":["variant_id"],"properties":{"variant_id":{"type":"string","description":"Id of the configured variant to serve to all traffic from now on."}}},"SynonymSuggestionsGenerateSchema":{"type":"object","properties":{"queries":{"type":"array","description":"Examine exactly these queries instead of collecting zero-hit ones.","items":{"type":"string"},"maxItems":20},"source":{"type":"string","description":"Where zero-hit queries come from when `queries` is absent: `events` — your `search` events with `found: 0` in the last `days`, most frequent first; `analytics` — the destination collection of a `nohits_queries` analytics rule (`nohits_collection`).\n","enum":["events","analytics"],"default":"events"},"nohits_collection":{"type":"string","description":"Destination collection of the `nohits_queries` analytics rule (source `analytics`)."},"days":{"type":"integer","description":"Look-back window for source `events`. Defaults to 30.","default":30,"minimum":1,"maximum":365},"limit":{"type":"integer","description":"Zero-hit queries to examine in this call. Defaults to 10.","default":10,"minimum":1,"maximum":20},"query_by":{"type":"string","description":"Fields to verify candidates against, comma-separated. Defaults to every string field of the collection.\n"},"synonym_set":{"type":"string","description":"Synonym set accepted suggestions go to. Defaults to `suggested`.","default":"suggested"},"use_llm":{"type":"boolean","description":"Also ask a language model for spelling fixes, brand spellings and synonyms.","default":true},"model":{"type":"string","description":"Workers AI text model for the LLM pass. Defaults to a small fast instruct model."}}},"SynonymSuggestion":{"type":"object","required":["id","collection","query","term","kind","found","synonym_set","status","created_at"],"properties":{"id":{"type":"string"},"collection":{"type":"string"},"query":{"type":"string","description":"The zero-hit query as shoppers typed it."},"term":{"type":"string","description":"What the catalogue actually contains for it — the tokens the engine matched when the candidate was verified (`dewalt` for `девольт`).\n"},"candidate":{"type":"string","description":"The rewrite or model output that led to `term`, when it differs from it."},"kind":{"type":"string","description":"How the candidate was produced.","enum":["layout","translit","homoglyph","llm"]},"found":{"type":"integer","description":"Documents the verification search found for the candidate."},"sample_titles":{"type":"array","description":"Up to three values of the first `query_by` field from the verification hits.","items":{"type":"string"}},"occurrences":{"type":"integer","description":"How many times the zero-hit query was seen in the source."},"synonym_set":{"type":"string"},"status":{"type":"string","enum":["pending","accepted","rejected"]},"synonym_item_id":{"type":"string","description":"Id of the synonym item written on acceptance (`sug_<id>`)."},"created_at":{"type":"integer","x-fern-type":"long"},"decided_at":{"type":"integer","x-fern-type":"long"}}},"SynonymSuggestionsResponse":{"type":"object","required":["suggestions"],"properties":{"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/SynonymSuggestion"}},"examined":{"type":"integer","description":"Zero-hit queries looked at by this `generate` call."},"skipped":{"type":"array","description":"Queries examined without a new suggestion, with the reason.","items":{"type":"object","required":["query","reason"],"properties":{"query":{"type":"string"},"reason":{"type":"string","enum":["has_hits","no_candidates","nothing_found","already_suggested"]}}}}}},"SynonymSuggestionAcceptSchema":{"type":"object","properties":{"synonym_set":{"type":"string","description":"Write the synonym into this set instead of the suggestion's own."}}},"SynonymSuggestionDeleteResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"GraphEntity":{"type":"object","required":["id","collection","name","type","source_doc_ids","created_at","updated_at"],"properties":{"id":{"type":"string"},"collection":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","description":"Free-form, model-assigned (e.g. \"product\", \"brand\", \"concept\")."},"description":{"type":"string"},"aliases":{"type":"array","description":"Other surface forms of this entity folded in by semantic deduplication (e.g. \"De Walt\" merged into \"DeWalt\").","items":{"type":"string"}},"source_doc_ids":{"type":"array","description":"Document ids this entity was mentioned in.","items":{"type":"string"}},"community_id":{"type":"string","description":"Set once a `generateGraphCommunities` run groups this entity."},"created_at":{"type":"integer","x-fern-type":"long"},"updated_at":{"type":"integer","x-fern-type":"long"}}},"GraphEntitiesResponse":{"type":"object","required":["entities"],"properties":{"entities":{"type":"array","items":{"$ref":"#/components/schemas/GraphEntity"}}}},"GraphEntitiesGenerateSchema":{"type":"object","required":["document_ids","text_fields"],"properties":{"document_ids":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"string"}},"text_fields":{"type":"array","minItems":1,"description":"Which of the collection's string fields hold the text to extract entities and relations from.","items":{"type":"string"}},"model":{"type":"string","description":"Override the extraction model."}}},"GraphEntitiesGenerateResponse":{"type":"object","required":["examined","entities_created","entities_updated","edges_created","claims_created","entities","claims"],"properties":{"examined":{"type":"integer"},"entities_created":{"type":"integer"},"entities_updated":{"type":"integer"},"edges_created":{"type":"integer"},"claims_created":{"type":"integer","description":"New claims about these entities extracted this run — see `GraphClaim`."},"entities":{"type":"array","items":{"$ref":"#/components/schemas/GraphEntity"}},"claims":{"type":"array","items":{"$ref":"#/components/schemas/GraphClaim"}}}},"GraphEntityDeleteResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"GraphClaim":{"type":"object","required":["id","collection","subject_id","claim_type","status","description","source_doc_id","created_at"],"properties":{"id":{"type":"string"},"collection":{"type":"string"},"subject_id":{"type":"string","description":"The `GraphEntity.id` this claim is about."},"claim_type":{"type":"string","description":"Free-form, model-assigned (e.g. \"capability\", \"certification\", \"compatibility\", \"limitation\", \"pricing\")."},"object":{"type":"string","description":"What/who the claim relates the subject to, when there is one."},"status":{"type":"string","enum":["confirmed","suspected","disputed","unverified"],"description":"How certain the source text itself is about the claim, not the model's confidence."},"description":{"type":"string"},"source_doc_id":{"type":"string"},"created_at":{"type":"integer","x-fern-type":"long"}}},"GraphClaimsResponse":{"type":"object","required":["claims"],"properties":{"claims":{"type":"array","items":{"$ref":"#/components/schemas/GraphClaim"}}}},"GraphClaimDeleteResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"GraphCommunity":{"type":"object","required":["id","collection","title","summary","entity_ids","level","created_at"],"properties":{"id":{"type":"string"},"collection":{"type":"string"},"title":{"type":"string"},"summary":{"type":"string"},"entity_ids":{"type":"array","items":{"type":"string"}},"level":{"type":"integer","description":"0 is the finest grouping; each higher level is a coarser merge of level-(N-1) communities."},"parent_id":{"type":"string","description":"The level-(N+1) community this one was merged into during the next coarsening pass. Unset at the coarsest level reached."},"created_at":{"type":"integer","x-fern-type":"long"}}},"GraphCommunitiesResponse":{"type":"object","required":["communities"],"properties":{"communities":{"type":"array","items":{"$ref":"#/components/schemas/GraphCommunity"}}}},"GraphCommunitiesGenerateSchema":{"type":"object","properties":{"min_size":{"type":"integer","minimum":2,"default":2,"description":"Smallest connected group of entities worth summarizing into a report, at every level."},"max_levels":{"type":"integer","minimum":1,"maximum":5,"default":3,"description":"How many levels of the community hierarchy to build at most (0 finest). Clustering stops earlier on its own once a pass merges nothing further.\n"},"model":{"type":"string","description":"Override the summarization model."}}},"GraphCommunitiesGenerateResponse":{"type":"object","required":["communities_created","entities_grouped","communities"],"properties":{"communities_created":{"type":"integer"},"entities_grouped":{"type":"integer"},"communities":{"type":"array","items":{"$ref":"#/components/schemas/GraphCommunity"}}}},"GraphCommunityDeleteResponse":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"GraphGlobalSearchSchema":{"type":"object","required":["question"],"properties":{"question":{"type":"string"},"level":{"type":"integer","description":"Which hierarchy level's reports to search. Defaults to the coarsest level generated."},"max_communities":{"type":"integer","minimum":1,"maximum":30,"default":10,"description":"At most this many reports get a \"map\" call. When the level has more than this, the ones most similar to `question` by embedding are chosen first.\n"},"model":{"type":"string","description":"Override the model used for both the map and reduce steps."}}},"GraphGlobalSearchSource":{"type":"object","required":["community_id","title","relevance_score"],"properties":{"community_id":{"type":"string"},"title":{"type":"string"},"relevance_score":{"type":"integer","description":"0-100, as scored by the map step's model call for this report."}}},"GraphGlobalSearchResponse":{"type":"object","required":["answer","level","communities_considered","sources"],"properties":{"answer":{"type":"string"},"level":{"type":"integer"},"communities_considered":{"type":"integer","description":"How many reports were given a \"map\" call."},"sources":{"type":"array","description":"Reports whose points scored above the relevance floor and were fed to the \"reduce\" step, highest first.","items":{"$ref":"#/components/schemas/GraphGlobalSearchSource"}}}},"GraphDriftSearchSchema":{"type":"object","required":["question"],"properties":{"question":{"type":"string"},"level":{"type":"integer","description":"Which hierarchy level's reports the primer step searches. Defaults to the coarsest level generated."},"max_communities":{"type":"integer","minimum":1,"maximum":10,"default":5,"description":"At most this many community reports feed the primer step."},"max_follow_ups":{"type":"integer","minimum":1,"maximum":5,"default":3,"description":"At most this many of the primer's follow-up questions get their own local search."},"model":{"type":"string","description":"Override the model used for the primer, local, and reduce steps."}}},"GraphDriftFollowUp":{"type":"object","required":["question","answer"],"properties":{"question":{"type":"string"},"answer":{"type":"string","description":"Empty when the follow-up's local search found no grounded entities to answer from."}}},"GraphDriftSearchResponse":{"type":"object","required":["answer","primer_answer","follow_ups","level","communities_considered"],"properties":{"answer":{"type":"string","description":"The final answer, synthesizing the primer answer with every follow-up's local search."},"primer_answer":{"type":"string","description":"The intermediate answer from the primer step, before any follow-up was explored."},"follow_ups":{"type":"array","items":{"$ref":"#/components/schemas/GraphDriftFollowUp"}},"level":{"type":"integer"},"communities_considered":{"type":"integer","description":"How many community reports fed the primer step."}}},"SearchRuleBoost":{"type":"object","description":"Documents matching `filter_by` rank above the rest, in weight order. Compiled into a ranking expression that scores matching documents by their boost weight in front of the caller's own sort. A document scores the highest-weight boost it matches — weights do not add up, so for a cumulative effect combine conditions in one boost (`in_stock:true && has_image:true`) with a higher weight.\n","required":["filter_by"],"properties":{"filter_by":{"type":"string","description":"A `filter_by` expression, e.g. `in_stock:true` or `brand:=[Apple, Samsung]`.","example":"in_stock:true"},"weight":{"type":"integer","description":"Score given to matching documents; higher ranks first, negative buries. Defaults to 1.\n","default":1},"name":{"type":"string","description":"Label shown in a console; not used for ranking."},"priority":{"type":"integer","description":"Tie-breaker when several rules (the collection's own rule plus active campaigns) contribute boosts: higher-priority entries are compiled first. Default 0.\n"}}},"SearchRulePin":{"type":"object","description":"Forces `doc_id` into an exact `position` in the returned hits (0-based), a guarantee boosts cannot make — a boost only influences the `_eval` sort score among matched documents, never a final index. Applied response-side, after the engine call, so it holds regardless of ties, other boosts, or the caller's own `sort_by`. When `query` is set, the pin only applies to requests whose `q` matches it (same `match` semantics as `SearchRuleRedirect`); when `filter_contains` is set, the pin only applies to requests whose `filter_by` contains it verbatim (same semantics as `SearchRuleBanner`'s `filter_contains`, e.g. a category-page pin with no search text). When `query` and `filter_contains` are both set, either matching is enough. When neither is set, the pin applies to every search of the collection.\n","required":["doc_id","position"],"properties":{"query":{"type":"string","example":"iphone"},"match":{"type":"string","enum":["exact","prefix","contains"],"default":"exact"},"filter_contains":{"type":"string","description":"Trigger when the caller's `filter_by` string contains this substring verbatim (e.g. `category:=shoes`) — for category/browse-page pins with no search text. Omit to trigger on `query`/every search as before.\n"},"doc_id":{"type":"string","description":"The engine document id to pin."},"position":{"type":"integer","description":"0-based index to splice the document into. Clamped to the hit array's bounds.","minimum":0},"priority":{"type":"integer","description":"Higher-priority pins claim their slot first when several pins compete for the same position (campaign pins and the collection's own pins are merged). Default 0.\n"}}},"SearchRuleDiversityRule":{"type":"object","description":"One diversity treatment of the final hit order; a rule applies whichever of its parts are set. `field` + `max` caps how many hits may share the same value of `field`: after `max` hits with a given value have been kept, later hits with that same value are dropped (rank order of the remaining hits is otherwise unchanged); combining rules caps several fields at once, e.g. max 3 per `brand` and max 5 per `seller_id`. `field` + `min` guarantees every value of `field` present in the results at least `min` slots within the top `from` hits (default: the whole page) by pulling later hits of an under-represented value forward, when there are any. `near_duplicate` drops later hits whose text is nearly identical to an earlier one. `mmr` re-orders the page by Maximal Marginal Relevance. Order of application: near-duplicate suppression, max caps, MMR, min floors.\n","properties":{"field":{"type":"string","example":"brand"},"max":{"type":"integer","minimum":1},"min":{"type":"integer","minimum":1,"description":"Minimum hits per present value of `field` inside the top `from` hits."},"from":{"type":"integer","minimum":1,"description":"Window size (in hits) the `min` floor is guaranteed within; defaults to the page."},"near_duplicate":{"type":"object","description":"Near-duplicate suppression: a hit whose normalised-token Jaccard similarity over `fields` to an earlier kept hit reaches `threshold` is dropped.\n","required":["fields"],"properties":{"fields":{"type":"array","description":"Text fields the similarity is computed over.","items":{"type":"string"},"example":["title","description"]},"threshold":{"type":"number","format":"float","minimum":0,"maximum":1,"default":0.9}}},"mmr":{"type":"object","description":"Maximal Marginal Relevance re-ordering of the page: hits are picked greedily by `lambda × relevance − (1 − lambda) × similarity-to-already-picked`. The engine returns each hit's distance to the query but not the document vectors themselves, so document-to-document similarity uses `vector_field` only when the request's `include_fields` brought that field into `document`; otherwise it falls back to normalised-token Jaccard over `text_fields` (all string fields when unset).\n","properties":{"lambda":{"type":"number","format":"float","minimum":0,"maximum":1,"default":0.7,"description":"Relevance vs. diversity trade-off; higher favours relevance."},"vector_field":{"type":"string","description":"Document field holding the embedding, when the response includes it."},"text_fields":{"type":"array","description":"Fields for the token-overlap fallback similarity.","items":{"type":"string"}},"k":{"type":"integer","minimum":1,"description":"How many leading hits to re-order; the rest keep engine order behind them. Defaults to the page."}}}}},"SearchRuleRerank":{"type":"object","description":"Reranking of the leading hits by a cross-encoder or an LLM, after the engine ranked them (and after zero-hit rescue/fallback, before pins and diversity). Only the first `top_k` hits are scored and re-ordered; the rest keep their engine order behind them. Each reranked hit carries `rerank_score`; the response carries a `rerank` summary and the `x-nova-rerank` header names the model used (`skipped-<reason>` when it did not run). On a model timeout or error the engine order is returned unchanged. A request can override the rule with the `rerank`, `rerank_top_k` and `rerank_model` search parameters. Metered in credits per call plus per scored hit; when the wallet cannot cover it the search still answers, unreranked.\n","properties":{"enabled":{"type":"boolean","default":true,"description":"Off keeps the configuration but applies it only when a request asks with `rerank=true`."},"model":{"type":"string","enum":["bge-reranker-base","llm"],"default":"bge-reranker-base","description":"`bge-reranker-base` runs Workers AI's `@cf/baai/bge-reranker-base` cross-encoder; `llm` asks a small instruction model for a relevance-ordered list.\n"},"top_k":{"type":"integer","minimum":1,"maximum":100,"default":20,"description":"How many leading hits are scored and re-ordered."},"fields":{"type":"array","description":"Document fields concatenated into the passage the model scores; all string fields when empty.","items":{"type":"string"},"example":["title","description"]},"timeout_ms":{"type":"integer","minimum":50,"maximum":5000,"default":400,"description":"Hard budget for the model call; exceeding it returns the engine order."},"min_hits":{"type":"integer","minimum":1,"description":"Skip reranking when the page has fewer hits than this."},"fallback":{"type":"string","enum":["engine_order"],"default":"engine_order","description":"What to return when the model cannot answer in time."}}},"SearchRuleRedirect":{"type":"object","description":"When `q` matches `query` (case-insensitive, whitespace-normalised) the search result carries `redirect.url`. Results are still returned, so non-navigating clients keep working.\n","required":["query","url"],"properties":{"query":{"type":"string","example":"delivery"},"match":{"type":"string","enum":["exact","prefix","contains"],"default":"exact"},"url":{"type":"string","example":"/help/delivery"},"priority":{"type":"integer","description":"When several redirects match the same `q`, the highest priority wins. Default 0."}}},"SearchRuleSuggestion":{"type":"object","description":"Refinements offered when `q` matches `query`, e.g. \"phone\" → \"phone Apple\", \"phone Samsung\".","required":["query","suggestions"],"properties":{"query":{"type":"string"},"match":{"type":"string","enum":["exact","prefix"],"default":"exact"},"suggestions":{"type":"array","items":{"type":"string"}}}},"SearchRuleFacetSuggestions":{"type":"object","description":"Build refinement suggestions from the top values of these facet fields for every query: \"phone\" with `fields: [brand]` yields \"phone Apple\", \"phone Samsung\", … with the matching `filter_by`. AACSearch adds the fields to `facet_by` for the engine call and removes the extra facets from the response unless the caller asked for them.\n","required":["fields"],"properties":{"fields":{"type":"array","items":{"type":"string"},"example":["brand","category"]},"limit":{"type":"integer","description":"Maximum suggestions per field. Defaults to 5.","default":5,"minimum":1,"maximum":20}}},"SearchRuleBanner":{"type":"object","description":"A merchandising content block (image/text/link — free-form, see `content`) surfaced alongside search results when `query` matches `q` or `filter_contains` matches the caller's `filter_by`, e.g. a category banner shown on browse pages with no search text.\n","required":["id","content"],"properties":{"id":{"type":"string","description":"Stable identifier for this banner within the rule (for the caller to key React lists, etc)."},"query":{"type":"string","description":"Trigger when the caller's `q` matches this (see `match`). Omit to trigger on `filter_by` instead."},"match":{"type":"string","enum":["exact","prefix","contains"],"description":"How `query` is matched against the caller's `q`. Defaults to exact."},"filter_contains":{"type":"string","description":"Trigger when the caller's `filter_by` string contains this substring verbatim (e.g. `category:=shoes`) — for category/browse-page banners with no search text. At least one of `query` or `filter_contains` must be set; if both are set, either matching is enough.\n"},"content":{"type":"object","description":"Free-form banner payload (image URL, heading, body, link) — the caller's UI renders it however it wants."},"priority":{"type":"integer","description":"Higher wins when several banners match the same request. Default 0."}}},"SearchRuleSponsored":{"type":"object","description":"A sponsored placement: when the request matches (`query`/`match` against `q`, and/or `filter_by` contained verbatim in the caller's `filter_by`; neither set means every search), document `id` is spliced into `position` exactly like a pin and the returned hit carries a `_sponsored` marker (`label`, `campaign_id`) so the UI can label it. Like a pin, it only places a document the engine already returned for the query.\n","required":["id","position"],"properties":{"id":{"type":"string","description":"The engine document id to place."},"position":{"type":"integer","minimum":0,"description":"0-based index to splice the document into. Clamped to the hit array's bounds."},"query":{"type":"string","description":"Trigger when the caller's `q` matches this (see `match`). Omit to trigger on every query."},"match":{"type":"string","enum":["exact","prefix","contains"],"default":"exact"},"filter_by":{"type":"string","description":"Trigger when the caller's `filter_by` contains this substring verbatim (e.g. `category:=shoes`)."},"label":{"type":"string","description":"Shown to the end user (e.g. \"Sponsored\", \"Ad\"). Echoed in the hit's `_sponsored.label`."},"campaign_id":{"type":"string","description":"The campaign this placement belongs to; set automatically for campaign-sourced entries."}}},"SearchProfileSort":{"type":"object","required":["id","label","sort_by"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,63}$","description":"Stable id a client sends as `sort=<id>`","example":"price_asc"},"label":{"type":"string","description":"Human label shown to visitors","example":"Cheapest first"},"sort_by":{"type":"string","description":"Engine sort expression this id compiles to (never shown to browser keys)","example":"price:asc"}}},"SearchProfileFacet":{"type":"object","required":["field"],"properties":{"field":{"type":"string","description":"Facet field name in the collection schema","example":"brand"},"label":{"type":"string","description":"Human label; defaults to the field name","example":"Brand"}}},"SearchProfileUpsertSchema":{"type":"object","required":["searchable_fields"],"properties":{"label":{"type":"string","maxLength":120,"description":"Human name of the profile; defaults to `name`"},"is_default":{"type":"boolean","default":false,"description":"Pre-selected profile for consoles and widgets; the API never applies it implicitly"},"searchable_fields":{"type":"array","minItems":1,"maxItems":50,"items":{"type":"string"},"description":"Compiles to `query_by`, in this order","example":["name","brand","sku"]},"facet_fields":{"type":"array","maxItems":50,"items":{"$ref":"#/components/schemas/SearchProfileFacet"},"description":"Facets a client may request and filter on; compiles to `facet_by`"},"filterable_fields":{"type":"array","maxItems":100,"items":{"type":"string"},"description":"Fields a client's `filter_by` may reference in addition to the facets","example":["in_stock","price"]},"sorts":{"type":"array","maxItems":20,"items":{"$ref":"#/components/schemas/SearchProfileSort"},"description":"Sorts a client may pick by id"},"default_sort_id":{"type":"string","description":"Id from `sorts` used when the request sends no `sort`; omitted — engine relevance"},"fixed_filter_by":{"type":"string","description":"Filter ANDed into every request made with this profile (a client cannot remove it)","example":"visible:=true"},"highlight_fields":{"type":"array","maxItems":50,"items":{"type":"string"},"description":"Compiles to `highlight_fields`; omitted — the engine default"},"per_page_max":{"type":"integer","minimum":1,"maximum":250,"description":"Largest `per_page` a request may ask for; larger values are refused with `400`"},"search_policy":{"type":"string","description":"Name of a search policy (query intelligence) to apply for requests made with this profile, unless the request names one itself\n"}}},"SearchProfileCreateSchema":{"allOf":[{"$ref":"#/components/schemas/SearchProfileUpsertSchema"},{"type":"object","required":["name"],"properties":{"name":{"type":"string","pattern":"^[a-z0-9][a-z0-9_-]{0,63}$","description":"Stable identifier clients send as `profile=<name>`; immutable","example":"storefront"}}}]},"SearchProfile":{"allOf":[{"$ref":"#/components/schemas/SearchProfileUpsertSchema"},{"type":"object","required":["name","collection","created_at","updated_at"],"properties":{"revision":{"type":"integer","minimum":1,"description":"Revision required for optimistic publication and activation"},"active_release_id":{"type":"string","description":"Present after the first publication; searches use this immutable release"},"name":{"type":"string","example":"storefront"},"collection":{"type":"string"},"created_at":{"type":"integer","x-fern-type":"long"},"updated_at":{"type":"integer","x-fern-type":"long"}}}]},"SearchProfileActivateSchema":{"type":"object","required":["expected_revision"],"properties":{"expected_revision":{"type":"integer","minimum":1}}},"SearchProfilePublishSchema":{"allOf":[{"$ref":"#/components/schemas/SearchProfileActivateSchema"},{"type":"object","properties":{"note":{"type":"string","maxLength":1000},"change_class":{"type":"string","enum":["HOT","WARM","COLD"],"default":"HOT","description":"Only HOT query-time changes are currently supported"}}}]},"SearchProfileRelease":{"type":"object","required":["id","version","manifest","change_class","created_at"],"properties":{"id":{"type":"string"},"version":{"type":"integer","minimum":1},"manifest":{"$ref":"#/components/schemas/SearchProfileUpsertSchema"},"change_class":{"type":"string","enum":["HOT","WARM","COLD"]},"created_at":{"type":"integer","x-fern-type":"long"},"created_by":{"type":"string","description":"Identifier of the API key that published the release"},"note":{"type":"string"}}},"SearchProfileReleasesResponse":{"type":"object","required":["releases"],"properties":{"releases":{"type":"array","items":{"$ref":"#/components/schemas/SearchProfileRelease"}},"active_release_id":{"type":"string"},"next_before_version":{"type":"integer","minimum":1}}},"SearchProfilesResponse":{"type":"object","required":["search_profiles"],"properties":{"search_profiles":{"type":"array","items":{"$ref":"#/components/schemas/SearchProfile"}}}},"SearchProfileDeleteResponse":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"SearchProfileViewSort":{"type":"object","required":["id","label"],"properties":{"id":{"type":"string","example":"price_asc"},"label":{"type":"string","example":"Cheapest first"}}},"SearchProfileView":{"type":"object","description":"Browser-safe projection of a profile — no engine expressions (`sort_by`, `fixed_filter_by`) and none of the searchable / filterable / highlight field lists; facet field names are included because a visitor's filters have to name them.\n","required":["name","label","sorts","facets"],"properties":{"name":{"type":"string","example":"storefront"},"label":{"type":"string"},"sorts":{"type":"array","items":{"$ref":"#/components/schemas/SearchProfileViewSort"}},"facets":{"type":"array","items":{"$ref":"#/components/schemas/SearchProfileFacet"}},"default_sort_id":{"type":"string"},"per_page_max":{"type":"integer"}}},"SearchRuleUpsertSchema":{"type":"object","properties":{"exclusion_filter_by":{"type":"string","description":"A `filter_by` expression ANDed onto every search of the collection, e.g. `active:=true && stock_status:!=discontinued`. Applied server-side so a widget cannot skip it.\n"},"zero_hits_fallback":{"type":"string","description":"What to return when a search finds nothing: `broaden_query` reruns it without the caller's `filter_by`; `recommendation_model` returns the documents matching `fallback_model_id`'s filter. The response is marked with the `x-nova-fallback` header.\n","enum":["none","broaden_query","recommendation_model"],"default":"none"},"fallback_model_id":{"type":"string","description":"Required when `zero_hits_fallback` is `recommendation_model`."},"boosts":{"type":"array","items":{"$ref":"#/components/schemas/SearchRuleBoost"}},"boosts_override_sort":{"type":"boolean","description":"By default boosts apply only to relevance-ordered searches (no `sort_by` from the caller), so an explicit \"price ascending\" stays strictly by price. Set true to put the boosts in front of any caller sort as well.\n","default":false},"pins":{"type":"array","items":{"$ref":"#/components/schemas/SearchRulePin"}},"diversity":{"type":"array","description":"Per-field caps applied to the final hit order, e.g. max 3 hits sharing the same `brand`.\n","items":{"$ref":"#/components/schemas/SearchRuleDiversityRule"}},"redirects":{"type":"array","items":{"$ref":"#/components/schemas/SearchRuleRedirect"}},"suggestions":{"type":"array","items":{"$ref":"#/components/schemas/SearchRuleSuggestion"}},"facet_suggestions":{"$ref":"#/components/schemas/SearchRuleFacetSuggestions"},"starts_at":{"type":"string","format":"date-time","nullable":true,"description":"Rule is inactive (treated as if unconfigured) before this time. Unset means no lower bound.\n"},"ends_at":{"type":"string","format":"date-time","nullable":true,"description":"Rule is inactive (treated as if unconfigured) at and after this time. Unset means no upper bound.\n"},"device":{"type":"string","description":"Restricts the rule to requests whose caller-supplied `x_device` query parameter matches this value exactly. Unset means the rule matches every device.\n","enum":["desktop","mobile","tablet"]},"language":{"type":"string","description":"Restricts the rule to requests whose caller-supplied `x_language` query parameter matches this BCP-47 tag exactly (e.g. `en`, `en-US`, `fr`). Unset means the rule matches every language.\n"},"country":{"type":"string","description":"Restricts the rule to requests whose caller-supplied `x_country` query parameter matches this ISO 3166-1 alpha-2 code exactly (e.g. `US`, `DE`). Unset means the rule matches every country.\n"},"banners":{"type":"array","items":{"$ref":"#/components/schemas/SearchRuleBanner"}},"sponsored":{"type":"array","description":"Sponsored placements, applied response-side like pins (see `SearchRuleSponsored`).","items":{"$ref":"#/components/schemas/SearchRuleSponsored"}},"rerank":{"$ref":"#/components/schemas/SearchRuleRerank"}}},"SearchRule":{"allOf":[{"$ref":"#/components/schemas/SearchRuleUpsertSchema"},{"type":"object","required":["collection"],"properties":{"collection":{"type":"string"},"updated_at":{"type":"integer","x-fern-type":"long","description":"Absent for a collection that has no rules configured yet."}}}]},"SearchRulesResponse":{"type":"object","required":["search_rules"],"properties":{"search_rules":{"type":"array","items":{"$ref":"#/components/schemas/SearchRule"}}}},"SearchRuleDeleteResponse":{"type":"object","required":["collection"],"properties":{"collection":{"type":"string"}}},"Experiment":{"description":"Experiment state; promotion retains only the winning variant.","allOf":[{"type":"object","required":["name","collection","variants"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"collection":{"type":"string","description":"Collection whose searches take part"},"traffic":{"type":"number","description":"Share of sessions enrolled at all (the rest get the untouched request). Default 1.","minimum":0,"maximum":1},"variants":{"type":"array","minItems":1,"items":{"$ref":"#/components/schemas/ExperimentVariant"}}}},{"type":"object","required":["id","status","created_at"],"properties":{"id":{"type":"string"},"status":{"type":"string","enum":["draft","running","stopped"]},"created_at":{"type":"integer","x-fern-type":"long"},"started_at":{"type":"integer","x-fern-type":"long"},"stopped_at":{"type":"integer","x-fern-type":"long"}}}]},"ExperimentsResponse":{"type":"object","required":["experiments"],"properties":{"experiments":{"type":"array","items":{"$ref":"#/components/schemas/Experiment"}}}},"ExperimentDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"ExperimentVariantReport":{"type":"object","required":["variant_id","sessions","searches","clicks","add_to_carts","purchases","revenue"],"properties":{"variant_id":{"type":"string"},"sessions":{"type":"integer","description":"Sessions assigned to the variant"},"searches":{"type":"integer"},"clicks":{"type":"integer"},"add_to_carts":{"type":"integer"},"purchases":{"type":"integer"},"revenue":{"type":"number","description":"Sum of `value` over purchase events"},"ctr":{"type":"number","description":"clicks / searches, when there were searches"},"conversion_rate":{"type":"number","description":"purchases / searches, when there were searches"},"ctr_ci":{"$ref":"#/components/schemas/ConfidenceInterval"},"conversion_rate_ci":{"$ref":"#/components/schemas/ConfidenceInterval"},"significant_vs_control":{"type":"boolean","description":"`true` when this variant's conversion rate clearly beats the control (the first configured variant): its 95% CI lower bound exceeds the control's upper bound. Omitted (never `false`) when either side has too few searches or the intervals overlap.\n"}}},"ConfidenceInterval":{"type":"object","required":["lower","upper"],"properties":{"lower":{"type":"number"},"upper":{"type":"number"}}},"ExperimentReport":{"type":"object","required":["experiment_id","status","variants"],"properties":{"experiment_id":{"type":"string"},"status":{"type":"string","enum":["draft","running","stopped"]},"started_at":{"type":"integer","x-fern-type":"long"},"stopped_at":{"type":"integer","x-fern-type":"long"},"variants":{"type":"array","items":{"$ref":"#/components/schemas/ExperimentVariantReport"}}}},"SynonymImportResult":{"type":"object","required":["imported","rejected"],"properties":{"imported":{"type":"integer"},"rejected":{"type":"array","items":{"type":"object","required":["line","reason"],"properties":{"line":{"type":"integer"},"reason":{"type":"string"}}}}}},"MediaAsset":{"type":"object","required":["media_id","mime","bytes","uploaded","embedding","created_at"],"properties":{"media_id":{"type":"string"},"mime":{"type":"string"},"bytes":{"type":"integer"},"uploaded":{"type":"boolean","description":"False until the bytes of a `createMediaUpload` asset have been sent"},"caption":{"type":"string","description":"Description generated by the vision model, once ready"},"embedding":{"$ref":"#/components/schemas/MediaEmbedding"},"collection":{"type":"string"},"document_id":{"type":"string"},"vector_field":{"type":"string"},"created_at":{"type":"integer","x-fern-type":"long"}}},"MediaDeleteSchema":{"type":"object","required":["media_id"],"properties":{"media_id":{"type":"string"}}},"EmbeddingsRequest":{"type":"object","required":["input"],"properties":{"input":{"type":"array","minItems":1,"maxItems":100,"description":"Texts to embed; each up to about 500 tokens","items":{"type":"string"}}}},"EmbeddingsResponse":{"type":"object","required":["model","num_dim","data"],"properties":{"model":{"type":"string"},"num_dim":{"type":"integer"},"data":{"type":"array","items":{"type":"array","items":{"type":"number"}}}}},"VectorSearchOptions":{"type":"object","required":["vector_field"],"properties":{"vector_field":{"type":"string","description":"`float[]` field of the collection holding 1024-dimensional embeddings"},"k":{"type":"integer","default":10,"minimum":1,"maximum":100},"filter_by":{"type":"string"},"include_fields":{"type":"string"},"exclude_fields":{"type":"string"},"distance_threshold":{"type":"number","description":"Drop matches whose cosine distance is above this value (0 = identical, 1 = unrelated)"}}},"SemanticSearchRequest":{"allOf":[{"$ref":"#/components/schemas/VectorSearchOptions"},{"type":"object","required":["q"],"properties":{"q":{"type":"string","description":"Query text, any language"}}}]},"ImageSearchRequest":{"allOf":[{"$ref":"#/components/schemas/VectorSearchOptions"},{"type":"object","properties":{"media_id":{"type":"string","description":"An image uploaded with `uploadMedia`"},"image_url":{"type":"string","description":"Public HTTPS URL of an image (fetched server-side, up to 8 MB)"},"image_base64":{"type":"string","description":"Inline image bytes, base64 (with or without a data-URI prefix)"}}}]},"InsufficientCredits":{"type":"object","required":["message"],"properties":{"message":{"type":"string"},"available":{"type":"integer","description":"Credits the organization can still spend (balance minus pending reservations)"},"requested":{"type":"integer","description":"Credits this operation had to reserve before it could run"}}},"SeoRuleTemplates":{"type":"object","description":"One template per metatag field; at least one non-empty template is required.","properties":{"title":{"type":"string","description":"The `<title>` of the generated pages"},"description":{"type":"string","description":"The meta description of the generated pages"},"h1":{"type":"string","description":"The on-page heading of the generated pages"},"text":{"type":"string","description":"Body text above the result list of the generated pages"}}},"SeoRuleUpsertSchema":{"type":"object","required":["collection","name","facet_field"],"properties":{"collection":{"type":"string","description":"Collection the rule generates pages for (without tenant prefix)"},"name":{"type":"string","description":"Human-readable rule name"},"facet_field":{"type":"string","description":"The facet field whose values become pages"},"active":{"type":"boolean","default":true,"description":"Inactive rules are skipped by `generateSeoPages`"},"url_template":{"type":"string","description":"The url each page is materialized under, with the same `#PLACEHOLDER#` substitutions as the templates. Default `#SECTION#/#PROPERTY#/#VALUE#`.\n"},"site_name":{"type":"string","description":"What `#SITE_NAME#` renders as; the organization name when left out"},"templates":{"$ref":"#/components/schemas/SeoRuleTemplates"}}},"SeoRule":{"type":"object","required":["id","collection","name","facet_field","active","templates","created_at","updated_at"],"properties":{"id":{"type":"string"},"collection":{"type":"string"},"name":{"type":"string"},"facet_field":{"type":"string"},"active":{"type":"boolean"},"url_template":{"type":"string","nullable":true},"site_name":{"type":"string","nullable":true},"templates":{"$ref":"#/components/schemas/SeoRuleTemplates"},"created_at":{"type":"integer","x-fern-type":"long"},"updated_at":{"type":"integer","x-fern-type":"long"}}},"SeoRulesResponse":{"type":"object","required":["rules","total"],"properties":{"rules":{"type":"array","items":{"$ref":"#/components/schemas/SeoRule"}},"total":{"type":"integer","description":"Rules of the organization, across pages"}}},"SeoRuleDeleteSchema":{"type":"object","required":["id"],"properties":{"id":{"type":"string"}}},"SeoPage":{"type":"object","required":["id","collection","url","robots","active","created_at","updated_at"],"properties":{"id":{"type":"string"},"rule_id":{"type":"string","nullable":true,"description":"The rule the page was rendered from; null once that rule is deleted"},"collection":{"type":"string"},"url":{"type":"string"},"title":{"type":"string","nullable":true},"description":{"type":"string","nullable":true},"h1":{"type":"string","nullable":true},"text":{"type":"string","nullable":true},"robots":{"type":"string","enum":["index","noindex"],"description":"The robots directive the page deserves at audit time"},"section":{"type":"string","nullable":true,"description":"The `#SECTION#` value the page was rendered with"},"property":{"type":"string","nullable":true,"description":"The `#PROPERTY#` value (the facet field)"},"value":{"type":"string","nullable":true,"description":"The `#VALUE#` (the facet value)"},"hits":{"type":"integer","description":"Documents carrying the facet value when the page was generated"},"active":{"type":"boolean","description":"Whether the page belongs in the sitemap"},"created_at":{"type":"integer","x-fern-type":"long"},"updated_at":{"type":"integer","x-fern-type":"long"}}},"SeoPagesResponse":{"type":"object","required":["pages","total"],"properties":{"pages":{"type":"array","items":{"$ref":"#/components/schemas/SeoPage"}},"total":{"type":"integer","description":"Pages of the organization (or of `collection`), across pages"}}},"SeoPageGenerateSchema":{"type":"object","required":["collection"],"properties":{"collection":{"type":"string","description":"Collection to generate pages for (without tenant prefix)"},"rule_id":{"type":"string","description":"Generate from this rule only; default every active rule of the collection"}}},"SeoPageGenerateResponse":{"type":"object","required":["collection","rules","created","updated","total"],"properties":{"collection":{"type":"string"},"rules":{"type":"integer","description":"Active rules that were rendered"},"created":{"type":"integer","description":"New pages materialized by this run"},"updated":{"type":"integer","description":"Existing pages re-rendered by this run"},"total":{"type":"integer","description":"Pages of the collection after the run"}}},"SeoPageAuditSchema":{"type":"object","properties":{"collection":{"type":"string","description":"Audit only pages generated for this collection; default every page"}}},"SeoPageAuditResponse":{"type":"object","required":["checked","findings"],"properties":{"checked":{"type":"integer","description":"Pages examined"},"findings":{"type":"array","description":"Only pages with something to report","items":{"type":"object","required":["page_id","url","issues"],"properties":{"page_id":{"type":"string"},"url":{"type":"string"},"robots":{"type":"string","enum":["index","noindex"],"description":"The directive the page deserves after the audit"},"issues":{"type":"array","items":{"type":"string"}}}}}}},"SeoSitemapResponse":{"type":"object","required":["xml"],"properties":{"xml":{"type":"string","description":"The urlset XML; write it to the sitemap URL the storefront serves"}}},"CollectionReindexSchema":{"type":"object","properties":{"action":{"$ref":"#/components/schemas/IngestJobAction"}}},"IngestJobsRetryFailedResponse":{"type":"object","required":["retried","jobs"],"properties":{"retried":{"type":"integer","description":"How many failed jobs were re-queued"},"jobs":{"type":"array","items":{"$ref":"#/components/schemas/IngestJob"}}}},"StorefrontEvent":{"type":"object","required":["type","session_id","timestamp"],"properties":{"type":{"type":"string","enum":["search","click","conversion"],"description":"What the visitor did: ran a search (`query` required), clicked a result or converted (`document_id` required).\n"},"query":{"type":"string","description":"Search text, for `search` events"},"collection":{"type":"string","description":"Collection the event belongs to"},"document_id":{"type":"string","description":"The document clicked or bought, for `click` and `conversion`"},"session_id":{"type":"string","description":"Browsing session the event belongs to"},"timestamp":{"type":"integer","x-fern-type":"long","description":"When the event happened, Unix time in milliseconds"},"metadata":{"type":"object","additionalProperties":true,"description":"Free-form JSON, at most 2 KB serialized"}}},"StorefrontEventBatch":{"type":"object","required":["events"],"properties":{"events":{"type":"array","minItems":1,"maxItems":20,"items":{"$ref":"#/components/schemas/StorefrontEvent"}}}},"StorefrontEventsAccepted":{"type":"object","required":["accepted","rejected"],"properties":{"accepted":{"type":"integer","description":"Number of events stored"},"rejected":{"type":"array","description":"Events that failed validation, by index in the batch","items":{"type":"object","required":["index","reason"],"properties":{"index":{"type":"integer"},"reason":{"type":"string"}}}}}},"AnalyticsQueryMetric":{"type":"object","required":["q","searches","results_found_rate","clicks","ctr","no_click_rate","add_to_carts","purchases","revenue","conversion_rate","revenue_per_search"],"properties":{"q":{"type":"string"},"searches":{"type":"integer"},"results_found_rate":{"type":"number","description":"Share of searches that returned at least one hit."},"clicks":{"type":"integer"},"ctr":{"type":"number"},"no_click_rate":{"type":"number","description":"Share of searches that received no click before the next search or the attribution window closed."},"add_to_carts":{"type":"integer"},"purchases":{"type":"integer"},"revenue":{"type":"number"},"conversion_rate":{"type":"number","description":"Share of searches followed by a purchase."},"revenue_per_search":{"type":"number"}}},"AnalyticsQueryMetricsResponse":{"type":"object","required":["from","to","collection","events","truncated","total","next_offset","data"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"collection":{"type":"string","nullable":true},"events":{"type":"integer","description":"Raw events walked to compute this page (before the `AnalyticsQueryMetric` rows are aggregated)."},"truncated":{"type":"boolean","description":"True when the range held more events than the server will walk in one request; the numbers cover only the earliest rows."},"total":{"type":"integer","description":"Total number of distinct queries in the range, before `limit`/`offset`."},"next_offset":{"type":"integer","nullable":true,"description":"Pass as `offset` to fetch the next page; `null` once `data` reaches the end."},"data":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsQueryMetric"}}}},"AnalyticsZeroResultMetric":{"type":"object","required":["q","searches","zero_result_rate"],"properties":{"q":{"type":"string"},"searches":{"type":"integer"},"zero_result_rate":{"type":"number","description":"Share of this query's searches that returned no hits (`1 - results_found_rate`)."}}},"AnalyticsZeroResultMetricsResponse":{"type":"object","required":["from","to","collection","events","truncated","total","zero_result_rate","next_offset","data"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"collection":{"type":"string","nullable":true},"events":{"type":"integer"},"truncated":{"type":"boolean"},"total":{"type":"integer","description":"Total number of distinct queries in the range, before `limit`/`offset`."},"zero_result_rate":{"type":"number","description":"Organization-wide zero-result share across every search in the range (search-weighted, not query-weighted)."},"next_offset":{"type":"integer","nullable":true},"data":{"type":"array","description":"Per-query zero-result rate, sorted highest first.","items":{"$ref":"#/components/schemas/AnalyticsZeroResultMetric"}}}},"AnalyticsFunnelStepMetric":{"type":"object","required":["step","sessions","step_conversion","overall_conversion"],"properties":{"step":{"type":"string","enum":["search","click","add_to_cart","purchase"]},"sessions":{"type":"integer"},"step_conversion":{"type":"number","description":"sessions / previous step's sessions; 1 for the first step."},"overall_conversion":{"type":"number","description":"sessions / first step's sessions."}}},"AnalyticsFunnelMetricsResponse":{"type":"object","required":["from","to","collection","events","truncated","data"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"collection":{"type":"string","nullable":true},"events":{"type":"integer"},"truncated":{"type":"boolean"},"data":{"type":"array","items":{"$ref":"#/components/schemas/AnalyticsFunnelStepMetric"}}}},"AnalyticsAttributedQueryMetric":{"type":"object","required":["q","purchases","revenue"],"properties":{"q":{"type":"string"},"purchases":{"type":"integer"},"revenue":{"type":"number"}}},"AnalyticsRevenueAttributionMetricsResponse":{"type":"object","required":["from","to","collection","events","truncated","purchases","attributed_purchases","revenue","attributed_revenue","unattributed_revenue","next_offset","data"],"properties":{"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"collection":{"type":"string","nullable":true},"events":{"type":"integer"},"truncated":{"type":"boolean"},"purchases":{"type":"integer"},"attributed_purchases":{"type":"integer"},"revenue":{"type":"number"},"attributed_revenue":{"type":"number"},"unattributed_revenue":{"type":"number"},"next_offset":{"type":"integer","nullable":true},"data":{"type":"array","description":"Per-query attributed purchases/revenue, sorted by revenue.","items":{"$ref":"#/components/schemas/AnalyticsAttributedQueryMetric"}}}}},"parameters":{"AnalyticsMetricsFrom":{"in":"query","name":"from","required":true,"description":"Range start (ISO 8601 date or date-time, inclusive).","schema":{"type":"string"}},"AnalyticsMetricsTo":{"in":"query","name":"to","required":true,"description":"Range end (ISO 8601 date or date-time, inclusive; a date-only value covers the whole day). The range may not exceed 366 days.\n","schema":{"type":"string"}},"AnalyticsMetricsCollection":{"in":"query","name":"collection","required":false,"schema":{"type":"string"}},"AnalyticsMetricsLimit":{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"default":100}},"AnalyticsMetricsOffset":{"in":"query","name":"offset","required":false,"schema":{"type":"integer","minimum":0,"default":0}}},"responses":{"Unauthorized":{"description":"The `X-NOVA-API-KEY` header is missing, malformed, or names a key that was revoked.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"PaymentRequired":{"description":"The organization's credit balance cannot cover this AI operation. Every model call — an assistant turn, a transcription, an embedding, an image search — is paid for in credits from the organization's wallet, whichever key made the request. Top up the wallet, or lower the assistant's `max_output_tokens`.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InsufficientCredits"}}}},"Forbidden":{"description":"The key's scope does not reach this operation: a `search` key called an operation without `x-nova-key-scope: search`, or a `search` key asked for a conversation that belongs to another visitor's session.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}},"TooManyRequests":{"description":"The organization's monthly request quota is used up, or a `search` key exceeded its per-session allowance of AI operations (the allowance protects the wallet behind a key that ships in a browser). Wait for `Retry-After` seconds when the header is present; a quota answer has no known reset moment and carries none.\n","headers":{"Retry-After":{"description":"Seconds to wait before retrying, when the server knows.","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}}},"securitySchemes":{"api_key_header":{"type":"apiKey","name":"X-NOVA-API-KEY","in":"header","description":"Every request carries an organization API key. A key has one of two scopes. A `full` key reaches every operation in this document and belongs on your server. A `search` key is the one to ship in a browser widget or a storefront page: it reaches only the operations marked `x-nova-key-scope: search` — searching, federated search, recommendations, event ingestion, and the visitor-facing AI operations (semantic and image search, voice transcription and voice search, assistant chat, and the visitor's own conversation). It cannot write documents or read or change configuration; any other operation answers 403. AI operations are paid in credits from the organization's wallet whichever key calls them (402 when the balance runs out), and a `search` key needs `X-NOVA-SESSION-ID` on them: the session is what a conversation belongs to, and what the per-session allowance (429) is counted against. A key of either scope may additionally carry restrictions set in the console: an allowlist of collections (403 elsewhere), a forced `filter_by` per collection that is ANDed into every search (document-level access control), an allowlist of fields (`include_fields` is limited to it and a request naming any other field in `query_by`, `facet_by`, `sort_by`, `filter_by` or `highlight_fields` answers 400), an IP/CIDR allowlist and an Origin/Referer allowlist (403), and a per-key rate limit (429 with `Retry-After`).\n"}}}}