> SpecStream is the live web data engine for teams and agents. This is the Markdown copy of https://specstream.ai/docs/integrations/mistral-api. Every page, with what SpecStream does and costs: https://specstream.ai/llms.txt

# Mistral API

Give a Mistral model web search as a function tool. When the model asks, your code calls the SpecStream Search API and returns the answer, the page it was read from and the ranked results. It works on Chat Completions, where Mistral's own web\_search tool does not.

[SpecStream for Mistral APIAgent frameworks & builders](https://specstream.ai/integrations/mistral-api.md)

## What you need

-   A Mistral API key, and Python with the Mistral SDK and httpx (`pip install mistralai httpx`).
-   A SpecStream API key. New accounts start with $10 of credit, no card. [Create an account](https://specstream.ai/signup?utm_source=mistral-api).

1.  1

    ## 1. Create a SpecStream API key

    In SpecStream, open [Agents & API](https://specstream.ai/workspace/agents?tab=keys&utm_source=mistral-api), choose **API keys**, then **Create API key**. Give it execute permission and a spending limit above zero, so it can search. Set it as `SPECSTREAM_API_KEY`, and your Mistral key as `MISTRAL_API_KEY`, on the machine that runs your code.

2.  2

    ## 2. Declare the search function

    Mistral takes your functions in `tools`, each with a name, a description and a JSON schema for its parameters. Declare one that takes the question. Add each block of this guide to one file, `mistral_search.py`, in order:

    mistral\_search.py

    ```python
    tools = [
        {
            "type": "function",
            "function": {
                "name": "web_search",
                "description": "Search the live web. Use it for news, prices, people in roles and any fact that may have changed since training.",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "q": {"type": "string", "description": "The question, in everyday words"}
                    },
                    "required": ["q"],
                },
            },
        }
    ]
    ```

3.  3

    ## 3. Call the Search API

    The function calls `GET /v1/web-search` with the question in `q`. `num` sets how many results come back. Return JSON text, which Mistral takes as the tool's content:

    mistral\_search.py

    ```python
    import json
    import os
    
    import httpx
    
    specstream = httpx.Client(
        base_url="https://api.specstream.ai",
        headers={"Authorization": f"Bearer {os.environ['SPECSTREAM_API_KEY']}"},
        timeout=60,
    )
    
    def web_search(q: str) -> str:
        r = specstream.get("/v1/web-search", params={"q": q, "num": 5})
        if r.status_code != 200:
            return json.dumps({"error": r.status_code, "message": r.text[:500]})
        data = r.json()["data"]
        answer = data.get("answer") or {}
        return json.dumps({
            "answer": answer.get("value"),
            "answer_page": answer.get("page"),
            "sources": [
                {
                    "title": s.get("title"),
                    "url": s["url"],
                    "snippet": s.get("snippet"),
                    "published": s.get("published"),
                }
                for s in data["sources"]
            ],
        })
    
    functions = {"web_search": web_search}
    ```

4.  4

    ## 4. Answer each tool call

    Mistral does not run your function: the model returns `tool_calls`, your code runs each one and sends the result back as a `tool` message with the call's `tool_call_id`. The model can follow one call with another, so loop until it answers:

    mistral\_search.py

    ```python
    from mistralai.client import Mistral
    
    client = Mistral(api_key=os.environ["MISTRAL_API_KEY"])
    model = "mistral-large-latest"
    
    messages = [
        {"role": "system", "content": "Use web_search for any fact that may have changed since your training. Cite the URLs it returns."},
        {"role": "user", "content": "What did the European Central Bank decide at its last meeting?"},
    ]
    
    response = client.chat.complete(model=model, messages=messages, tools=tools)
    messages.append(response.choices[0].message)
    
    while response.choices[0].message.tool_calls:
        for tool_call in response.choices[0].message.tool_calls:
            args = json.loads(tool_call.function.arguments)
            messages.append({
                "role": "tool",
                "name": tool_call.function.name,
                "content": functions[tool_call.function.name](**args),
                "tool_call_id": tool_call.id,
            })
        response = client.chat.complete(model=model, messages=messages, tools=tools)
        messages.append(response.choices[0].message)
    
    print(response.choices[0].message.content)
    ```

5.  5

    ## 5. Run it

    Run `python mistral_search.py`. The answer names the pages it came from. Print the `content` of each `tool` message to see every result the model read.

## Beside Mistral's built in web search

Mistral's own `web_search` and `web_search_premium` tools run only in the Conversations API and the Agents API, not in Chat Completions, and Mistral's pricing page says tool APIs are priced per call without showing the amount. A SpecStream function differs in three ways:

-   It runs on any endpoint that takes function tools: Chat Completions, Conversations and Agents, and on every Mistral model that calls functions.
-   Your code holds the results. Each call returns the answer, the page it was read from and the ranked results with their URLs and publication dates, so you can log them, show them or drop a site you do not trust.
-   The price is on this page: $5 per 1,000 searches of up to 10 results, from your balance. The Search API is the most accurate web search API on SimpleQA Verified and WideSearch ([scores and method](https://specstream.ai/benchmarks.md)).

## In the Agents and Conversations API

An agent takes the same `tools` list. When the last output is a `function.call`, run it and append a `FunctionResultEntry` to the conversation:

## Read pages too

Add a second function that reads the pages a search found, through the Extract API: `POST /v1/extract` with up to 20 URLs returns each page's main text, at $0.80 per 1,000 pages. A page that gives no text is not charged.

## Keep queries in the EU

A SpecStream key can send its searches only from SpecStream's server in Madrid, and can be set to zero retention, so no request text or answer is kept after the reply. Set both on the key in your workspace, or with `PATCH /v1/account/keys/{id}` and `{"zero_retention": true, "eu_egress_only": true}`.

## Cost

Mistral bills the model's tokens. SpecStream bills each search at $5 per 1,000 searches of up to 10 results, and each page read at $0.80 per 1,000 pages, from your balance, with no quote and no approval. A search that returns no results costs nothing. [Balance, quotes, and billing](https://specstream.ai/docs/billing.md) has the details.

## More

[SpecStream for Mistral API](https://specstream.ai/integrations/mistral-api.md) covers what it does in Mistral API on one page. Every other tool has its guide in [Connect your tools](https://specstream.ai/docs/integrations.md). You see the most a request can cost before it starts, and the matches are paid from your balance. [Billing](https://specstream.ai/docs/billing.md) has the details. For help, email [support@specstream.ai](mailto:support@specstream.ai).
