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

# Such-API

> Durchsuche das Web mit natürlicher Sprache und erhalte strukturierte Links — Olosteps KI-Such-API.

Der Olostep-Endpunkt `/v1/searches` ermöglicht es dir, das Web mit einer natürlichen Sprachabfrage zu durchsuchen und eine deduplizierte Liste relevanter Links mit Titeln und Beschreibungen zurückzubekommen.

* Sende eine Abfrage in einfachem Englisch
* Erhalte strukturierte Links aus dem gesamten Web
* Optional kannst du jede zurückgegebene URL in einem Durchgang scrapen und `markdown_content` / `html_content` direkt in die Antwort einbetten
* Filtere nach Domain, kontrolliere die Anzahl der Ergebnisse und begrenze die Scraping-Zeit

Die Abfrage wird semantisch im gesamten Web durchsucht und Ergebnisse werden zurückgegeben.

Für API-Details siehe die [API-Referenz des Suchendpunkts](/api-reference/searches/create).

## Installation

<CodeGroup>
  ```python Python theme={null}
  pip install olostep
  ```

  ```javascript Node theme={null}
  npm install olostep
  ```

  ```bash cURL theme={null}
  # curl ist standardmäßig auf macOS, Linux und Windows verfügbar
  ```

  ```javascript Node (API) theme={null}
  npm install node-fetch
  ```

  ```bash Python (API) theme={null}
  pip install requests
  ```
</CodeGroup>

## Grundlegende Nutzung

Sende eine Abfrage in natürlicher Sprache und erhalte eine Liste relevanter Links.

<CodeGroup>
  ```python Python theme={null}
  from olostep import Olostep

  client = Olostep(api_key="YOUR_REAL_KEY")

  search = client.searches.create("Best Answer Engine Optimization startups")

  print(search.id, len(search.links))
  ```

  ```js Node theme={null}
  import Olostep from 'olostep'

  const client = new Olostep({ apiKey: 'YOUR_REAL_KEY' })

  const search = await client.searches.create('Best Answer Engine Optimization startups')

  console.log(search.id, search.links.length)
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/v1/searches" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "Best Answer Engine Optimization startups"
    }'
  ```

  ```js Node (API) theme={null}
  const res = await fetch('https://api.olostep.com/v1/searches', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: 'Best Answer Engine Optimization startups'
    })
  })
  console.log(await res.json())
  ```

  ```python Python (API) theme={null}
  import requests, json

  endpoint = "https://api.olostep.com/v1/searches"
  payload = {
    "query": "Best Answer Engine Optimization startups"
  }
  headers = {"Authorization": "Bearer <YOUR_API_KEY>", "Content-Type": "application/json"}

  response = requests.post(endpoint, json=payload, headers=headers)
  print(json.dumps(response.json(), indent=2))
  ```
</CodeGroup>

## Anfrageparameter

| Feld              | Typ       | Erforderlich | Standard | Beschreibung                                                                                                                                             |
| ----------------- | --------- | ------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `query`           | string    | ja           | —        | Die Suchabfrage in natürlicher Sprache.                                                                                                                  |
| `limit`           | integer   | nein         | `12`     | Maximale Anzahl an Links, die nach Deduplikation zurückgegeben werden. Muss zwischen `1` und `25` liegen.                                                |
| `include_domains` | string\[] | nein         | `[]`     | Beschränke Ergebnisse auf diese Domains. Nur Hostnamen — führende `http(s)://` und nachfolgende Schrägstriche werden automatisch entfernt.               |
| `exclude_domains` | string\[] | nein         | `[]`     | Schließe Ergebnisse von diesen Domains aus. Nur Hostnamen — führende `http(s)://` und nachfolgende Schrägstriche werden automatisch entfernt.            |
| `scrape_options`  | object    | nein         | —        | Wenn angegeben, wird jeder zurückgegebene Link auch gescrapt und sein Inhalt in die Antwort eingebettet. Siehe [scrape\_options](#scrape-options) unten. |

### Begrenzung der Anzahl der Ergebnisse

```json theme={null}
{
  "query": "What's going on with OpenAI's Sora shutting down?",
  "limit": 5
}
```

### Filtern nach Domain

`include_domains` beschränkt Ergebnisse auf eine Whitelist; `exclude_domains` filtert unerwünschte Quellen aus. Sie können kombiniert werden.

```json theme={null}
{
  "query": "OpenAI Sora shutdown analysis",
  "include_domains": ["nytimes.com", "wsj.com", "bbc.com"],
  "exclude_domains": ["pinterest.com"]
}
```

## scrape\_options

Übergebe `scrape_options`, um jede zurückgegebene URL parallel zu scrapen und den gerenderten Inhalt direkt auf jedem Link einzubetten. Dies spart eine Hin- und Rückfahrt pro Ergebnis im Vergleich zum separaten Aufruf von `/v1/searches` und `/v1/scrapes`.

```json theme={null}
{
  "query": "What's going on with OpenAI's Sora shutting down?",
  "limit": 10,
  "scrape_options": {
    "formats": ["markdown"],
    "remove_css_selectors": "default",
    "timeout": 25
  }
}
```

| Feld                   | Typ       | Standard       | Beschreibung                                                                                                                                                                                                                              |
| ---------------------- | --------- | -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `formats`              | string\[] | `["markdown"]` | Ausgabeformate, die jedem Link angehängt werden. Für `/v1/searches` werden nur `"html"` und `"markdown"` unterstützt. Übergebe `["html", "markdown"]`, um beide zu erhalten.                                                              |
| `remove_css_selectors` | string    | `"default"`    | Weitergeleitet an `/v1/scrapes`. `"default"` entfernt Navigations-/Fußzeilen-/Skript-/Stil-/SVG-/Dialoggeräusche. Verwende `"none"`, um zu deaktivieren, oder übergebe ein JSON-String-Array von Selektoren, die entfernt werden sollen.  |
| `timeout`              | integer   | `25`           | Zeitbudget in **Sekunden** für die gesamte Scraping-Phase. Muss zwischen `1` und `60` liegen. Wenn diese Zeit abläuft, wird die Suche sofort zurückgegeben — Inhaltsfelder sind `null` für alle Links, die noch nicht abgeschlossen sind. |

### Verhalten

* Alle Links werden **parallel** gescrapt. Der `timeout` begrenzt das gesamte Batch, nicht jeden einzelnen Link.
* Bei Scraping-Fehlern pro Link (Netzwerkfehler, individuelle Seitenauszeiten) bleibt der `markdown_content` / `html_content` dieses Links `null`, während andere Links normal zurückkehren.
* Wenn der globale `timeout` abläuft, bevor alle Scrapes abgeschlossen sind, antwortet die Suche sofort mit den Links, die sie hat — bereits abgeschlossene Scrapes behalten ihren Inhalt; in Bearbeitung befindliche kommen mit `null`-Inhalt zurück.
* Für `reddit.com/.../comments/...` URLs wird die Anfrage automatisch über den `@olostep/reddit-post` Parser geleitet und das strukturierte JSON wird in sauberes Markdown + einfaches HTML gerendert.
* Wenn der kombinierte Inline-Inhalt 9MB überschreitet, werden Inhaltsfelder genullt, `result.size_exceeded` wird auf `true` gesetzt, und du kannst die vollständige Nutzlast von `result.json_hosted_url` abrufen.

### Beispiel mit Scraping

<CodeGroup>
  ```python Python theme={null}
  from olostep import Olostep

  client = Olostep(api_key="YOUR_REAL_KEY")

  search = client.searches.create(
      query="What's going on with OpenAI's Sora shutting down?",
      limit=5,
      scrape_options={"formats": ["markdown"], "timeout": 25},
  )

  for link in search.links:
      print(link["url"], "—", len(link.get("markdown_content") or ""), "chars")
  ```

  ```js Node theme={null}
  import Olostep, { Format } from 'olostep'

  const client = new Olostep({ apiKey: 'YOUR_REAL_KEY' })

  const search = await client.searches.create({
    query: "What's going on with OpenAI's Sora shutting down?",
    limit: 5,
    scrapeOptions: {
      formats: [Format.MARKDOWN],
      timeout: 25
    }
  })

  for (const link of search.links) {
    console.log(link.url, '—', (link.markdown_content || '').length, 'chars')
  }
  ```

  ```bash cURL theme={null}
  curl -s -X POST "https://api.olostep.com/v1/searches" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "query": "What'"'"'s going on with OpenAI'"'"'s Sora shutting down?",
      "limit": 5,
      "scrape_options": {
        "formats": ["markdown"],
        "timeout": 25
      }
    }'
  ```

  ```js Node (API) theme={null}
  const res = await fetch('https://api.olostep.com/v1/searches', {
    method: 'POST',
    headers: { 'Authorization': 'Bearer <YOUR_API_KEY>', 'Content-Type': 'application/json' },
    body: JSON.stringify({
      query: "What's going on with OpenAI's Sora shutting down?",
      limit: 5,
      scrape_options: {
        formats: ['markdown'],
        timeout: 25
      }
    })
  })
  const data = await res.json()
  for (const link of data.result.links) {
    console.log(link.url, '—', (link.markdown_content || '').length, 'chars')
  }
  ```

  ```python Python (API) theme={null}
  import requests, json

  endpoint = "https://api.olostep.com/v1/searches"
  payload = {
    "query": "What's going on with OpenAI's Sora shutting down?",
    "limit": 5,
    "scrape_options": {
      "formats": ["markdown"],
      "timeout": 25
    }
  }
  headers = {"Authorization": "Bearer <YOUR_API_KEY>", "Content-Type": "application/json"}

  response = requests.post(endpoint, json=payload, headers=headers)
  data = response.json()
  for link in data["result"]["links"]:
    print(link["url"], "—", len(link.get("markdown_content") or ""), "chars")
  ```
</CodeGroup>

## Antwort

Du erhältst ein `search`-Objekt als Antwort. Das `search`-Objekt enthält eine `id`, deine ursprüngliche `query`, `credits_consumed` und ein `result` mit einer Liste von `links`.

```json theme={null}
{
  "id": "search_9bi0sbj9xa",
  "object": "search",
  "created": 1760327323,
  "metadata": {},
  "query": "What's going on with OpenAI's Sora shutting down?",
  "credits_consumed": 10,
  "result": {
    "json_content": "...",
    "json_hosted_url": "https://olostep-storage.s3.us-east-1.amazonaws.com/search_9bi0sbj9xa.json",
    "size_exceeded": false,
    "credits_consumed": 10,
    "links": [
      {
        "url": "https://www.bbc.com/news/articles/c3w3e467ewqo",
        "title": "OpenAI to shut down Sora video platform",
        "description": "OpenAI says it will discontinue its Sora app...",
        "markdown_content": "# OpenAI to shut down Sora video platform\n\nOpenAI says it will discontinue..."
      },
      {
        "url": "https://www.reddit.com/r/OutOfTheLoop/comments/1s2u847/whats_going_on_with_openais_sora_shutting_down/",
        "title": "What's going on with OpenAI's Sora shutting down?",
        "description": "Reddit thread discussing the shutdown.",
        "markdown_content": "# What's going on with OpenAI's Sora shutting down?\n\n*r/OutOfTheLoop · u/rm-minus-r · 1mo ago*\n\n..."
      }
    ]
  }
}
```

Jeder Link in `result.links` enthält:

| Feld               | Typ    | Beschreibung                                                                                                                                                                                  |
| ------------------ | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `url`              | string | Die URL des Suchergebnisses.                                                                                                                                                                  |
| `title`            | string | Der Titel der Ergebnisseite.                                                                                                                                                                  |
| `description`      | string | Ein kurzer Ausschnitt, der das Ergebnis beschreibt.                                                                                                                                           |
| `markdown_content` | string | Markdown-Inhalt der Seite. Nur vorhanden, wenn `scrape_options.formats` `"markdown"` enthält. `null`, wenn das Scraping fehlgeschlagen ist, leer war oder das globale Timeout erreicht wurde. |
| `html_content`     | string | HTML-Inhalt der Seite. Nur vorhanden, wenn `scrape_options.formats` `"html"` enthält. `null` bei Fehler/Timeout.                                                                              |

Das vollständige Ergebnis ist auch als gehostete JSON-Datei unter `result.json_hosted_url` verfügbar — nützlich, wenn `result.size_exceeded` `true` ist.

## Abrufen einer vergangenen Suche

`GET /v1/searches/{search_id}` gibt alles zurück, was zum Zeitpunkt der Suche gespeichert wurde, einschließlich aller gescrapten Inhalte. Es ist ein reiner idempotenter Lesevorgang — kein erneutes Scraping, keine erneute Abrechnung. Ältere Suchen ohne `scrape_options` haben einfach keine Inhaltsfelder pro Link.

<CodeGroup>
  ```python Python theme={null}
  from olostep import Olostep

  client = Olostep(api_key="YOUR_REAL_KEY")

  search = client.searches.get(search_id="search_9bi0sbj9xa")
  print(search.id, len(search.links))
  ```

  ```js Node theme={null}
  import Olostep from 'olostep'

  const client = new Olostep({ apiKey: 'YOUR_REAL_KEY' })

  const search = await client.searches.get('search_9bi0sbj9xa')
  console.log(search.id, search.links.length)
  ```

  ```bash cURL theme={null}
  curl -s "https://api.olostep.com/v1/searches/search_9bi0sbj9xa" \
    -H "Authorization: Bearer $OLOSTEP_API_KEY"
  ```
</CodeGroup>

Siehe [Suche abrufen](/api-reference/searches/get) für vollständige Details.

## Preisgestaltung

Jede Suche kostet **5 Credits** für die Suche selbst.

Wenn `scrape_options` angegeben wird, wird jede gescrapte Seite zum Standardtarif von `/v1/scrapes` berechnet (typischerweise 1 Credit pro Seite; einige Parser kosten mehr). Die Gesamtsumme wird in `credits_consumed` zurückgegeben.

Beispiele:

| Anfrage                                  | `credits_consumed` |
| ---------------------------------------- | ------------------ |
| Nur Suche                                | `5`                |
| Suche + 5 gescrapte Seiten (je 1 Credit) | `10`               |
