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

# POST /api/search — compare item prices across platforms

> Search for a restaurant and dish to get a ranked price comparison across HungerStation, Keeta, and Jahez with real totals including delivery fees and VAT.

Send a natural-language query — in Arabic or English — and PRIXO returns a ranked price comparison for the matched dish across every platform that carries it. The response includes real delivery totals with fees and VAT factored in, so you can see exactly what you would pay before you order.

## Endpoint

```
POST /api/search
```

## Authentication

Not required. This endpoint is fully public.

## Rate limit

No rate limit applies to this endpoint.

## Request

Set `Content-Type: application/json` and send a JSON body with a single `query` field.

### Body parameters

<ParamField body="query" type="string" required>
  A natural-language search query in Arabic or English. You can include the restaurant name, dish name, or both. For example: `"شاورما ماما نورة"` or `"mama noura shawarma"`.
</ParamField>

### Example request

```json theme={null}
{ "query": "شاورما ماما نورة" }
```

```bash theme={null}
curl -X POST https://prixo.ai/api/search \
  -H "Content-Type: application/json" \
  -d '{"query": "شاورما ماما نورة"}'
```

## Response

The response is a JSON object with the top-level fields `intent`, `matches`, `emptyReason`, and `discoveredViaGoogle`.

### Top-level fields

<ResponseField name="intent" type="object">
  The structured search intent that PRIXO extracted from your query.

  <Expandable title="intent fields">
    <ResponseField name="intent.restaurant" type="string">
      The restaurant name extracted from the query.
    </ResponseField>

    <ResponseField name="intent.item" type="string">
      The dish or menu item extracted from the query.
    </ResponseField>

    <ResponseField name="intent.quantity" type="number">
      The quantity implied by the query. Defaults to `1` when no quantity is mentioned.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="matches" type="array">
  An array of brand matches. Each entry pairs a matched restaurant brand with a full price comparison across platforms. May be empty when no results are found — see `emptyReason`.

  <Expandable title="matches[n] fields">
    <ResponseField name="matches[n].brand" type="object">
      The matched restaurant brand.

      <Expandable title="brand fields">
        <ResponseField name="matches[n].brand.id" type="string">
          Unique identifier for the brand in the PRIXO database.
        </ResponseField>

        <ResponseField name="matches[n].brand.name" type="string">
          Display name of the restaurant brand.
        </ResponseField>

        <ResponseField name="matches[n].brand.is_brand" type="boolean">
          `true` if this entry represents a chain with multiple branches. `false` for single-location restaurants.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="matches[n].comparison" type="object">
      The price comparison result for the matched item at this brand.

      <Expandable title="comparison fields">
        <ResponseField name="matches[n].comparison.ranked" type="array">
          Platforms sorted from cheapest to most expensive total. Each entry represents one platform.

          <Expandable title="ranked[n] fields">
            <ResponseField name="matches[n].comparison.ranked[n].platform" type="string">
              Platform identifier. One of `"hungerstation"`, `"keeta"`, or `"jahez"`.
            </ResponseField>

            <ResponseField name="matches[n].comparison.ranked[n].total" type="number">
              The full amount you pay, including item price, delivery fee, and VAT, in Saudi Riyals (SAR).
            </ResponseField>

            <ResponseField name="matches[n].comparison.ranked[n].itemPrice" type="number">
              The price of the item itself, before fees, in SAR.
            </ResponseField>

            <ResponseField name="matches[n].comparison.ranked[n].deliveryFee" type="number">
              The delivery fee charged by this platform, in SAR.
            </ResponseField>

            <ResponseField name="matches[n].comparison.ranked[n].confidence" type="string">
              How reliable this price data is. One of `"high"`, `"medium"`, or `"low"`.
            </ResponseField>

            <ResponseField name="matches[n].comparison.ranked[n].status" type="string">
              Verification status of the price. One of `"verified"`, `"unverified"`, or `"stale"`.
            </ResponseField>
          </Expandable>
        </ResponseField>

        <ResponseField name="matches[n].comparison.winner" type="string">
          The platform with the lowest total. One of `"hungerstation"`, `"keeta"`, or `"jahez"`.
        </ResponseField>

        <ResponseField name="matches[n].comparison.savings" type="number">
          The SAR difference between the cheapest and most expensive platform total. Shows how much you save by picking the winner.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="emptyReason" type="string | null">
  Explains why `matches` is empty. `null` when results were found. See the [Empty reason values](#empty-reason-values) section below.
</ResponseField>

<ResponseField name="discoveredViaGoogle" type="boolean">
  `true` when the restaurant was not in the PRIXO database and was discovered via a Google Maps lookup instead. Prices may be limited or unavailable for Google-discovered restaurants.
</ResponseField>

### Example response

```json theme={null}
{
  "intent": {
    "restaurant": "ماما نورة",
    "item": "شاورما",
    "quantity": 1
  },
  "matches": [
    {
      "brand": {
        "id": "brand_mama_noura_01",
        "name": "ماما نورة",
        "is_brand": true
      },
      "comparison": {
        "ranked": [
          {
            "platform": "hungerstation",
            "total": 15.5,
            "itemPrice": 10.5,
            "deliveryFee": 5.0,
            "confidence": "high",
            "status": "verified"
          },
          {
            "platform": "keeta",
            "total": 17.0,
            "itemPrice": 11.0,
            "deliveryFee": 6.0,
            "confidence": "medium",
            "status": "verified"
          },
          {
            "platform": "jahez",
            "total": 18.0,
            "itemPrice": 10.5,
            "deliveryFee": 7.5,
            "confidence": "high",
            "status": "verified"
          }
        ],
        "winner": "hungerstation",
        "savings": 2.5
      }
    }
  ],
  "emptyReason": null,
  "discoveredViaGoogle": false
}
```

## Empty reason values

When `matches` is an empty array, `emptyReason` tells you why:

| Value                  | Meaning                                                                                                                                          |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `restaurant_not_found` | PRIXO could not match any restaurant to your query, even via Google. Try a different spelling or the restaurant's full name.                     |
| `item_not_in_db`       | The restaurant was found but the specific dish is not yet in the PRIXO database. You can help by [submitting a price snapshot](/api/snapshots).  |
| `no_prices_yet`        | The dish exists in the database but no community prices have been submitted for it yet. Be the first to [contribute a snapshot](/api/snapshots). |

<Note>
  All prices are in **Saudi Riyals (SAR)** and include VAT where applicable. PRIXO does not add any markup — totals reflect what the delivery platforms charge.
</Note>

<Tip>
  Queries work best when you include both the restaurant name and the dish name. Single-word queries like `"شاورما"` still work but may return multiple brand matches.
</Tip>
