Skip to main content

PyPI version

Seltz Python SDK

Official Python SDK for Seltz, the Web search engine for AI agents.

💾 Installation

pip install seltz

Requires Python 3.9 or higher.

⚡️ Quick Start

from seltz import Seltz

client = Seltz(api_key="your-api-key")

# Search the Web
response = client.search("best ai search engines", max_results=10)

# Access results
for document in response.documents:
    print(f"URL: {document.url}")
    print(f"Content: {document.content}")

Output:

URL: https://www.best-ai-search-engines.com
Content: Generative AI can make finding information faster and more intuitive.
If you’re tired of traditional search, explore some of the best AI-powered
search engines we've tested...

Search tiers

tier selects which search tier serves the request, "base" or "pro". It never changes which corpus is searched — that is scope — and the two are orthogonal: any scope can be requested in either tier.

Omitting tier defaults to "pro", the higher-precision tier, which is what a caller who expressed no preference should get. "base" is therefore opt-out rather than opt-in — name it explicitly to skip the reranking:

response = client.search(
    "best ai search engines",
    tier="base",
)

The SDK sends no tier of its own when you omit the argument, so the default follows the service rather than being pinned here.

tier is typed as a plain str and the name is forwarded to the API as given. The service owns the set of tiers: it matches the name case-insensitively and rejects one it does not recognize, in a 400 that names the tiers it accepts. The SDK carries no list of tier names, so tiers can be added or renamed without an SDK release — check the API reference for the current names.

Result fields

fields selects which members of each result document come back. Content is the default; url and published_date are always emitted:

from seltz import Seltz

client = Seltz(api_key="your-api-key")

response = client.search(
    "best ai search engines",
    fields={"content": True, "snippets": True},
)

for document in response.documents:
    print(f"URL: {document.url}")
    for snippet in document.snippets:
        print(f"  {snippet.text}")

snippets are the passages of a document that best match your query, in descending order of score — useful when you want the relevant part of a long page rather than the whole thing, and cheaper to feed to a model.

A selection you pass is taken literally. {"snippets": True} asks for snippets and nothing else, so the documents come back with no content. Name every member you want:

# passages only — document.content is empty
response = client.search("ai news", fields={"snippets": True})

# both
response = client.search("ai news", fields={"content": True, "snippets": True})

Snippets are only available on scopes whose index produces them; elsewhere the list comes back empty rather than erroring.

A member also takes a ceiling instead of True. Pass an object in place of the boolean to bound how much of that member comes back:

# content, capped at 500 characters per result
response = client.search("ai news", fields={"content": {"max_characters_per_result": 500}})

# a ceiling on each member
response = client.search(
    "ai news",
    fields={
        "content": {"max_characters_per_result": 500},
        "snippets": {"max_snippets_per_result": 5, "max_tokens_per_result": 400},
    },
)

An object selects the member as well as bounding it, so {"content": {"max_characters_per_result": 500}} returns content and no snippets. max_characters_per_result counts Unicode code points and accepts 100 to 1000000; a value outside that range is a 400 naming the field and the bound.

Answer

Get a natural-language answer grounded in Web search results, with citations:

from seltz import Seltz

client = Seltz(api_key="your-api-key")

response = client.answer("Who is Apple's next CEO?")

print(response.answer)
for citation in response.citations:
    print(f"Source: {citation.url}")

Pass model to pick an answer tier. It defaults to seltz-base; seltz-pro runs agentic RAG over a single grounding search:

response = client.answer("Who is Apple's next CEO?", model="seltz-pro")

Pass response_format (an OpenAI-style object) to get structured output. response.answer then carries a JSON string matching your schema instead of Markdown; response.citations are still returned:

response = client.answer(
    "Who is Apple's next CEO?",
    response_format={
        "type": "json_schema",
        "json_schema": {
            "name": "news_summary",
            "schema": {
                "type": "object",
                "properties": {"summary": {"type": "string"}},
                "required": ["summary"],
                "additionalProperties": False,
            },
        },
    },
)

import json
print(json.loads(response.answer)["summary"])

Pass system_prompt to steer how the answer is presented — tone, voice, format:

response = client.answer(
    "Who is Apple's next CEO?",
    system_prompt="Answer in British English. Open with a one-line summary, then the detail.",
)

Answer (streaming)

Stream an answer as it is generated, instead of waiting for the full response. answer_stream yields events as they arrive: a citations event first, then text_delta chunks, then a terminal finish_reason. Inspect each event with event.WhichOneof("event"):

from seltz import Seltz

client = Seltz(api_key="your-api-key")

for event in client.answer_stream("Who is Apple's next CEO?"):
    kind = event.WhichOneof("event")
    if kind == "citations":
        for citation in event.citations.citations:
            print(f"Source: {citation.url}")
    elif kind == "text_delta":
        print(event.text_delta, end="", flush=True)
    elif kind == "finish_reason":
        print()

Streaming is also available asynchronously via AsyncSeltz — async for over the events:

import asyncio

from seltz import AsyncSeltz


async def main():
    async with AsyncSeltz(api_key="your-api-key") as client:
        async for event in client.answer_stream("Who is Apple's next CEO?"):
            kind = event.WhichOneof("event")
            if kind == "citations":
                for citation in event.citations.citations:
                    print(f"Source: {citation.url}")
            elif kind == "text_delta":
                print(event.text_delta, end="", flush=True)
            elif kind == "finish_reason":
                print()


asyncio.run(main())

Agent runs

An agent run researches a question with Seltz search and returns a grounded, cited answer. Runs are asynchronous — create one and poll it, or let the SDK wait for you:

from seltz import Seltz

client = Seltz(api_key="your-api-key")

run = client.agent.create_and_wait(
    "Who are the current CEOs of OpenAI, Anthropic and Mistral AI?"
)
print(run.output.text)  # cited markdown; [n] markers cite output.sources
for source in run.output.sources:
    print(f"  [{source.id}] {source.url}")

wait and create_and_wait return once the run reaches a terminal status (AGENT_RUN_STATUS_COMPLETED, _FAILED, or _CANCELLED — compare with the AgentRunStatus enum); run.stop_reason says why it ended.

effort picks how much research a run may do, and its price — one of the deployment's level names (low, medium, high, max). Omit it and the run uses the default level; run.request.effort echoes the level it ran at:

run = client.agent.create_and_wait(
    "Who are the current CEOs of OpenAI, Anthropic and Mistral AI?",
    effort="high",
)

Pass an OpenAI-style response_format object as output_schema to also get structured output (run.output.structured, a JSON string shaped by your schema, with per-field citations in run.output.grounding):

run = client.agent.create_and_wait(
    "Who are the current CEOs of OpenAI, Anthropic and Mistral AI?",
    output_schema={
        "type": "json_schema",
        "json_schema": {
            "name": "companies",
            "schema": {
                "type": "object",
                "properties": {
                    "companies": {
                        "type": "array",
                        "items": {
                            "type": "object",
                            "properties": {
                                "name": {"type": "string"},
                                "ceo": {"type": "string"},
                            },
                        },
                    }
                },
            },
        },
    },
)
print(run.output.structured)

The lower-level pieces are there when you need them: client.agent.create returns the pending run at once, client.agent.get(run_id) polls it, client.agent.wait(run_id) polls to completion (an optional timeout bounds the wait client-side; the run keeps executing), client.agent.cancel(run_id) stops a run, and client.agent.list() pages through past runs newest-first via its next cursor.

Fetch

Turn URLs into LLM-ready Markdown. Up to 20 per call, fetched concurrently:

from seltz import FetchStatus, Seltz

client = Seltz(api_key="your-api-key")

response = client.fetch(["https://example.com/"])

for result in response.results:
    if result.status == FetchStatus.FETCH_STATUS_OK:
        print(result.markdown)
    else:
        print(f"{result.requested_url}: {result.error.code}")

A page that cannot be fetched is not a call failure. Every requested URL gets a result, in the order requested, and a failed one carries status = FetchStatus.FETCH_STATUS_ERROR and an error.code.

Async

The same API is available asynchronously via AsyncSeltz — await each call:

import asyncio

from seltz import AsyncSeltz


async def main():
    client = AsyncSeltz(api_key="your-api-key")

    response = await client.search("best ai search engines", max_results=10)

    for document in response.documents:
        print(f"URL: {document.url}")
        print(f"Content: {document.content}")


asyncio.run(main())

To close the connection deterministically rather than leaving it to garbage collection, use AsyncSeltz as an async context manager (async with) or call await client.close() when done.

📚 Documentation

Browse the documentation for more details.

Metadata

Release files for seltz 1.15.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for seltz 1.15.0
File Size Uploaded
seltz-1.15.0.tar.gz 68.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for seltz 1.15.0
File Interpreter ABI Platform
seltz-1.15.0-py3-none-any.whl Python 3 none any Details

Total release size: 126.7 kB

Release files / seltz-1.15.0.tar.gz

Download URL seltz-1.15.0.tar.gz
Size 68.6 kB
Tags Source
SHA-256 checksum
How to use checksums
f956dccb83d8b552f5605c7e6ab49c0a1a90f26a0c0cf3762170e2b29d91ade4
BLAKE2b-256 checksum
How to use checksums
054620441dcfc553593bdba262f0a86d15b58dddeb5f5ea9a71d324f9471ee7e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release files / seltz-1.15.0-py3-none-any.whl

Download URL seltz-1.15.0-py3-none-any.whl
Size 58.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
31d3c1b46fbaa069f1b638f355de509286315b11e31ccdbdbf12f5a53883b5be
BLAKE2b-256 checksum
How to use checksums
657ca7c6eda5d4387cb3192dc3dd57596b8cdaa693e542a3a512c52c16191e63
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 11, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.15.0 This release

2 release files

1.14.0

2 release files

1.9.0

2 release files

1.8.0

2 release files

1.7.0

2 release files

1.6.0

2 release files

1.5.0

2 release files

1.4.0

2 release files

1.3.0

2 release files

1.2.0

2 release files

1.1.0

2 release files

1.0.0

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

0.0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page