# OTTO Product Search API Documentation

Scrappa's `GET /api/otto/search` returns OTTO (otto.de) products for a search query as structured JSON. A page holds up to 120 products.

## What you get

Each product has `id`, `variation_id`, `article_number`, `title`, `brand`, `category`, `url`, `price`, `original_price`, `discount_percent`, `currency`, `on_sale`, `price_from`, `rating`, `review_count`, `availability`, `multiple_sizes`, `colors` and `images`. Use `id` with the product and reviews endpoints. `total` is the number of matches OTTO reports.

## Prices

Prices are numbers in `currency` (EUR). `price` is the current price. For reduced products `original_price` is the list price (UVP) and `discount_percent` the saving. `price_from` is `true` when OTTO shows an "ab" price for a product with several variations.

## Filters are honoured

`brand`, `color`, `min_price`, `max_price` and `on_sale` are part of the search itself. `on_sale=true` also returns products with an extra discount (`extra_discount`, for example "-20% Extra"). `min_price` and `max_price` are whole euros: `min_price=50&max_price=100` returns prices from 50,00 to 100,00 (both ends included). Every returned price is checked, and a product that breaks a filter is removed. `filtered_out` counts them. If no product matches, `items` is empty and `total` is 0. OTTO's "similar products" fallback is never returned.

Use the brand as search results show it (for example `Marikoo` or `Levi's`). `color` is one of schwarz, weiss, grau, blau, rot, gruen, gelb, braun, beige, rosa, lila, orange, bunt.

## Sort and pages

`sort` is `relevance` (default), `rating`, `price_low_to_high` or `price_high_to_low`. `page` is 1-100. A page past the last result returns an empty `items` list, never page 1. Umlauts in `query` are handled for you.

## Credits

A successful search costs **1 credit**. If the usual route fails and the search has to use a more expensive route, it costs 1 credits instead. Errors, blocks and `404` answers cost nothing. The response shows the charge in `meta.credits_charged`.

- **Documentation:** [https://scrappa.co/docs/otto-api/otto_search](https://scrappa.co/docs/otto-api/otto_search)
- **API group:** OTTO API
- **Endpoint:** `GET https://scrappa.co/api/otto/search`

## Authentication

Send your Scrappa API key in the `X-API-KEY` request header. Paid endpoints also support accountless x402 payments when called without an API key.

## Parameters

| Parameter | Type | Required | Description |
| --- | --- | --- | --- |
| `query` | string | Yes | Search words, for example winterjacke damen. |
| `brand` | string | No | Brand as OTTO shows it, for example Marikoo. Only this brand is returned. |
| `color` | string | No | Base colour: schwarz, weiss, grau, blau, rot, gruen, gelb, braun, beige, rosa, lila, orange, bunt. |
| `min_price` | integer | No | Lowest price in whole euros. |
| `max_price` | integer | No | Highest price in whole euros. Must not be lower than min_price. |
| `on_sale` | boolean | No | true for reduced products only. |
| `sort` | string | No | relevance (default), rating, price_low_to_high or price_high_to_low. |
| `page` | integer | No | Result page of 120 products, 1-100. |

## Example request

```bash
#!/bin/bash

curl -X GET \
    -H "x-api-key: YOUR_API_KEY_HERE" \
    "https://scrappa.co/api/otto/search?query=winterjacke+damen&max_price=100&on_sale=true"
```

## Example response

```json
{
    "success": true,
    "query": "winterjacke damen",
    "items": [
        {
            "position": 1,
            "id": "C774733826",
            "variation_id": "1172134399",
            "article_number": "50293859",
            "title": "Marikoo Outdoorjacke Erdbeere sportliche Funktionsjacke mit Kapuze",
            "brand": "Marikoo",
            "category": "Jacken",
            "url": "https://www.otto.de/p/marikoo-outdoorjacke-erdbeere-sportliche-funktionsjacke-mit-kapuze-C774733826/?variationId=1172134399",
            "price": 79.9,
            "original_price": 119.9,
            "discount_percent": 33,
            "currency": "EUR",
            "price_from": false,
            "on_sale": true,
            "extra_discount": null,
            "rating": 4.5,
            "review_count": 773,
            "availability": {
                "state": "AVAILABLE",
                "text": "lieferbar - in 3-4 Werktagen bei dir"
            },
            "multiple_sizes": true,
            "colors": [
                {
                    "name": "weinrot",
                    "base_color": "rot",
                    "hex": "#60303B",
                    "variation_id": "1172134399",
                    "selected": true
                }
            ],
            "images": [
                "https://i.otto.de/i/otto/f0f6fe49-54fc-5a0d-a2a2-800c86483c4f?$formatz$"
            ]
        }
    ],
    "total": 1985,
    "page": 1,
    "page_size": 120,
    "has_more": true,
    "sort": "relevance",
    "applied_filters": {
        "max_price": 100,
        "on_sale": true
    },
    "filtered_out": 0,
    "meta": {
        "endpoint_family": "otto-search",
        "billable": true,
        "attempts": 2,
        "credits_charged": 1
    }
}
```

## Errors

| Status | Error | Description |
| --- | --- | --- |
| 422 | Filter Not Applied | OTTO rejected the search rule built from your filters (`upstream_rejected`). The request fails instead of returning unfiltered products. Non-billable. |
| 422 | Validation Error | A query parameter is missing, unknown or unusable. Unknown parameters are rejected, never ignored. Non-billable. |
| 503 | Upstream Unavailable | OTTO could not be reached in time or answered with a block or an unexpected page (`upstream_unavailable`, `upstream_blocked`, `parser_drift`). Retryable and never billed. Clients are never rate limited. |

## More Scrappa resources

- [API documentation](https://scrappa.co/docs)
- [Full LLM-readable API reference](https://scrappa.co/llms-full.txt)
- [OpenAPI specification](https://scrappa.co/docs/api.json)
- [Pricing](https://scrappa.co/pricing)
