openapi: 3.0.1 info: contact: email: info@commerce-experts.com description: A common product search API that separates its usage from required search expertise license: name: Apache 2.0 url: http://www.apache.org/licenses/LICENSE-2.0.html title: Open Commerce Search Stack API version: 0.26.0 paths: /indexer-api/v1/full/add: post: description: Add one or more documents to a running import session. operationId: add requestBody: content: '*/*': schema: $ref: "#/components/schemas/BulkImportData" description: Data that contains the import session reference and one or more documents that should be added to that session. required: true responses: "200": content: '*/*': schema: type: string description: Amount of documents successfuly added description: documents successfully added "400": description: import session is invalid security: - basic-auth: [] servers: - description: "Service to run a full import into a new index. To do so, start\ \ a indexation session with a request to 'start' and use the returned ImportSession\ \ object to 'add' products bulkwise. If all documents where added, use the\ \ 'done' request to deploy that index. In case there were failures (or more\ \ failures then tollerated), the 'cancel' request can be used to stop the\ \ process and cleanup the incomplete index. Depending on the document size,\ \ an amount of 500-2000 documents per bulk is sufficient. If product and\ \ content data should be indexed, its recommended to use different indexes.\ \ Otherwise make sure to use the same fields for the same content type,\ \ e.g. both kind of documents can have a textual 'title' field, but both\ \ kind of documents shouldn't have for example an 'author' field, which\ \ could be used for product facets (e.g. book authors) but not for faceting\ \ the content documents (e.g. blog post authors)." url: http://indexer-service tags: - indexer /indexer-api/v1/full/cancel: post: description: "Cancels the import and in case there was an index created, it\ \ will be deleted." operationId: cancel requestBody: content: '*/*': schema: $ref: "#/components/schemas/ImportSession" required: true responses: "400": description: indexation was already confirmed or import session is invalid security: - basic-auth: [] servers: - description: "Service to run a full import into a new index. To do so, start\ \ a indexation session with a request to 'start' and use the returned ImportSession\ \ object to 'add' products bulkwise. If all documents where added, use the\ \ 'done' request to deploy that index. In case there were failures (or more\ \ failures then tollerated), the 'cancel' request can be used to stop the\ \ process and cleanup the incomplete index. Depending on the document size,\ \ an amount of 500-2000 documents per bulk is sufficient. If product and\ \ content data should be indexed, its recommended to use different indexes.\ \ Otherwise make sure to use the same fields for the same content type,\ \ e.g. both kind of documents can have a textual 'title' field, but both\ \ kind of documents shouldn't have for example an 'author' field, which\ \ could be used for product facets (e.g. book authors) but not for faceting\ \ the content documents (e.g. blog post authors)." url: http://indexer-service tags: - indexer /indexer-api/v1/full/done: post: description: "Finishes the import, flushing the new index and (in case there\ \ is already an index with the initialized name) replacing the old one." operationId: done requestBody: content: '*/*': schema: $ref: "#/components/schemas/ImportSession" required: true responses: "200": description: successfully done "400": description: indexation was already confirmed or import session is invalid security: - basic-auth: [] servers: - description: "Service to run a full import into a new index. To do so, start\ \ a indexation session with a request to 'start' and use the returned ImportSession\ \ object to 'add' products bulkwise. If all documents where added, use the\ \ 'done' request to deploy that index. In case there were failures (or more\ \ failures then tollerated), the 'cancel' request can be used to stop the\ \ process and cleanup the incomplete index. Depending on the document size,\ \ an amount of 500-2000 documents per bulk is sufficient. If product and\ \ content data should be indexed, its recommended to use different indexes.\ \ Otherwise make sure to use the same fields for the same content type,\ \ e.g. both kind of documents can have a textual 'title' field, but both\ \ kind of documents shouldn't have for example an 'author' field, which\ \ could be used for product facets (e.g. book authors) but not for faceting\ \ the content documents (e.g. blog post authors)." url: http://indexer-service tags: - indexer /indexer-api/v1/full/start/{indexName}: get: description: "Starts a new full import. Returns a handle containing meta data,\ \ that has to be passed to all following calls." operationId: startImport parameters: - description: "index name, that should match the regular expression '[a-z0-9_-]+'" in: path name: indexName required: true schema: type: string - description: used for language dependent settings in: query name: locale required: true schema: type: string responses: "200": content: '*/*': schema: $ref: "#/components/schemas/ImportSession" description: import session started "409": description: there is already an import running for that index security: - basic-auth: [] servers: - description: "Service to run a full import into a new index. To do so, start\ \ a indexation session with a request to 'start' and use the returned ImportSession\ \ object to 'add' products bulkwise. If all documents where added, use the\ \ 'done' request to deploy that index. In case there were failures (or more\ \ failures then tollerated), the 'cancel' request can be used to stop the\ \ process and cleanup the incomplete index. Depending on the document size,\ \ an amount of 500-2000 documents per bulk is sufficient. If product and\ \ content data should be indexed, its recommended to use different indexes.\ \ Otherwise make sure to use the same fields for the same content type,\ \ e.g. both kind of documents can have a textual 'title' field, but both\ \ kind of documents shouldn't have for example an 'author' field, which\ \ could be used for product facets (e.g. book authors) but not for faceting\ \ the content documents (e.g. blog post authors)." url: http://indexer-service tags: - indexer /indexer-api/v1/update/{indexName}: delete: description: "Delete existing document. If document does not exist, it returns\ \ code 304." operationId: deleteDocuments parameters: - in: path name: indexName required: true schema: type: string - in: query name: "id[]" schema: type: array items: type: string responses: "200": description: OK. The response contains a map of ids and according result. "404": description: index does not exist security: - basic-auth: [] servers: - url: http://indexer-service tags: - update patch: description: "Partial update of existing documents. If a document does not exist,\ \ no update will be performed and it gets the result status 'NOT_FOUND'. In\ \ case a document is a master product with variants, the provided master product\ \ may only contain the changed values. However if some of the variants should\ \ be updated, all data from all variant products are required, unless you\ \ have an ID data-field inside variant - then you can update single variants.\ \ Without variant ID field, the missing variants won't be there after the\ \ update! This is how single variants can be deleted." operationId: patchDocuments parameters: - in: path name: indexName required: true schema: type: string responses: "200": description: OK. The response contains a map of ids and according result. "404": description: index does not exist security: - basic-auth: [] servers: - url: http://indexer-service tags: - update put: description: "Puts a document to the index. If document does not exist, it will\ \ be added, but in that case the langCode parameter is required. An existing\ \ product will be overwritten unless the parameter 'replaceExisting\" is set\ \ to \"false\". Provided document should be a complete object, partial updates\ \ should be done using the updateDocument method." operationId: putDocuments parameters: - in: path name: indexName required: true schema: type: string - description: set to false to avoid overriding a document with that ID. Defaults to 'true' in: query name: replaceExisting schema: type: boolean - description: "If this put request targets an index that does not exist yet,\ \ that index will be created. To use the correct index template, the language\ \ is required for that case. Otherwise its ignored." in: query name: langCode schema: type: string responses: "200": description: OK. The response contains a map of ids and according result. "404": description: index does not exist security: - basic-auth: [] servers: - url: http://indexer-service tags: - update /search-api/v1/doc/{tenant}/{id}: get: operationId: getDocument parameters: - description: tenant name in: path name: tenant required: true schema: type: string - description: document id in: path name: id required: true schema: type: string responses: default: content: '*/*': schema: $ref: "#/components/schemas/Document" description: default response security: - basic-auth: [] servers: - url: http://search-service tags: - search /search-api/v1/search/arranged/{tenant}: post: operationId: arrangedSearch parameters: - description: tenant name in: path name: tenant required: true schema: type: string requestBody: content: '*/*': schema: $ref: "#/components/schemas/ArrangedSearchQuery" description: A list of all search requests that should be part of a single response required: true responses: default: content: '*/*': schema: $ref: "#/components/schemas/SearchResult" description: default response security: - basic-auth: [] servers: - url: http://search-service tags: - search /search-api/v1/search/{tenant}: get: description: Runs a search request for a certain tenant. The tenant should exist at the service and linked to a certain index in the backend. Different tenants may use the same index. operationId: search parameters: - description: tenant name in: path name: tenant required: true schema: type: string - description: the query that describes the wished result in: query name: searchQuery required: true schema: $ref: "#/components/schemas/SearchQuery" style: form - description: "Any other parameter is considered as filter. Each one is validated\ \ according to the actual data and configuration. Each filter can have multiple\ \ values, separated by comma. Commas inside the values have to be double-URL\ \ encoded. Depending on the configured filter type these values are used\ \ differently (see examples)." examples: hierarchical_filter: description: "if category would be configured as path, these values are\ \ used for hierarchical filtering" summary: hierarchical filter value: "category=men,shoes,sneaker" joined_exclusive_filter: description: The way filters are interpreted depends on the backend configuration. If that field is configured to be used for "exclusive filtering" only products would be shown that are available in red AND black summary: joined exclusive filter value: "color=red,black" joined_filter: description: products from adidas OR nike are shown summary: joined filter value: "brand=adidas,nike" numeric_range_filter: description: "if price is configured as numeric field, these values are\ \ used as range filters" summary: numeric range filter value: "price=10,99.90" simple_filter: description: Filters are simple parameters with the field-names as parameter and the filter values as comma separated parameter values. summary: simple filter value: brand=adidas in: query name: filters schema: type: object additionalProperties: type: string style: form responses: "200": content: '*/*': schema: $ref: "#/components/schemas/SearchResult" description: successful found results "204": content: '*/*': schema: $ref: "#/components/schemas/SearchResult" description: Optional response code that represents 'no result' "403": content: text/plain: {} description: tenant can't be accessed or does not exist "404": content: text/plain: {} description: response code if tenant is unknown or index does not exist security: - basic-auth: [] servers: - url: http://search-service summary: Search for documents tags: - search /search-api/v1/tenants: get: operationId: getTenants responses: "200": description: a list of available tenants security: - basic-auth: [] servers: - url: http://search-service tags: - search /suggest-api/v1/{indexname}/suggest: get: description: Runs a suggestion request on the data of a certain index. operationId: suggest parameters: - description: index name that should be searched for autocompletions in: path name: indexname required: true schema: type: string - description: the simple raw query typed by the user in: query name: userQuery required: true schema: type: string - description: A optional limit for the suggestions in: query name: limit schema: type: integer format: int32 - description: Optional comma-separated list of filter values. in: query name: filter schema: type: string responses: "200": content: '*/*': schema: type: array items: $ref: "#/components/schemas/Suggestion" description: successful found results "404": content: text/plain: {} description: tenant is unknown or index does not exist security: - basic-auth: [] servers: - url: http://suggest-service summary: Autocomplete the user input tags: - Suggest components: schemas: ArrangedSearchQuery: type: object properties: arrangedProductSets: type: array items: $ref: "#/components/schemas/ProductSet" filters: type: object additionalProperties: type: string includeMainResult: type: boolean limit: type: integer format: int32 description: The amount of products to return in the result minimum: 1 offset: type: integer format: int32 description: The amount of products to omit from the whole result to select the returned results. minimum: 0 q: type: string description: the user query example: blue shirt sort: type: string description: "Full sorting parameter value. This is the name of the sorting\ \ and optionally a dash as prefix, thats means the sorting should be descending.\ \ Several sorting criterion can be defined by separating the values using\ \ comma." example: "sort=price,-name (price asc and name descending)" withFacets: type: boolean description: flag to specify if facets should be returned with the requested response. Should be set to false in case only the next batch of hits is requested (e.g. for endless scrolling). Attribute: type: object description: "Rich model that can be used to represent a document's or product's\ \ attribute. The attribute 'name' should be a URL friendly identifier for\ \ that attribute (rather maxSpeed than 'Max Speed'). It will be used as filter\ \ parameter laster. If the attribute 'code' is provieded, it can be used for\ \ consistent filtering, even if the value name should change. The values are\ \ used to produce nice facets or if used for search, they will be added to\ \ the searchable content." example: name: color value: red code: ff0000 properties: code: type: string description: "Optional: code is considered as ID of the attribute value,\ \ e.g. \"FF0000\" for color" pattern: "[A-Za-z0-9\\-_.]" name: type: string description: "The name SHOULD be URL friendly identifier for the attribute,\ \ since it could be used to build according filter parameters." pattern: "[A-Za-z0-9\\-_.]" value: type: string description: "Human readable representation of that attribute, e.g. 'Red'\ \ for the attribute 'Color'. Values can be numeric and " required: - name - value BulkImportData: type: object description: composite object that is used to add documents to the index. properties: documents: type: array description: An array of Documents or Products that should be indexed into the given index.Products have the speciality to contain other documents as variants. items: $ref: "#/components/schemas/Document" session: $ref: "#/components/schemas/ImportSession" required: - documents - session Category: type: object description: Model that represents a single category inside a category path. example: id: "7001" name: Sale properties: id: type: string description: Optional ID for a consistent filtering name: type: string description: actual category name required: - name Document: type: object description: A data record that contains any data relevant for search. The single field types and conversions are part of the according service configuration. properties: attributes: type: array description: multiple attributes can be delivered separately from standard data fields items: $ref: "#/components/schemas/Attribute" categories: type: array description: "A category path is a list of Category objects that are defined\ \ in a hierarchical parent-child relationship.Multiple category paths\ \ can be defined per document, therefor this property is a list of category\ \ arrays." example: - - id: "7001" name: Electronics - id: "7011" name: Notebooks - - id: "9000" name: Sale items: type: array description: "A category path is a list of Category objects that are defined\ \ in a hierarchical parent-child relationship.Multiple category paths\ \ can be defined per document, therefor this property is a list of category\ \ arrays." example: - - id: "7001" name: Electronics - id: "7011" name: Notebooks - - id: "9000" name: Sale items: $ref: "#/components/schemas/Category" data: type: object additionalProperties: type: object anyOf: - type: boolean - type: integer format: int32 - type: integer format: int64 - type: number format: double - type: string - $ref: "#/components/schemas/Category" - type: array items: type: boolean - type: array items: type: integer format: int32 - type: array items: type: integer format: int64 - type: array items: type: number format: double - type: array items: type: string - type: array items: $ref: "#/components/schemas/Category" - type: array items: type: array items: $ref: "#/components/schemas/Category" description: "The data property should be used for standard fields, such\ \ as title, description, price. Only values of the following types are\ \ accepted (others will be dropped silently): Standard primitive types\ \ (Boolean, String, Integer, Double) and arrays of these types. Attributes\ \ (key-value objects with ID) should be passed to the attributes property." description: "The data property should be used for standard fields, such\ \ as title, description, price. Only values of the following types are\ \ accepted (others will be dropped silently): Standard primitive types\ \ (Boolean, String, Integer, Double) and arrays of these types. Attributes\ \ (key-value objects with ID) should be passed to the attributes property." id: type: string required: - data - id DynamicProductSet: type: object allOf: - $ref: "#/components/schemas/ProductSet" - type: object properties: asSeparateSlice: type: boolean filters: type: object additionalProperties: type: string limit: type: integer format: int32 description: The maximum amount of products to pick based on the given query and filters minimum: 1 name: type: string query: type: string size: type: integer format: int32 sort: type: string type: type: string variantBoostTerms: type: string Facet: type: object description: "If facets are part of this slice, they are placed here. By default\ \ only one slice SHOULD contain facets." properties: absoluteFacetCoverage: type: integer format: int64 description: This is the amount of matched documents that are covered by that facet. entries: type: array description: The entries of that facet. items: $ref: "#/components/schemas/FacetEntry" fieldName: type: string description: This is the name coming from the data. Separate label information should be available in the meta data. filtered: type: boolean isFiltered: type: boolean description: Is set to true if there an active filter from that facet. meta: type: object additionalProperties: type: object description: "Optional meta data for that facet, e.g. display hints like\ \ a label or a facet-type." description: "Optional meta data for that facet, e.g. display hints like\ \ a label or a facet-type." type: type: string description: "The type of the facet, so the kind of FacetEntries it contains.\ \ See the according FacetEntry variants for more details." enum: - term - hierarchical - interval - range FacetEntry: type: object description: The entries of that facet. discriminator: mapping: hierarchical: "#/components/schemas/HierarchialFacetEntry" interval: "#/components/schemas/IntervalFacetEntry" range: "#/components/schemas/RangeFacetEntry" term: "#/components/schemas/FacetEntry" propertyName: type properties: docCount: type: integer format: int64 description: "Estimated amount of documents that will be returned, if this\ \ facet entry is picked as filter." id: type: string key: type: string link: type: string format: URI selected: type: boolean description: "Should be set to true in the response, if that filter is actually\ \ selected." type: type: string GenericProductSet: type: object allOf: - $ref: "#/components/schemas/ProductSet" - type: object properties: asSeparateSlice: type: boolean name: type: string parameters: type: object additionalProperties: type: string size: type: integer format: int32 type: type: string variantBoostTerms: type: string description: A non-specific product set usable for custom product set resolvers. HierarchialFacetEntry: type: object allOf: - $ref: "#/components/schemas/FacetEntry" - type: object properties: children: type: array description: Child facet entries to that particular facet. The child facets again could be HierarchialFacetEntries. items: $ref: "#/components/schemas/FacetEntry" docCount: type: integer format: int64 description: "Estimated amount of documents that will be returned, if\ \ this facet entry is picked as filter." id: type: string key: type: string link: type: string format: URI path: type: string selected: type: boolean description: "Should be set to true in the response, if that filter is\ \ actually selected." type: type: string ImportSession: type: object properties: finalIndexName: type: string temporaryIndexName: type: string readOnly: true required: - finalIndexName - temporaryIndexName IntervalFacetEntry: type: object allOf: - $ref: "#/components/schemas/FacetEntry" - type: object properties: docCount: type: integer format: int64 description: "Estimated amount of documents that will be returned, if\ \ this facet entry is picked as filter." id: type: string key: type: string link: type: string format: URI lowerBound: type: number selected: type: boolean description: "Should be set to true in the response, if that filter is\ \ actually selected." type: type: string upperBound: type: number description: "Facet entry that describes a numerical interval. If only the lower\ \ value or only the upper value is set, this means it's an open ended interval,\ \ e.g. '< 100' for upper bound only." Product: type: object allOf: - $ref: "#/components/schemas/Document" - type: object properties: variants: type: array description: "for products without variants, it can be null or rather\ \ us a document directly." items: $ref: "#/components/schemas/Document" description: Main product containing the data that is common for all variants. A product may represent a master-variant relation ship. A variant should be associated to a single Product and cannot have variants again - those will be ignored. It should only contain data special to that variant. Data that is common to all variants should be set at master level. ProductSet: type: object discriminator: mapping: dynamic: "#/components/schemas/DynamicProductSet" generic: "#/components/schemas/GenericProductSet" querystring: "#/components/schemas/QueryStringProductSet" static: "#/components/schemas/StaticProductSet" propertyName: type properties: asSeparateSlice: type: boolean name: type: string size: type: integer format: int32 type: type: string variantBoostTerms: type: string QueryStringProductSet: type: object allOf: - $ref: "#/components/schemas/ProductSet" - type: object properties: asSeparateSlice: type: boolean fieldWeights: type: object additionalProperties: type: number format: float filters: type: object additionalProperties: type: string limit: type: integer format: int32 description: The amount of products to pick from that query-string product set minimum: 1 name: type: string query: type: string size: type: integer format: int32 sort: type: string type: type: string variantBoostTerms: type: string RangeFacetEntry: type: object allOf: - $ref: "#/components/schemas/FacetEntry" - type: object properties: docCount: type: integer format: int64 description: "Estimated amount of documents that will be returned, if\ \ this facet entry is picked as filter." id: type: string key: type: string link: type: string format: URI lowerBound: type: number selected: type: boolean description: "Should be set to true in the response, if that filter is\ \ actually selected." selectedMax: type: number selectedMin: type: number type: type: string upperBound: type: number description: "Facet entry that describes the complete range of the facet. If\ \ a filter is picked, the selectedMin and selectedMax value are set, otherwise\ \ null." ResultHit: type: object description: the list of actual hits for that result view. properties: document: $ref: "#/components/schemas/Document" index: type: string matchedQueries: type: array items: type: string metaData: type: object additionalProperties: type: object SearchQuery: type: object properties: limit: type: integer format: int32 description: The amount of products to return in the result minimum: 1 offset: type: integer format: int32 description: The amount of products to omit from the whole result to select the returned results. minimum: 0 q: type: string description: the user query example: blue shirt sort: type: string description: "Full sorting parameter value. This is the name of the sorting\ \ and optionally a dash as prefix, thats means the sorting should be descending.\ \ Several sorting criterion can be defined by separating the values using\ \ comma." example: "sort=price,-name (price asc and name descending)" withFacets: type: boolean description: flag to specify if facets should be returned with the requested response. Should be set to false in case only the next batch of hits is requested (e.g. for endless scrolling). SearchResult: type: object properties: inputURI: type: string format: URI description: The URI that was used to get that result view. May be used to generate breadcrumbs. meta: type: object additionalProperties: type: object slices: type: array description: "The result may consist of several slices, for example if a\ \ search request couldn't be answered matching all words (e.g. \"striped\ \ nike shirt\") then one slice could be the result for one part of the\ \ query (e.g. \"striped shirt\") and the other could be for another part\ \ of the query (e.g. \"nike shirt\"). This can also be used to deliver\ \ some special advertised products or to split the result in different\ \ ranked slices (e.g. the first 3 results are ranked by popularity, the\ \ next 3 are sorted by price and the rest is ranked by 'default' relevance).\ \ Each slice contains the {@link SearchQuery} that represent that exact\ \ slice. At least 1 slice should be expected. If there is no slice, no\ \ results were found." items: $ref: "#/components/schemas/SearchResultSlice" sortOptions: type: array items: $ref: "#/components/schemas/Sorting" tookInMillis: type: integer format: int64 description: amount of time the internal search needed to compute that result SearchResultSlice: type: object description: "The result may consist of several slices, for example if a search\ \ request couldn't be answered matching all words (e.g. \"striped nike shirt\"\ ) then one slice could be the result for one part of the query (e.g. \"striped\ \ shirt\") and the other could be for another part of the query (e.g. \"nike\ \ shirt\"). This can also be used to deliver some special advertised products\ \ or to split the result in different ranked slices (e.g. the first 3 results\ \ are ranked by popularity, the next 3 are sorted by price and the rest is\ \ ranked by 'default' relevance). Each slice contains the {@link SearchQuery}\ \ that represent that exact slice. At least 1 slice should be expected. If\ \ there is no slice, no results were found." properties: facets: type: array description: "If facets are part of this slice, they are placed here. By\ \ default only one slice SHOULD contain facets." items: $ref: "#/components/schemas/Facet" hits: type: array description: the list of actual hits for that result view. items: $ref: "#/components/schemas/ResultHit" label: type: string description: An identifier for that result slice. Can be used to differentiate different slices. Values depend on the implementation. matchCount: type: integer format: int64 description: the absolute number of matches in this result. nextLink: type: string format: URI description: "URL conform query parameters, that has to be used to get the\ \ next bunch of results. Is null if there are no more results." nextOffset: type: integer format: int64 description: the offset value to use to get the next result batch resultLink: type: string format: URI description: "The query that represents exact that passed slice. If send\ \ to the engine again, that slice should be returned as main result." Sorting: type: object properties: active: type: boolean field: type: string isActive: type: boolean label: type: string link: type: string format: URI sortOrder: type: string enum: - asc - desc StaticProductSet: type: object allOf: - $ref: "#/components/schemas/ProductSet" - type: object properties: asSeparateSlice: type: boolean ids: type: array items: type: string name: type: string size: type: integer format: int32 type: type: string variantBoostTerms: type: string Suggestion: type: object properties: payload: type: object additionalProperties: type: string description: "arbitrary payload attached to that suggestion. Default:\ \ null" description: "arbitrary payload attached to that suggestion. Default: null" phrase: type: string description: The phrase that is suggested and/or used as suggestion label. type: type: string description: "Optional type of that suggestion. Should be different for\ \ the different kind of suggested data. Default: 'keyword'" example: "keyword, brand, category, product" securitySchemes: basic-auth: scheme: basic type: http