> ## Documentation Index
> Fetch the complete documentation index at: https://docs.salesive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Marketplace search

> How the marketplace ranks a query across app names, categories, tags and descriptions, when a result carries a score, and how the typeahead suggestions work.

## Overview

The marketplace listing accepts a `q` query and ranks the catalog against it.
The ranker is lexical and deterministic: it folds case and accents, matches
tokens across every searchable field, and turns common merchant intents into the
categories and tags the catalog uses. There is no embedding service behind it.

Search runs on `GET /api/v1/apps/marketplace`:

```http theme={null}
GET /api/v1/apps/marketplace?q=shipping&shopType=ecommerce
Authorization: Bearer <merchant-session-token>
```

The listing is for the **merchant dashboard**, so send the merchant's session
token. An `app_` token cannot call it.

## What a query searches

A query is folded to lowercase, stripped of accents, and split into word tokens.
One character tokens are dropped. The full phrase is kept as well when the query
contains a space.

Each term is matched against:

| Field | What it holds |
| - | - |
| `name` | The app's name |
| `tagline` | The short line on the listing card |
| `description` | The long description |
| `category` | The curated category, such as `marketing` or `fulfillment` |
| `tags` | The app's tags |
| `developerName` | The developer's name |

Synonyms widen the candidate set before scoring. If the query is `shipping`, the
listing also considers apps that mention `delivery`, `fulfillment` or
`logistics`, so an app that solves the problem under a different word is not
missed.

## Ranking

Scores are built in tiers. The tiers are spaced far enough apart that no amount
of lower tier scoring can overturn a higher tier.

| Match | Points |
| - | - |
| App name equals the query | 100,000 |
| App name starts with the query | 10,000 |
| App name contains the query | 5,000 |
| Category equals the query | 150 |
| Category contains the query | 90 |
| Tagline contains the query | 120 |
| A tag equals the query | 100 |
| Developer name contains the query | 60 |
| Description contains the query | 40 |

Below the name tiers, each query token is matched against every field. An exact
token match earns the field's full weight:

| Field | Points per exact token |
| - | - |
| `name` | 80 |
| `category` | 34 |
| `tagline` | 30 |
| `tags` | 26 |
| `developerName` | 14 |
| `description` | 8 |

A token that is a prefix of a word earns 60 percent of the field weight, and a
mid-word substring earns 30 percent. A single query token contributes at most
**160 points** across all fields, so a long description cannot run away with the
score.

Synonyms add one contribution per token, using the strongest match only:

| Where the synonym appears | Points |
| - | - |
| The app's category | 45 |
| One of the app's tags | 35 |
| The tagline or description | 8 |

## Store type and tie breakers

When the listing has a `shopType`, an app that fits it gets a bounded bonus. This
is a bonus on a match, never a reason to include an app: an unrelated app in the
right store type still scores zero.

| Situation | Points |
| - | - |
| The app declares no store types, so it fits every store | 25 |
| The app declares the requested store type | 35 |
| The app declares other store types only | 0 |

Two fractional tie breakers are added to apps that already matched. They are
always smaller than one lexical point, so social proof can reorder equal matches
but can never pull in a stranger.

| Tie breaker | Maximum |
| - | - |
| Average rating, scaled from 0 to 5 | 0.4 |
| Live installs, capped at 10,000 | 0.3 |

The final score is rounded to six decimals. The integer part carries the lexical
score and the fraction carries the tie breakers, so an install count one apart
still breaks a tie.

## The score field

A search result carries `score`:

```json theme={null}
{
  "name": "ShipStation",
  "slug": "shipstation",
  "tagline": "Shipping and fulfillment for ecommerce",
  "score": 218.6375
}
```

`score` is present **only when `q` is present and not blank**. Browsing the
marketplace without a query keeps the older response shape and has no `score`
field. A blank query is treated as no query.

## Sort and pagination

`sort` still applies while a search is active, but the score is always the
default order:

| `sort` | Order |
| - | - |
| `relevance` (default) | Score, then app name. A featured app gets no bonus here |
| `installs` | Featured first, then live installs, then score, then name |
| `rating` | Featured first, then average rating, then rating count, then score, then name |
| `newest` | Featured first, then creation time, then score, then name |

An unknown `sort` falls back to `relevance`.

Search scores at most **500** candidates after the database has narrowed the
catalog to apps that mention a query term. `total` is the number of apps that
scored above zero, not the size of the whole catalog. Pagination slices that
ranked list.

## Suggestions

The search box can ask for typeahead suggestions:

```http theme={null}
GET /api/v1/apps/marketplace/suggestions?q=ship
Authorization: Bearer <merchant-session-token>
```

```json theme={null}
{
  "status": 200,
  "success": true,
  "message": "Marketplace suggestions retrieved",
  "data": {
    "suggestions": [
      { "text": "Fulfillment", "type": "category" },
      { "text": "ShipStation", "type": "app" }
    ]
  }
}
```

* It returns up to **8** items.
* Categories come first, at most **3**, then app names in rank order.
* `type` is `category` or `app`.
* A category is suggested when its slug or display label starts with the query,
  or when the query maps to it through a synonym. For example, `email` suggests
  `Marketing`.
* An app name is suggested when the app matches the query through its name,
  tagline, category or tags.
* Suggestions are deduplicated case-insensitively, and a suggestion equal to the
  query itself is dropped.
* An empty or blank `q` returns an empty list.
* The typeahead reads at most **60** candidates and uses the same auth gate as
  the listing.

## Intent synonyms

These are the supported synonyms. The key is what a merchant may type; the values
are terms the catalog actually uses.

| Query token | Also searches for |
| - | - |
| `email` | `email`, `newsletter`, `campaigns`, `marketing` |
| `whatsapp` | `whatsapp`, `chat`, `messaging`, `customer-service` |
| `instagram` | `instagram`, `social`, `marketing` |
| `seo` | `seo`, `search`, `marketing` |
| `reviews` | `reviews`, `ratings`, `customer-service`, `marketing` |
| `shipping` | `shipping`, `delivery`, `fulfillment`, `logistics` |
| `inventory` | `inventory`, `stock`, `catalog`, `fulfillment` |
| `loyalty` | `loyalty`, `rewards`, `points`, `marketing` |
| `upsell` | `upsell`, `cross-sell`, `recommendations`, `sales`, `marketing` |
| `returns` | `returns`, `refunds`, `exchanges`, `fulfillment`, `customer-service` |

A token that is not in this list still searches its own text. The map only adds
terms; it never replaces the query.

## Next steps

> [card] [Marketplace listing](https://docs.salesive.com/apps-api/marketplace.md)
>
> The full listing contract, install consent and the consent ticket.

> [card] [Developer analytics](https://docs.salesive.com/apps-api/developer-analytics.md)
>
> See how installs and ratings move after a listing change.

> [card] [Building and publishing](https://docs.salesive.com/apps/building-publishing.md)
>
> Name, tagline, category and tags are part of what a merchant searches.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.