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

# DeepSeek Web Search and Fetch API

> DeepSeek's native Search / Fetch tool APIs: search the web by query, fetch any URL as Markdown, for agents and RAG. APIYI serves /v1/tools/search and /v1/tools/fetch, billed per successful request; large-deposit customers pay the same as the official price.

DeepSeek offers two standalone tool APIs for agents and RAG pipelines that need live web data:

* **Search**: send a query, get structured web search results (title, link, summaries, optional page body)
* **Fetch**: send a URL, get the page body already converted to Markdown

They are **not chat models**. They consume no tokens and are billed **per successful request**. Your code decides when and what to search, then feeds the results to any model.

> [!NOTE]
>
> **Model names**: `deepseek-search`, `deepseek-fetch`. **Endpoints**: `POST /v1/tools/search`, `POST /v1/tools/fetch`. Available in the `default` / `svip` groups.
> All data on this page comes from APIYI testing on October 21, 2026 (UTC+8).

> [!WARNING]
>
> **Keys in the ClaudeCode group cannot call these two APIs.** They return 503 `no available channels for model deepseek-search`. Create a separate key in the `default` or `svip` group.

## What it is and when to use it

| | Search | Fetch |
| - | - | - |
| Input | A query (supports operators such as `site:` and `lang:`) | One HTTP / HTTPS URL |
| Output | 1–50 search results, page body optional | Page title + Markdown body |
| Typical use | Agent web lookup, live context for RAG, news and topic monitoring | Read one page from the results, crawl a docs site, feed a page to a model for summarizing |
| Measured latency | 1.6–3.0 s | 1.6–5 s (depends on the target site) |

The usual pattern is **Search first, then Fetch a few results**: each result's `summary` is enough for a model to judge relevance, so only fetch the pages you need in full.

### How this relates to built-in search in Claude Code

This page is a **plain API**: your code calls `/v1/tools/search` and `/v1/tools/fetch` directly.

In clients such as Claude Code and Codex, web searches started by the model go through a server-side tool (`web_search`) inside the chat API, which is a different thing. APIYI will support built-in search for DeepSeek models in those clients in a later release and will announce it separately.

## Pricing

| API | Official price | APIYI list price | Large-deposit customers pay (÷1.2) | General customers pay (÷1.1) |
| - | - | - | - | - |
| Search (`deepseek-search`) | \$0.75 / 1,000 requests | \$0.90 / 1,000 requests | **\$0.75 / 1,000 requests** | about \$0.82 / 1,000 requests |
| Fetch (`deepseek-fetch`) | \$0.75 / 1,000 requests | \$0.90 / 1,000 requests | **\$0.75 / 1,000 requests** | about \$0.82 / 1,000 requests |

> [!NOTE]
>
> **Pricing in one sentence: set against the "large-deposit customer with 20% bonus" baseline, so it lands on par with the official price once the bonus applies.** The list price is \$0.0009 per request; with the 20% [top-up bonus](/en/faq/recharge-promotions) the effective cost is \$0.00075 per request, **the same as DeepSeek's official price**. General customers with the 10% bonus pay about 1.09× the official price. Prices **include tax** and can be invoiced. DeepSeek offers no discount on these APIs and APIYI doesn't price them for profit: they are offered to **secure supply and serve customers**. One APIYI key covers search, fetch and every major model, with no separate DeepSeek account or top-up needed.

> [!NOTE]
>
> Model prices are aligned with official pricing and may change with it; the table above is for reference only, and the **Model Pricing** tab in the top navigation is authoritative: [Model Pricing](/en/models/index).

**Billing rules** (same as the official API):

* **Only successful requests are billed**: HTTP 200 with a result
* Parameter errors (400) and fetch failures (404) are **not billed**
* The price does **not** depend on `count`, `need_content` or response length: 1 result or 50 results with page bodies is still one request
* Each call is its own row in the console logs, under the model name `deepseek-search` or `deepseek-fetch`, so you can reconcile by model

## Quick start

```bash Search theme={null}
curl https://api.apiyi.com/v1/tools/search \
  -H "Authorization: Bearer $APIYI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "DeepSeek V4 release",
    "count": 5
  }'
```

```bash Fetch theme={null}
curl https://api.apiyi.com/v1/tools/fetch \
  -H "Authorization: Bearer $APIYI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://docs.apiyi.com/en"
  }'
```

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

BASE = "https://api.apiyi.com/v1/tools"
HEADERS = {"Authorization": f"Bearer {os.environ['APIYI_API_KEY']}"}

# 1. Search
r = requests.post(f"{BASE}/search", headers=HEADERS, timeout=60,
                  json={"query": "DeepSeek V4 release", "count": 5})
r.raise_for_status()
results = r.json()["results"]
for item in results:
    print(item["rerank_score"], item["title"], item["url"])

# 2. Fetch the top result
r = requests.post(f"{BASE}/fetch", headers=HEADERS, timeout=60,
                  json={"url": results[0]["url"]})
if r.status_code == 200:
    page = r.json()
    print(page["title"])
    print(page["content"][:500])
else:
    print("Fetch failed, not billed:", r.status_code, r.json()["error"]["message"])
```

The request body does **not** need a `model` field; if you send one it is ignored.

## Request parameters

### Search: `POST /v1/tools/search`

| Parameter | Type | Required | Description |
| - | - | - | - |
| `query` | string | ✓ | Search query, 1–128 characters, not all whitespace. Supports the operators below |
| `count` | int | | Number of results, 1–50, default 10. **Does not affect the price** |
| `need_content` | bool | | Return the page body, default `false` (then `content` is always an empty string). Roughly doubles the response size |
| `ori_question` | string | | The user's original question behind this search, 1–128 characters, used to understand intent |
| `localization` | string | | **The user's IP address**, used to prioritize localized results. **Not a locale code**: `ja-JP` returns 400 |

**Search operators** (inside `query`):

| Operator | Effect | Example |
| - | - | - |
| `site:` | Only this site; join several with `OR` | `site:arxiv.org OR site:github.com RAG` |
| `-site:` | Exclude a site | `LLM -site:reddit.com` |
| `"..."` / `-"..."` | Require / exclude an exact phrase | `"thinking mode" -"deprecated"` |
| `-keyword` | Exclude pages containing the keyword | `apple -iphone` |
| `lang:` | Limit languages, comma-separated | `lang:zh,en DeepSeek` |
| `after:` / `before:` | Filter by publication date (year or full date) | `after:2026-10-01 AI news` |

### Fetch: `POST /v1/tools/fetch`

| Parameter | Type | Required | Description |
| - | - | - | - |
| `url` | string | ✓ | HTTP / HTTPS URL, up to 8192 characters, no username or password |

## Response fields

**Search** returns `{"results": [...]}`; each result has:

| Field | Description |
| - | - |
| `title` / `url` | Title and link |
| `snippet` | Short summary, about 100–200 characters, for showing to people |
| `summary` | Long summary, about 600–800 characters, **for feeding to models** |
| `content` | Page body; empty string when `need_content` is `false` |
| `rerank_score` | Relevance score 0–3; **1.5 or higher is high quality** |
| `authority` | Site authority 0–4, `-1` = unknown; **3 or higher is highly authoritative** |
| `date` | Publication time (UTC, RFC 3339), may be `null` |
| `site_name` / `site_icon` | Site name and icon, may be `null` |

**Fetch** returns `{"title": "...", "content": "..."}`, where `content` is the Markdown body.

## Test results

Tested on 2026-10-21 (UTC+8):

| Case | Result | Billed |
| - | - | - |
| Search, `count=5` | ✅ 5 results, 1.8 s | 1 request |
| Search, `count=5` + `need_content` | ✅ all 5 with body, 32 KB response | 1 request |
| Search, `count=50` | ✅ 50 results, 180 KB response, 3.0 s | 1 request |
| Search, `site:` operator | ✅ every result from the given site | 1 request |
| Search, `localization` set to an IP | ✅ | 1 request |
| Search, `count=51` / empty `query` | 400 with a specific reason | Not billed |
| Fetch, normal page | ✅ 6,400-character Markdown, 1.6 s | 1 request |
| Fetch, 404 page / nonexistent domain / private address | 404 `failed to fetch URL` | Not billed |
| Fetch, malformed URL | 400 | Not billed |
| 20 concurrent searches | ✅ all 200, done within 2 s | 1 request each |

## Things you need to know

> **"No results, no charge" rarely applies**
>
> A search engine almost always returns something: in testing, a string of random characters still returned 3 results and was billed.
> Likewise, some sites answer a missing page with their home page or a notice page instead of a 404 (a "soft 404"); Fetch treats that as a successful fetch and bills it.
> Validate queries and URLs in your own code before calling.

> **Every fetch failure is a 404; branch on the HTTP status code**
>
> When Fetch cannot get usable content it always returns 404 `failed to fetch URL`, whether the target page is 404, the domain does not exist, the address is private, or the site refused access.
> The `type` field in the error body is always `shell_api_error`, so use the **HTTP status code plus `message`** to tell errors apart:
> on 400 fix the parameters; on 404 try another URL; on 429 / 5xx wait and retry.

> **Results are raw third-party web content; treat them as untrusted input**
>
> Search and Fetch return raw content from the internet, which may include ads, wrong information, or even prompt injection aimed at AI.
> When you pass results to a model, tell it explicitly that this is external web content, not instructions. When you show results in a web page or app, escape the HTML.

> **Rate limits**
>
> The upstream limits are 100 QPS for Search and 25 QPS for Fetch, and Fetch has a separate limit per target domain.
> Going over returns 429; wait briefly and retry. When fetching many pages from the same site, throttle on the client side.

## FAQ

> **How is this different from OpenAI / Claude / Gemini web search?**
>
> Those are **built-in tools of chat models**: the model decides whether and what to search, and searches are billed as tool calls on top (OpenAI `web_search` is \$10 per 1,000 calls).
> This page is a **standalone search API**: your code decides when and what to search, the unit price is a small fraction of that, and the results can go to any model.
> For built-in tools, see [OpenAI Web Search](/en/api-capabilities/openai/web-search), [Claude Web Search](/en/api-capabilities/claude-web-search) and [Gemini Web Search](/en/api-capabilities/gemini/web-search).

> **Can I use it in Claude Code?**
>
> Not directly yet. Web searches the model starts inside Claude Code go through the chat API's server-side tool, not through this API,
> and keys in the ClaudeCode group cannot call this API either. APIYI will support built-in search for DeepSeek models in those clients in a later release.

> **How fresh are the results?**
>
> Results carry a `date` field, and you can use the `after:` operator to get only recent content. In testing, news published the same day showed up.

## Related docs

> **[Search Playground](/en/api-capabilities/deepseek-search-fetch/search-api)**
>
> Parameter reference, error codes, and a live request panel

> **[Fetch Playground](/en/api-capabilities/deepseek-search-fetch/fetch-api)**
>
> Fetch any web page as Markdown

> **[DeepSeek V4 Flash](/en/api-capabilities/deepseek-v4-flash/overview)**
>
> A chat model to pair with it

> **[Top-up bonuses](/en/faq/recharge-promotions)**
>
> The more you top up, the bigger the bonus; large-deposit customers pay the official price


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.