Search the independent web.
One HTTP endpoint. Send a query, get back ranked, deduplicated results from the WebAtlas index — no scraping, no headless browsers, no rate-limit roulette.
The WebAtlas API gives programmatic access to the same index that powers WebAtlas search. Every request is authenticated with an API key tied to a subscription plan, and every response is plain JSON — ranked by relevance, deduplicated by domain, and optionally filtered for safe search.
Authentication
Every request needs a key query parameter. Keys are issued per plan from your
WebAtlas Cloud dashboard
after subscribing, and look like this:
wa_3f8a1b2c4d9e7f1a0b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e
Keys are passed in the URL, not in a header — this keeps simple GET requests
copy-pasteable in a browser or curl one-liner.
Quickstart
A minimal search request with curl:
curl
"https://cloud.webatlasindex.pl/api.php?q=polish+search+engines&key=YOUR_API_KEY"
The same request in JavaScript:
const res = await fetch(
"https://cloud.webatlasindex.pl/api.php?q=polish+search+engines&key=YOUR_API_KEY"
);
const data = await res.json();
console.log(data.results);
And in Python:
import requests
res = requests.get(
"https://cloud.webatlasindex.pl/api.php",
params={"q": "polish search
engines", "key": "YOUR_API_KEY"},
)
data = res.json()
print(data["results"])
Endpoint
This is the only endpoint in the API. All search functionality is controlled through query parameters below.
Parameters
| Parameter | Type | Description |
|---|---|---|
| keyrequired | string | Your API key, format wa_<48 hex chars>. Get one from the
dashboard. |
| qrequired | string | Search query. Max 200 characters. URL-encode spaces and special characters. |
| langoptional | string | 2-letter language filter (e.g. pl, en, de).
Non-letter characters are stripped automatically. |
| dateoptional | string | Filter by publish date. Accepts any format strtotime() understands
(e.g. 2026-06-01). Invalid dates are ignored silently. |
| safeoptional | boolean | Set to true to exclude adult content and known unsafe domains from
results. Default is off. |
| pageoptional | integer | Page number for pagination, starting at 1. Default 1. |
| newsoptional | boolean | By default, a handful of fresh, relevant news articles are blended straight into
results on page 1 — see Response format for
how they're ranked and shaped. Set to false to disable blending
entirely. For dedicated, paginated news search, use the News
API instead. |
Response format
All responses are JSON with a top-level success boolean.
Successful response
{
"success": true,
"query": "polish search",
"pagination": {
"page": 1,
"total": 5,
"total_pages": 1,
"max_reached": false
},
"did_you_mean": null,
"results": [
{
"url": "https://webatlasindex.pl/example-page",
"title": "WebAtlas Index — Polish
independent website index",
"description": "Search results from the
WebAtlas Index for quality, ad-free content.",
"language": "pl",
"publish_date": "2026-06-01",
"indexed_at": "2026-06-10
12:00:00"
}
]
}
Fields
| pagination.total | Total matching results across all pages, capped at 20. |
| pagination.total_pages | Number of pages available, 20 results per page. |
| pagination.max_reached | True when the 20-result cap was hit — refine your query for more precision rather than paging further. |
| did_you_mean | null, or {"query", "title"} with a corrected suggestion
when your query returned zero results but closely matches a known site. |
| results[].url | Canonical URL of the indexed page. |
| results[].title | Page title as indexed. |
| results[].description | Extracted page description or summary. |
| results[].language | Detected 2-letter language code. |
| results[].publish_date | Publish date if detected, otherwise null. On a blended news item
(see below), this is the article's publish timestamp. |
| results[].indexed_at | Timestamp when WebAtlas last indexed the page. Always null on a
blended news item — news is proxied from cache, not indexed. |
Blended news in results
Unless news=false is set, page 1 of results may include a few
fresh news articles alongside regular site results — powered by the same data as the
News API. A blended item is a results entry like any
other, with the exact same fields — there's nothing extra to parse for.
Placement is deliberately conservative: by default, a matching news article is appended to
the end of the page, after every genuine index result. It only gets inserted near
the top (right after your #1 result) when the match is unambiguous — the article's domain
is exactly what you searched for, or its title substantially overlaps your query, not just
a passing mention. Searching google won't bury google.com under
an article that merely name-drops Google in a long headline about something else.
Error response
{
"success": false,
"error": {
"code": 401,
"message": "Invalid or missing API
key."
}
}
Errors
The HTTP status code always matches error.code in the response body.
q parameter, or query exceeds 200
characters.GET.News API
A dedicated endpoint for searching fresh news, separate from the main site index. It's the
same product as api.php — same key, same api_keys
record, same plans and quotas from Plans & quotas below. One request
to news.php counts against your quota exactly like one request to
api.php.
Parameters
| Parameter | Type | Description |
|---|---|---|
| keyrequired | string | Same API key as api.php. |
| qrequired | string | Search query, matched against each article's title, excerpt, source and domain. Max 200 characters. |
| langoptional | string | 2-letter language filter (e.g. pl, en). |
| pageoptional | integer | Page number for pagination, starting at 1. Default 1,
20 results per page. |
Response format
{
"success": true,
"query": "onet",
"generated_at": "2026-10-05T19:05:07Z",
"stale": false,
"pagination": {
"page": 1,
"total": 14,
"total_pages": 1
},
"results": [
{
"url": "https://wiadomosci.onet.pl/kraj/example-article/abc123",
"title": "Example headline",
"description": "Short excerpt of the
article.",
"language": "pl",
"category": "national",
"source": "Onet",
"domain": "onet.pl",
"image": "https://cdn.onet.pl/example.jpg",
"published_at": "2026-10-05
18:37:42"
}
]
}
| generated_at | When the underlying news data was generated upstream. |
| stale | True if the live news source was unreachable and this response was served from an older cached copy. |
| results[] | Ranked by relevance first (exact domain match or a near word-for-word title match ranks highest), then by publish time — newest first within the same relevance tier. |
| results[].category / source / domain / image | As provided by the upstream source; any of these may be null. |
Errors follow the same codes as Errors above (401/403/405/429/500), plus one of its own:
Plans & quotas
Every API key belongs to exactly one plan. Quota resets on the 1st of each month.
| Plan | Price | Monthly quota | Rate limit |
|---|---|---|---|
| Starter | $2/mo | 1,000 requests | 30 req/min |
| Growth | $18/mo | 10,000 requests | 50 req/min |
| Business | $80/mo | 50,000 requests | 90 req/min |
| Agency | $150/mo | 100,000 requests | 300 req/min |
Manage your subscription, view usage, and regenerate keys anytime from the Dashboard.
Rate limits
Rate limits are enforced per minute, per API key, on top of your monthly quota. Exceeding either
returns 429 with a message identifying which limit was hit.
- Per-minute limit resets every minute — back off and retry after a few seconds.
- Monthly quota resets on the 1st — upgrade your plan from the dashboard if you're consistently hitting it.
- Results are cached for performance. Identical queries (same
q,lang,date,safe,page) are served from our cache in accordance with our Usage License (12–48h refresh cycle) and Privacy Policy, reducing latency without impacting your quota.