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

# Search

> Premium multi-source search with LLM analysis — relevant results already ranked.

# Search

`POST /search` starts an asynchronous premium search. It queries multiple web
sources and applies LLM judgment to select and summarize the most relevant
results.

## Endpoint

```
POST /search
```

## Authentication

`X-API-Key` header required. See [Authentication](/en/authentication).

## Parameters

<ParamField body="query" type="string" required>
  Search text. Must contain at least 1 character.
</ParamField>

<ParamField body="num_results" type="integer" default="10">
  Desired number of final results (10–100).
</ParamField>

<ParamField body="country" type="string">
  ISO 3166-1 alpha-2 code to restrict results by region (e.g. `BR`, `US`, `GB`).
</ParamField>

<ParamField body="include_domains" type="string[]">
  Restrict results to these domains (up to 20). Exact hostname or subdomain.
</ParamField>

<ParamField body="exclude_domains" type="string[]">
  Omit results from these domains (up to 20). Must not overlap with `include_domains`.
</ParamField>

<ParamField body="freshness" type="string">
  Time window for results: `day`, `week`, `month`, `year`. Omit for no filter.
</ParamField>

<ParamField body="timeout_seconds" type="integer">
  Search duration limit in seconds (15–120). Omit to use the worker default timeout.
</ParamField>

<ParamField body="tags" type="string[]">
  Attribution tags for usage records (up to 10 tags).
</ParamField>

## Cost

**1 credit per returned result** (charged for effective results, not requested count).

The pre-check requires balance ≥ requested `num_results` (worst case). If the
balance is insufficient, the API returns `402`.

## Asynchronous flow

1. Send `POST /search` → receive `202` with `job_id`
2. Poll via `GET /jobs/{job_id}` every 2s
3. When `status: "SUCCESS"`, results are in the `results` field

<Note>
  The `stopped_reason` field may be `token_cap` if the LLM token limit was hit before all sources were processed.
</Note>

## Example

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://api.messora.dev/search \
    -H "Content-Type: application/json" \
    -H "X-API-Key: YOUR_API_KEY" \
    -d '{
      "query": "best Python frameworks 2025",
      "num_results": 10,
      "country": "US",
      "freshness": "year"
    }'
  ```

  ```python Python theme={null}
  import requests
  import time

  # 1. Start the search
  response = requests.post(
      "https://api.messora.dev/search",
      headers={
          "Content-Type": "application/json",
          "X-API-Key": "YOUR_API_KEY",
      },
      json={
          "query": "best Python frameworks 2025",
          "num_results": 10,
          "country": "US",
          "freshness": "year",
      },
  )

  job_id = response.json()["job_id"]
  print(f"Job created: {job_id}")

  # 2. Poll until complete
  while True:
      status = requests.get(
          f"https://api.messora.dev/jobs/{job_id}",
          headers={"X-API-Key": "YOUR_API_KEY"},
      ).json()

      if status["status"] in ("SUCCESS", "FAILURE"):
          break
      time.sleep(2)

  # 3. Results
  for result in status.get("results", []):
      print(result)
  ```

  ```javascript JavaScript theme={null}
  // 1. Start the search
  const res = await fetch("https://api.messora.dev/search", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-API-Key": "YOUR_API_KEY",
    },
    body: JSON.stringify({
      query: "best Python frameworks 2025",
      num_results: 10,
      country: "US",
      freshness: "year",
    }),
  });

  const { job_id } = await res.json();
  console.log(`Job created: ${job_id}`);

  // 2. Poll until complete
  let status;
  do {
    await new Promise((r) => setTimeout(r, 2000));
    const poll = await fetch(
      `https://api.messora.dev/jobs/${job_id}`,
      { headers: { "X-API-Key": "YOUR_API_KEY" } }
    );
    status = await poll.json();
  } while (!["SUCCESS", "FAILURE"].includes(status.status));

  // 3. Results
  console.log(status.results);
  ```
</CodeGroup>

## Successful response (via polling)

```json theme={null}
{
  "status": "SUCCESS",
  "job_id": "550e8400-e29b-41d4-a716-446655440001",
  "results": [
    {
      "title": "Top Python Frameworks",
      "url": "https://example.com/frameworks",
      "snippet": "An overview of the most used frameworks..."
    }
  ],
  "credits_used": 10,
  "stopped_reason": null
}
```

## Errors

| HTTP Status | Description                                     |
| ----------- | ----------------------------------------------- |
| `401`       | Missing `X-API-Key`                             |
| `402`       | Insufficient credits (balance \< `num_results`) |
| `403`       | Invalid or revoked API key                      |
| `422`       | Empty query or invalid parameters               |
| `429`       | Rate limit exceeded (2 req/min)                 |
