Skip to main content

typesearch

The official Python client for the typesearch API: news search for AI agents, with a calibrated relevance score on every result.

pip install typesearch

Python 3.9+. Sync and async. Built on httpx and pydantic: every response is a typed model, and unknown fields from a newer API are kept instead of breaking your code.

Quickstart

Create a key in the dashboard and set it as TYPESEARCH_API_KEY:

from typesearch import Typesearch

ts = Typesearch()  # reads TYPESEARCH_API_KEY

res = ts.search("inflation", mode="fast", max_results=5)

for r in res.results:
    print(f"{r.score:.2f}", r.title, f"({r.source})")

Every result carries a score: the calibrated probability that it is about your query. Threshold on it directly — 0.9 means relevant, and anything between 0.35 and 0.65 means the model is undecided.

Create a client

Argument Default
api_key TYPESEARCH_API_KEY Your key.
base_url https://api.typesearch.ai Or TYPESEARCH_BASE_URL.
timeout 70.0 Seconds before a request is aborted. A deep search can take about a minute.
max_retries 2 Retries on connection errors, 429 rate_limited and 5xx.
default_headers — Headers sent with every request.
http_client — Your own httpx.Client (or httpx.AsyncClient for async), for proxies or tests.

Use it as a context manager to close connections when you are done: with Typesearch() as ts: …. Keep keys on the server: never ship one to a browser or a mobile app.

What you can do

Method Endpoint
search(query, **options) POST /v1/search Search the index: one query, or up to five judged together.
search_stream(query, **options) POST /v1/search The same, as events: steps, partial results, the final result.
similar(url, **options) POST /v1/similar Articles about the same story as a URL.
contents(urls, query=…) POST /v1/contents Metadata and a short verbatim excerpt of up to 10 URLs.
site_search(site, query, **options) POST /v1/search/site Search a live site. Returns a job.
site_search_and_wait(site, query, **options) POST /v1/search/site The same, waiting for the result.
site_search_stream(site, query, **options) POST /v1/search/site The same, as events.
jobs.get(id) · jobs.wait(id) GET /v1/jobs/{id} A job's status and result.
usage() GET /v1/usage Usage, limits and credit of your key.

Keyword arguments have the same names as the HTTP API and are typed (SearchOptions, SimilarOptions… in typesearch.types), so your editor and type checker know every one of them. Responses are pydantic models generated from the API's OpenAPI document: r.title, res.usage.cost_usd, res.model_dump().

res = ts.search(
    "el dólar",
    mode="normal",  # "ultra" | "fast" | "normal" | "deep"
    max_results=10,
    include_domains=["reddiaria.example", "diarioejemplo.example"],
    published_after="2026-09-20",  # or a datetime.date / an aware datetime.datetime
    highlights=True,
)

# Several queries at once, judged together
res = ts.search(["el dólar", "el FMI"], mode="fast")
for group in res.groups or []:
    print(group.query, group.total)

days=None searches the whole index; leaving days out keeps the default of 7. Add questions for typed answers on every result, and tone, dedupe or essential for enrichments — see the guides.

mode sets how much is read, and the price: ultra (headlines only) is the cheapest, then fast, normal and deep — see modes and pricing.

Filter by country and language

res = ts.search(
    "inflation",
    countries=["AR", "UY"],  # ISO 3166-1 alpha-2
    languages=["es"],  # ISO 639-1; a tag such as pt-BR counts as pt
)

for r in res.results:
    print(r.country, r.language, r.title)

Every result carries the country and language of its source (None when unknown), and similar() takes the same two filters. The index covers news from 130+ countries in 30+ languages. Missing an outlet? Suggest it from the dashboard (Suggest a source) or write to support@typesearch.ai.

Stream

with ts.search_stream("el dólar", mode="deep") as stream:
    for event in stream:
        if event.type == "step":
            print("·", event.step.text)
        elif event.type in ("partial", "result"):
            render(event.response.results)

# Or only the final result
final = ts.search_stream("el dólar").final_response()

The request starts when you start iterating. An error event is raised as an APIError.

Similar and contents

similar = ts.similar("https://diarioejemplo.example/economia/…", exclude_domains=["diarioejemplo.example"])

pages = ts.contents(["https://reddiaria.example/economia/…"], query="el dólar")
for page in pages.results:
    if page.status == "ok":
        print(page.relevance, page.title, page.highlights)
    else:
        print(page.url, page.error.code)

contents() never returns the full text: at most one excerpt of up to 25 words per article.

# Create the job and wait for it
res = ts.site_search_and_wait("diarioejemplo.example", "el dólar", mode="normal")

# Or handle the job yourself
job = ts.site_search("diarioejemplo.example", "el dólar")
done = ts.jobs.wait(job.id, poll_interval=2, timeout=120)

jobs.wait() returns the job's result and raises JobFailedError if the job fails.

Usage

usage = ts.usage()
print(usage.today.remaining_tokens, usage.limits.requests_per_minute)

Async

AsyncTypesearch has the same methods, awaitable:

import asyncio
from typesearch import AsyncTypesearch


async def main():
    async with AsyncTypesearch() as ts:
        res = await ts.search("el dólar", mode="fast")
        async for event in ts.search_stream("el FMI"):
            ...


asyncio.run(main())

Errors

Every error subclasses TypesearchError. API errors are APIError subclasses with status, code (stable, for programs), request_id and, for invalid requests, errors per field.

Class When
BadRequestError 400
AuthenticationError 401
BudgetError 402 — budget_too_small, insufficient_credits or spend_limit_reached
PermissionDeniedError 403
NotFoundError 404
RateLimitError 429 — with retry_after
InternalServerError 5xx
APIConnectionError · APITimeoutError No response, or too slow
JobFailedError A live site search job failed
from typesearch import APIError, BadRequestError, RateLimitError

try:
    ts.search("x")
except BadRequestError as e:
    print(e.code, e.errors)
except RateLimitError as e:
    print(e.code, e.retry_after)
except APIError as e:
    print(e.status, e.code, e.request_id)

Retries and timeouts

Connection errors, timeouts, 429 rate_limited and 5xx are retried twice with exponential backoff and jitter, honouring Retry-After; quota_exceeded never is. Set max_retries=0 on the client to handle them yourself, or override it per call, with the timeout and extra headers:

res = ts.search("el dólar", mode="deep", timeout=90, max_retries=0, extra_headers={"X-Trace-Id": "abc"})

Examples

examples/ has three short scripts: search, contents and streaming.

Development

uv sync
uv run python scripts/generate_models.py          # models from openapi/openapi.json (--fetch pulls the live one)
uv run ruff check . && uv run ruff format --check . && uv run mypy
uv run pytest --cov                                # against a fake API that validates every request against the OpenAPI
TYPESEARCH_LIVE=1 uv run pytest tests/test_live.py # against the real API: needs TYPESEARCH_API_KEY (spends less than a cent)

License

MIT

Metadata

Release files for typesearch 0.1.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 typesearch 0.1.0
File Size Uploaded
typesearch-0.1.0.tar.gz 62.7 kB Details

Built distribution (wheel)

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

Total release size: 93.1 kB

Release files / typesearch-0.1.0.tar.gz

Download URL typesearch-0.1.0.tar.gz
Size 62.7 kB
Tags Source
SHA-256 checksum
How to use checksums
49a9f8adccccdc9da5fc795b71fac904f73a0a1a2488b16e89707dc5a2bc002e
BLAKE2b-256 checksum
How to use checksums
b6db178305260841c7f2d15c9b041080f9d2a869829b4a3f581c93065b94571e
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 27, 2026.

Transparency log

Release files / typesearch-0.1.0-py3-none-any.whl

Download URL typesearch-0.1.0-py3-none-any.whl
Size 30.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e931aeda4362da662e5b94670c0de45bea99097a1e3afd74490e8af8a9e12d17
BLAKE2b-256 checksum
How to use checksums
84b52e0d45dddeb22958793d7b0e728710a827d4e6dc1b6b8652fce03b4b16f5
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 27, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

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