# Search API

POST /v1/search

Search the web and vertical data sources through one endpoint. General search only needs query. For a vertical capability, discover its tag and parameter definitions first. The gateway routes the request, combines sources and reranks results.

## Request examples

### General search

Submit query. The gateway routes the request, combines sources and reranks results.

### cURL

### cURL · macOS / Linux / Git Bash

```bash
curl -X POST https://api.anysearch.com/v1/search \
  -H "Authorization: Bearer YOUR_ANYSEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "query": "Global AI Semiconductor Industry Analysis",
  "max_results": 5
}'
```

### Python

### Python 3 · requests

```python
import os
import requests

response = requests.post(
    "https://api.anysearch.com/v1/search",
    headers={
        "Authorization": f"Bearer {os.environ['ANYSEARCH_API_KEY']}",
    },
    json={
        "query": "Global AI Semiconductor Industry Analysis",
        "max_results": 5,
    },
    timeout=30,
)

if not response.ok:
    request_id = response.headers.get("X-Request-ID", "unknown")
    raise RuntimeError(
        f"Request failed: HTTP {response.status_code}; request_id={request_id}"
    )

result = response.json()
print(result["data"])
```

### JavaScript

### JavaScript · Node.js 18+

```javascript
const response = await fetch("https://api.anysearch.com/v1/search", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANYSEARCH_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    query: "Global AI Semiconductor Industry Analysis",
    max_results: 5,
  }),
  signal: AbortSignal.timeout(30_000),
});

if (!response.ok) {
  const requestId = response.headers.get("X-Request-ID") ?? "unknown";
  throw new Error(
    `Request failed: HTTP ${response.status}; request_id=${requestId}`
  );
}

const result = await response.json();
console.log(result.data);
```

### Go

### Go · Standard library

```go
package main

import (
	"encoding/json"
	"fmt"
	"net/http"
	"os"
	"strings"
	"time"
)

func main() {
	req, err := http.NewRequest(
		http.MethodPost,
		"https://api.anysearch.com/v1/search",
		strings.NewReader(`{
			"query": "Global AI Semiconductor Industry Analysis",
			"max_results": 5
		}`),
	)
	if err != nil {
		panic(err)
	}

	req.Header.Set("Authorization", "Bearer "+os.Getenv("ANYSEARCH_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{Timeout: 30 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		requestID := resp.Header.Get("X-Request-ID")
		if requestID == "" {
			requestID = "unknown"
		}

		panic(fmt.Sprintf(
			"Request failed: HTTP %d; request_id=%s",
			resp.StatusCode, requestID,
		))
	}

	var result struct {
		Data json.RawMessage `json:"data"`
	}
	if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
		panic(err)
	}

	fmt.Println(string(result.Data))
}
```

### Rust

### Rust · reqwest + serde_json

```rust
use reqwest::blocking::Client;
use serde_json::{json, Value};
use std::{env, error::Error, time::Duration};

fn main() -> Result<(), Box<dyn Error>> {
    let api_key = env::var("ANYSEARCH_API_KEY")?;

    let client = Client::builder()
        .timeout(Duration::from_secs(30))
        .build()?;

    let response = client
        .post("https://api.anysearch.com/v1/search")
        .bearer_auth(api_key)
        .json(&json!({
            "query": "Global AI Semiconductor Industry Analysis",
            "max_results": 5,
        }))
        .send()?;

    if !response.status().is_success() {
        let request_id = response
            .headers()
            .get("X-Request-ID")
            .and_then(|value| value.to_str().ok())
            .unwrap_or("unknown");

        return Err(format!(
            "Request failed: HTTP {}; request_id={request_id}",
            response.status()
        )
        .into());
    }

    let result: Value = response.json()?;
    println!("{}", result["data"]);

    Ok(())
}
```

### Vertical search

Use the discovered `finance.quote` capability and its required `type: "stock"` parameter.

### cURL

### cURL · macOS / Linux / Git Bash

```bash
curl -X POST https://api.anysearch.com/v1/search \
  -H "Authorization: Bearer YOUR_ANYSEARCH_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "query": "Apple stock price",
  "tag": "finance.quote",
  "params": {
    "type": "stock"
  },
  "max_results": 5
}'
```

### Python

### Python 3 · requests

```python
# Install: pip install requests
import os
import requests

payload = {
  "query": "Apple stock price",
  "tag": "finance.quote",
  "params": {
    "type": "stock"
  },
  "max_results": 5
}
response = requests.post(
    "https://api.anysearch.com/v1/search",
    headers={
        "Authorization": "Bearer " + os.environ["ANYSEARCH_API_KEY"],
    },
    json=payload,
    timeout=30,
)
if not response.ok:
    # Do not log the response body: HTTP 402 may contain credentials.
    print({"status": response.status_code,
           "request_id": response.headers.get("X-Request-ID")})
    raise SystemExit(1)
result = response.json()
print(result["data"])
```

### JavaScript

### JavaScript · Node.js 18+

```javascript
// Node.js 18+; set ANYSEARCH_API_KEY before running.
const response = await fetch("https://api.anysearch.com/v1/search", {
  method: "POST",
  headers: {
    "Authorization": "Bearer " + process.env.ANYSEARCH_API_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "query": "Apple stock price",
    "tag": "finance.quote",
    "params": {
      "type": "stock"
    },
    "max_results": 5
  }),
  signal: AbortSignal.timeout(30_000)
});
if (!response.ok) {
  // Do not log the response body: HTTP 402 may contain credentials.
  throw new Error("HTTP " + response.status +
    "; request_id=" + response.headers.get("X-Request-ID"));
}
const result = await response.json();
console.log(result.data);
```

### Go

### Go · Standard library

```go
package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "os"
    "strings"
    "time"
)

func main() {
    if err := run(); err != nil {
        fmt.Fprintln(os.Stderr, err)
        os.Exit(1)
    }
}

func run() error {
    key := os.Getenv("ANYSEARCH_API_KEY")
    if key == "" {
        return fmt.Errorf("set ANYSEARCH_API_KEY before running")
    }
    payload := strings.NewReader(`{
  "query": "Apple stock price",
  "tag": "finance.quote",
  "params": {
    "type": "stock"
  },
  "max_results": 5
}`)
    request, err := http.NewRequest("POST", "https://api.anysearch.com/v1/search", payload)
    if err != nil {
        return err
    }
    request.Header.Set("Authorization", "Bearer " + key)
    request.Header.Set("Content-Type", "application/json")
    client := &http.Client{Timeout: 30 * time.Second}
    response, err := client.Do(request)
    if err != nil {
        return err
    }
    defer response.Body.Close()
    if response.StatusCode < 200 || response.StatusCode >= 300 {
        // HTTP 402 bodies may contain credentials; keep them out of logs.
        return fmt.Errorf("HTTP %d; request_id=%s",
            response.StatusCode, response.Header.Get("X-Request-ID"))
    }
    var result map[string]json.RawMessage
    if err := json.NewDecoder(response.Body).Decode(&result); err != nil {
        return err
    }
    fmt.Println(string(result["data"]))
    return nil
}
```

### Rust

### Rust · reqwest + serde_json

```rust
// Dependencies:
// cargo add reqwest --features blocking,json
// cargo add serde_json
use reqwest::blocking::Client;
use serde_json::{json, Value};
use std::{env, error::Error, time::Duration};

fn main() -> Result<(), Box<dyn Error>> {
    let key = env::var("ANYSEARCH_API_KEY")?;
    let client = Client::builder()
        .timeout(Duration::from_secs(30))
        .build()?;
    let response = client
        .post("https://api.anysearch.com/v1/search")
        .bearer_auth(key)
        .json(&json!({
          "query": "Apple stock price",
          "tag": "finance.quote",
          "params": {
            "type": "stock"
          },
          "max_results": 5
        }))
        .send()?;
    if !response.status().is_success() {
        // HTTP 402 bodies may contain credentials; keep them out of logs.
        let request_id = response.headers().get("X-Request-ID")
            .and_then(|value| value.to_str().ok()).unwrap_or("unknown");
        return Err(format!("HTTP {}; request_id={}",
            response.status(), request_id).into());
    }
    let result: Value = response.json()?;
    println!("{}", result["data"]);
    Ok(())
}
```

**Authentication and example environment**

Examples use `Authorization: Bearer YOUR_ANYSEARCH_API_KEY`. Python, JavaScript, Go and Rust read the `ANYSEARCH_API_KEY` environment variable. cURL uses Bash syntax; use Git Bash or WSL on Windows. Code timeouts are client-side only.

## Using tag and params

[Find a capability by tag, purpose or parameter name →](/docs/api-endpoints/v1-sub-domains)

| Item | How to fill it |
| --- | --- |
| `tag` | Use one complete tag, not only its domain. |
| `params` | Use a JSON object with parameter names defined by that tag. Omit it if there are no dedicated parameters. |
| Required and conditional parameters | Read both required flags and descriptions. required=false can still have a conditional requirement. |
| Types, allowed values and defaults | The definitions provide description, required and optional sort\_order. Do not infer separate schema fields. |
| Applicability | Respect upstream-specific, summary-only and future-filter limitations. |

A minimal general search can omit tag and only submit query.

## When to include tag and params

| Scenario | tag | params | Flow |
| --- | --- | --- | --- |
| General search | Omit | Omit | Submit query for intent-based routing. |
| Specific vertical capability | Use a discovered sub\_domain | Follow its definition | Discover → read parameters → search. |

## Request parameters

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| [query](/docs/api-endpoints/v1-search#param-query) | `string` | Required | `—` | A non-empty search query. |
| [max\_results](/docs/api-endpoints/v1-search#param-max_results) | `int` | Optional | `10` | Number of results, from 1 to 10. |
| [tag](/docs/api-endpoints/v1-search#param-tag) | `string` | Optional | `—` | One complete capability tag in `{domain}.{sub_domain}` form. Read it from the [capability directory](/docs/api-endpoints/v1-sub-domains) or discovery response. |
| [zone](/docs/api-endpoints/v1-search#param-zone) | `string` | Optional | `—` | Region: `cn` or `intl`. |
| [language](/docs/api-endpoints/v1-search#param-language) | `string` | Optional | `—` | Preferred language, such as `zh-CN` or `en`. |
| [params](/docs/api-endpoints/v1-search#param-params) | `object` | Optional | `—` | Capability-specific parameters. Follow the returned names, descriptions and required flags. |
| [format](/docs/api-endpoints/v1-search#param-format) | `string` | Optional | `—` | `json` or `markdown`. Markdown changes result content; the outer response is still JSON. |

— means no documented default or not applicable.

## Response fields

**Markdown content**

`format: "markdown"` changes `data.results[].content`; the outer response remains JSON.

| Field | Description |
| --- | --- |
| `data.results` | Array of search results. |
| `data.results[].title` | Always present; can be an empty string if the source has no title. |
| `data.results[].url` | Source URL. |
| `data.results[].snippet` | Summary; omitted if unavailable. |
| `data.results[].content` | Cleaned content; omitted if unavailable. |
| `data.metadata.total_results` | Actual number of returned results. |
| `data.metadata.search_time_ms` | Upstream search time in milliseconds. |

### Success response · Illustrative content and values

```json
{
  "code": 0,
  "message": "success",
  "request_id": "7d6f4e91-2a83-4c5b-9f10-6e8a3d27b541",
  "data": {
    "results": [
      {
        "title": "Example source",
        "url": "https://example.com/article",
        "snippet": "A short source summary.",
        "content": "Cleaned page content for the example."
      }
    ],
    "metadata": {
      "total_results": 1,
      "search_time_ms": 312
    }
  }
}
```

## Error codes

HTTP status codes and their meanings. `error_code` is optional; inspect the actual response.

| HTTP status | Meaning |
| --- | --- |
| 400 | Invalid request body or fields, missing query, or an upstream client error. |
| 401 | Invalid Authorization or API Key. |
| 402 | Quota exhausted. An anonymous request may receive generated credentials in message. |
| 403 | API Key expired, account disabled, or access forbidden. |
| 415 | Missing Content-Type or a value other than application/json. |
| 429 | API Key, user, or anonymous IP rate limit exceeded. |
| 502 | Search service unavailable or an invalid upstream response. |

### 400 · Missing query

```json
{
  "code": -1,
  "message": "Query is required.",
  "request_id": "7d6f4e91-2a83-4c5b-9f10-6e8a3d27b541"
}
```

## Anonymous quota response

When an anonymous request exceeds the daily free quota, the rejected request is not executed. After automatic account creation completes, the multi-line HTTP 402 message can contain a username, password and API Key. Account creation may briefly still be in progress. Once complete credentials are available, use the Bearer API Key to resubmit the original request.

### 402 · Redacted structural example

```json
{
  "code": -1,
  "message": "Your account and API key have been automatically generated. Use the API key below to continue.\nusername=<USERNAME>\npassword=<PASSWORD>\napi_key=<API_KEY>",
  "request_id": "7d6f4e91-2a83-4c5b-9f10-6e8a3d27b541"
}
```

**Responses may contain credentials**

HTTP 402 may contain a password and API Key. Do not pass the raw response to routine logs, analytics, tracing, tickets or model context. Retain only the HTTP status and `request_id` for diagnostics.

## FAQ

### Is tag required?

No. General search only needs query. Discover a vertical capability before specifying its tag and parameters.

### Can snippet or content be missing?

Yes. Both fields can be omitted if unavailable. Clients should handle missing values.

<!-- docs-navigation -->

## Documentation navigation

- [Source](https://anysearch.com/docs/api-endpoints/v1-search)
- Index: [Docs index](https://anysearch.com/docs.md)
- Parent / Previous: [API Endpoints](https://anysearch.com/docs.md/api-endpoints)
- Next: [/v1/sub-domains](https://anysearch.com/docs.md/api-endpoints/v1-sub-domains)
