krenzo
Search and extract API for LLM agents. One endpoint for live web search, one for turning any URL into clean markdown — returned as token-efficient context rather than raw HTML.
No runtime dependencies.
pip install krenzo
Quickstart
Get a key at krenzo.in/dashboard/keys, then:
export KRENZO_API_KEY=krz_live_...
from krenzo import Krenzo
client = Krenzo()
for hit in client.search("nvidia q3 earnings", max_results=5):
print(hit.source, "—", hit.title)
Search
results = client.search(
"western digital analyst price target",
depth="deep", # also returns page contents for the top results
max_results=10,
include_domains=["stockanalysis.com"],
freshness="week",
)
for r in results:
print(r.title, r.url)
if r.content: # populated when depth="deep"
print(r.content[:500])
depth="deep" fetches and extracts the top results in the same call, which
saves a round trip per result when you were going to read them anyway.
Extract
pages = client.extract([
"https://example.com/a",
"https://example.com/b",
])
for p in pages:
if p.ok:
print(p.title, p.word_count)
print(p.content)
else:
print("failed:", p.url, p.error_type, p.error_message)
Each URL carries its own ok/error, so one dead link does not discard the
rest of the batch. Pass format="text" for plain text instead of markdown, and
render=True for pages that block plain clients or build their content in the
browser.
When an empty page is not an empty page
A site that blocks you and a site with nothing on it look identical downstream
— and only one of them is a bug in your parser. extract_one makes the
difference explicit:
from krenzo import Krenzo, BlockedError
client = Krenzo()
try:
text = client.extract_one("https://www.tipranks.com/stocks/wdc/forecast")
except BlockedError as e:
print("needs a browser or was refused:", e)
Batch extract() reports the same thing without raising: check
p.needs_rendering and p.error_type.
Answer
A grounded answer in one call, with every quote checked against the page it came from.
res = client.answer("What did the RBI decide on the repo rate?", max_sources=4)
print(res.answer)
for c in res.citations:
print(f" — {c.quote}\n {c.url}")
The model proposes quotes; the service verifies each one against the fetched source and drops anything it cannot find. A fabricated citation therefore cannot reach you. Two fields are worth reading every time:
res.unverified— quotes that were dropped. Empty means every claim was grounded; non-empty means the answer drifted from its sources.res.skipped— pages found but not readable, with a reason. An answer built on one of four sources is weaker than one built on four.
If the sources do not contain the answer, it says so and returns no citations
rather than guessing. Pass render=True to retry unreadable sources through a
browser; it is billed at the rendered rate, so it is off by default.
Errors
| Exception | When |
|---|---|
AuthenticationError |
missing, malformed, or revoked key |
InsufficientCredits |
balance cannot cover the call — top up |
RateLimited |
too many requests; carries retry_after |
UpstreamError |
search index or origin failed; usually transient |
BlockedError |
page refused, or needs a browser (extract_one only) |
KrenzoError |
base class for all of the above |
Rate limits and upstream failures are retried automatically with backoff. Authentication and credit errors are not — they fail identically on a retry.
Usage and billing
Every call records what it cost:
client.search("anything")
print(client.last_usage.balance_usd, client.last_usage.free_calls_remaining)
Calls are billed per call; extract is billed per URL, so a 20-URL batch is 20
calls. Failed requests are not billed, and a call that fails upstream is
refunded.
Configuration
KRENZO_API_KEY |
your API key (or pass api_key=) |
KRENZO_API_URL |
override the base URL, for testing against a local server |
client = Krenzo(api_key="krz_live_...", timeout=30, max_retries=3)
Never hard-code a key in published source. A key committed to a repository is a key anyone can spend, and keys cannot be un-published. Read it from the environment or a secret manager.
License
MIT
Metadata
Release files for krenzo 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| krenzo-0.1.0.tar.gz | 9.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| krenzo-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.9 kB
Release files / krenzo-0.1.0.tar.gz
| Download URL | krenzo-0.1.0.tar.gz |
|---|---|
| Size | 9.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a05ec285258168a5757da990ccf2ef78df2a25b9cf9f6abd50011a9889cf4767
|
|
BLAKE2b-256 checksum How to use checksums |
ab597815febca67fa373a3b92a0f6be39a451ba53f95cc524b51175f2a5f2003
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|
Release files / krenzo-0.1.0-py3-none-any.whl
| Download URL | krenzo-0.1.0-py3-none-any.whl |
|---|---|
| Size | 9.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
4f2e7d52aaa5c10d474f7f2ac862aabc45ead7aa723a67d3f7891adec4f3021d
|
|
BLAKE2b-256 checksum How to use checksums |
36bd20bda8a31c9fb8c9774f84f09df3e305bab0f6861016e9ece399c017762d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|