Code templates
Ready-to-copy code for the Polias Search API, from a one-liner
to a complete search page for your website. Free to use, modify and share, also commercially, no attribution
required (MIT-0 license). Provided without warranty: you are responsible for using it on your website.
Wherever it says pol_YOUR_API_KEY, insert your key (get a key).
Important: keep the key on your server, never in code that runs in your visitors' browser, where anyone could read it and search at your expense. Every search costs one search from your credit.
Vorlagen zum Kopieren
Fertige Bausteine für die Polias Such-Schnittstelle, von einer Zeile zum
Ausprobieren bis zur kompletten Suchseite für Ihre Website. Sie dürfen die Vorlagen frei verwenden, ändern und
weitergeben, auch kommerziell, ohne Namensnennung (Lizenz MIT-0). Ohne Gewähr: Für den Einsatz auf Ihrer
Website sind Sie selbst verantwortlich. Überall, wo pol_YOUR_API_KEY steht, kommt Ihr Schlüssel
hinein (Schlüssel bekommen).
Wichtig: Der Schlüssel gehört auf Ihren Server, nie in Code, der im Browser der Besucher läuft. Sonst kann ihn jeder auslesen und auf Ihre Kosten suchen. Jede Suche zieht eine Suche von Ihrem Guthaben ab.
No coding: a brief for your AIOhne Programmieren: Auftrag für Ihre KI
Working with an AI assistant that can write code? Paste this text and describe what you need in the last line. It contains everything the AI needs to know about our API.
Sie arbeiten mit einem KI-Assistenten, der Code schreiben kann? Kopieren Sie diesen Text hinein und beschreiben Sie in der letzten Zeile, was Sie brauchen. Darin steht alles, was die KI über unsere Schnittstelle wissen muss.
Please add search to my project using the Polias Search API. This is how it works:
- Endpoint: GET https://polias.eu/api/v1/search
- Header: Authorization: Bearer pol_YOUR_API_KEY
The key must stay on the server (environment variable POLIAS_API_KEY), never in browser code.
- Query parameters:
q (search term, required, max. 200 characters), count (1 to 10), offset (0 to 90, 10 = page 2),
lang (de or en; en focuses on technical topics), land (prefer de, at or ch),
ort (a municipality in DE, AT or CH, only with lang=de), quelle=amtlich (official websites only, only with lang=de)
- Response (JSON): {"results": [{"position", "title", "url", "snippet", "hostname", "page_age"}]}
page_age is only present for news articles.
- Errors: 400 invalid request, 401 wrong key, 402 credit used up, 429 too many searches per minute
(wait briefly), 503 temporarily unavailable.
- Every search costs one search from the credit. Escape titles and snippets before showing them as HTML.
What I want: [describe it here, e.g. "a search box on our website that shows only official results for our
town" or "a script that searches for new articles on a topic every morning"].Bitte baue mir eine Suche mit der Polias-Such-Schnittstelle ein. So funktioniert sie:
- Adresse: GET https://polias.eu/api/v1/search
- Schlüssel im Kopf: Authorization: Bearer pol_YOUR_API_KEY
Der Schlüssel darf nur auf dem Server stehen (Umgebungsvariable POLIAS_API_KEY), nie im Browser-Code.
- Angaben in der Adresse:
q (Suchbegriff, Pflicht, höchstens 200 Zeichen), count (1 bis 10), offset (0 bis 90, 10 = Seite 2),
lang (de oder en; en hat den Schwerpunkt Technik), land (de, at oder ch bevorzugen),
ort (eine Gemeinde in DE, AT oder CH, nur bei lang=de), quelle=amtlich (nur amtliche Websites, nur bei lang=de)
- Antwort (JSON): {"results": [{"position", "title", "url", "snippet", "hostname", "page_age"}]}
page_age gibt es nur bei Nachrichten.
- Fehler: 400 Anfrage ungültig, 401 Schlüssel falsch, 402 Guthaben leer, 429 zu viele Suchen je Minute
(kurz warten), 503 vorübergehend nicht verfügbar.
- Jede Suche kostet eine Suche vom Guthaben. Titel und Ausschnitte bitte beim Anzeigen HTML-sicher machen.
Was ich will: [hier beschreiben, z. B. „ein Suchfeld auf unserer Website, das nur amtliche Treffer für unsere
Gemeinde zeigt“ oder „ein Skript, das jeden Morgen nach neuen Meldungen zu einem Thema sucht“].Try it in one minuteIn einer Minute ausprobieren
In a terminal (Windows: PowerShell with curl.exe, Mac and Linux: curl):
Im Terminal (Windows: PowerShell mit curl.exe, Mac und Linux: curl):
curl -H "Authorization: Bearer pol_YOUR_API_KEY" "https://polias.eu/api/v1/search?q=python+asyncio&lang=en&count=3"
Small snippetsKleine Bausteine
One function each that searches and returns the results, with an example call. The key is read from the
environment variable POLIAS_API_KEY.
Je eine Funktion, die sucht und die Treffer zurückgibt, mit einem Beispielaufruf. Der Schlüssel kommt aus der
Umgebungsvariable POLIAS_API_KEY.
Python
import json
import os
import urllib.parse
import urllib.request
API_KEY = os.environ.get("POLIAS_API_KEY", "pol_YOUR_API_KEY")
def polias_search(query, count=10, **params):
"""Search with Polias. params e.g. lang="en", land="at", ort="Graz", quelle="amtlich"."""
url = "https://polias.eu/api/v1/search?" + urllib.parse.urlencode({"q": query, "count": count, **params})
request = urllib.request.Request(url, headers={"Authorization": "Bearer " + API_KEY})
with urllib.request.urlopen(request, timeout=15) as response:
return json.load(response)["results"]
for result in polias_search("python list comprehension", count=3, lang="en"):
print(result["title"], "-", result["url"])
JavaScript (Node.js, server-sideauf dem Server)
// Node.js 18 or newer, on your server (never in the browser, where anyone could read the key).
const API_KEY = process.env.POLIAS_API_KEY || 'pol_YOUR_API_KEY';
async function poliasSearch(query, params = {}) {
const url = new URL('https://polias.eu/api/v1/search');
url.searchParams.set('q', query);
for (const [name, value] of Object.entries(params)) url.searchParams.set(name, value);
const response = await fetch(url, { headers: { Authorization: `Bearer ${API_KEY}` } });
if (!response.ok) throw new Error(`Polias responded with ${response.status}`);
return (await response.json()).results;
}
for (const result of await poliasSearch('kubernetes pod lifecycle', { lang: 'en', count: 3 })) {
console.log(result.title, '-', result.url);
}
PHP
<?php
// PHP 7.4 or newer. Best keep the key in the environment variable POLIAS_API_KEY.
function polias_search(string $query, array $params = []): array
{
$apiKey = getenv('POLIAS_API_KEY') ?: 'pol_YOUR_API_KEY';
$url = 'https://polias.eu/api/v1/search?' . http_build_query(['q' => $query] + $params);
$context = stream_context_create(['http' => [
'header' => "Authorization: Bearer $apiKey\r\n",
'timeout' => 15,
'ignore_errors' => true,
]]);
$response = json_decode((string) @file_get_contents($url, false, $context), true);
return $response['results'] ?? [];
}
foreach (polias_search('Sperrmüll anmelden', ['ort' => 'Freiburg im Breisgau', 'count' => 3]) as $result) {
echo $result['title'], ' - ', $result['url'], "\n";
}
Ready-made search page for your websiteFertige Suchseite für Ihre Website
A single PHP file with search box, result list and “More results”, no dependencies. Made for municipalities,
associations or companies that want to offer search on their website. Save it e.g. as search.php
on your web server and adjust the settings at the top: $UI_LANGUAGE sets the language for your
visitors (English or German), $TOWN puts results for your town first, $OFFICIAL_ONLY
shows only results from public authorities and courts. Runs on PHP 7.4 or newer, like most web hosts.
Every request costs one search. Keep an eye on your credit (/api/v1/usage). The page is closed to
search engines (noindex) and allows at most 30 searches per minute ($MAX_PER_MINUTE),
so bots cannot use up your credit. Your visitors' search terms are sent to Polias to answer them.
Please mention this in your privacy policy.
Eine einzige PHP-Datei mit Suchfeld, Trefferliste und „Weitere Treffer“, ohne weitere Bausteine. Gedacht etwa
für Gemeinden, Vereine oder Firmen, die auf ihrer Website eine Suche anbieten wollen. Datei z. B. als
search.php auf den Webserver legen und oben die Einstellungen anpassen: $UI_LANGUAGE
ist die Sprache für Ihre Besucher ('de' für Deutsch), mit $TOWN kommen Treffer für
Ihren Ort zuerst, mit $OFFICIAL_ONLY nur Treffer von Behörden, Gemeinden und Gerichten. Läuft mit
PHP 7.4 oder neuer, wie bei den meisten Webhostern.
Jeder Aufruf der Seite kostet eine Suche. Behalten Sie Ihr Guthaben im Blick (/api/v1/usage). Die
Seite ist für Suchmaschinen gesperrt (noindex) und lässt höchstens 30 Suchen je Minute zu
($MAX_PER_MINUTE), damit Roboter Ihr Guthaben nicht aufbrauchen. Die Suchbegriffe Ihrer Besucher
werden zur Beantwortung an Polias übermittelt. Bitte erwähnen Sie das in Ihrer Datenschutzerklärung.
Show search page (PHP, about 130 lines)Suchseite anzeigen (PHP, rund 130 Zeilen)
<?php
/*
* Ready-made search page powered by Polias: a single file, PHP 7.4 or newer, no dependencies.
* Put it on your web server (e.g. as search.php) and adjust the settings below.
* Every request with a query costs one search from your Polias credit (check: /api/v1/usage).
* Your visitors' queries are sent to Polias to answer them: please mention this in your privacy policy.
* License MIT-0, provided without warranty.
*/
// ---- Settings -----------------------------------------------------------------------------------
$API_KEY = getenv('POLIAS_API_KEY') ?: 'pol_YOUR_API_KEY'; // your key
$TITLE = 'Search'; // page heading
$UI_LANGUAGE = 'en'; // language of this page for your visitors: 'en' or 'de'
$INDEX_LANGUAGE = 'de'; // search index: 'de' (German) or 'en' (English, focus on technical topics)
$TOWN = ''; // e.g. 'Freiburg im Breisgau': prefer results for this town (German index only)
$OFFICIAL_ONLY = false; // true: only results from public authorities and courts (German index only)
$PER_PAGE = 10; // results per page, 1 to 10
$MAX_PER_MINUTE = 30; // at most this many searches per minute through this page (protects against bots)
// -------------------------------------------------------------------------------------------------
$TEXT = [
'en' => ['placeholder' => 'Enter a search term', 'button' => 'Search', 'none' => 'No results for “%s”.',
'busy' => 'Too many searches right now. Please try again in a minute.',
'down' => 'Search is not available right now. Please try again later.',
'more' => 'More results →', 'credit' => 'Search results by'],
'de' => ['placeholder' => 'Suchbegriff eingeben', 'button' => 'Suchen', 'none' => 'Keine Treffer für „%s“.',
'busy' => 'Gerade sind zu viele Suchen auf einmal. Bitte in einer Minute noch einmal versuchen.',
'down' => 'Die Suche ist gerade nicht erreichbar. Bitte später noch einmal versuchen.',
'more' => 'Weitere Treffer →', 'credit' => 'Suchergebnisse von'],
][$UI_LANGUAGE] ?? [];
function h($text) { return htmlspecialchars((string) $text, ENT_QUOTES, 'UTF-8'); }
// Counts the searches of the current minute for the whole page (stores nothing about visitors).
function within_limit(int $limit): bool
{
$file = fopen(sys_get_temp_dir() . '/polias-search-counter', 'c+');
if (!$file) return true;
flock($file, LOCK_EX);
[$minute, $count] = array_map('intval', explode(' ', trim(stream_get_contents($file)) . ' 0 0'));
$now = (int) (time() / 60);
$count = $minute === $now ? $count + 1 : 1;
ftruncate($file, 0);
rewind($file);
fwrite($file, "$now $count");
flock($file, LOCK_UN);
fclose($file);
return $count <= $limit;
}
$query = trim(mb_substr((string) ($_GET['q'] ?? ''), 0, 200));
$offset = max(0, min(90, (int) ($_GET['start'] ?? 0)));
$results = [];
$error = '';
if ($query !== '' && !within_limit($MAX_PER_MINUTE)) {
$error = $TEXT['busy'];
} elseif ($query !== '') {
$params = ['q' => $query, 'count' => $PER_PAGE, 'offset' => $offset, 'lang' => $INDEX_LANGUAGE];
if ($TOWN !== '' && $INDEX_LANGUAGE === 'de') $params['ort'] = $TOWN;
if ($OFFICIAL_ONLY && $INDEX_LANGUAGE === 'de') $params['quelle'] = 'amtlich';
$context = stream_context_create(['http' => [
'header' => "Authorization: Bearer $API_KEY\r\n",
'timeout' => 15,
'ignore_errors' => true,
]]);
$body = @file_get_contents('https://polias.eu/api/v1/search?' . http_build_query($params), false, $context);
$status = isset($http_response_header[0]) && preg_match('/\s(\d{3})\s/', $http_response_header[0], $m) ? (int) $m[1] : 0;
if ($status === 200) {
$results = json_decode($body, true)['results'] ?? [];
} elseif ($status === 429) {
$error = $TEXT['busy'];
} else {
$error = $TEXT['down'];
error_log("Polias search: status $status"); // 401 = wrong key, 402 = credit used up
}
}
?><!doctype html>
<html lang="<?= h($UI_LANGUAGE) ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex, nofollow">
<title><?= h($query !== '' ? "$query – $TITLE" : $TITLE) ?></title>
<style>
body { font: 17px/1.5 system-ui, sans-serif; max-width: 760px; margin: 0 auto; padding: 24px 16px; color: #1d1d1b; }
form { display: flex; gap: 8px; margin: 16px 0 24px; }
input[type=search] { flex: 1; font: inherit; padding: 10px 14px; border: 1px solid #bbb; border-radius: 10px; }
button { font: inherit; padding: 10px 18px; border: 0; border-radius: 10px; background: #16241a; color: #fff; cursor: pointer; }
.result { margin: 0 0 22px; }
.result a { font-size: 19px; color: #1a4fa0; text-decoration: none; }
.result a:hover { text-decoration: underline; }
.url { color: #2e6b3a; font-size: 14px; word-break: break-all; }
.snippet { margin: 2px 0 0; color: #444; }
.credit { color: #666; font-size: 14px; }
</style>
</head>
<body>
<h1><?= h($TITLE) ?></h1>
<form method="get" role="search">
<input type="search" name="q" value="<?= h($query) ?>" placeholder="<?= h($TEXT['placeholder']) ?>" maxlength="200" aria-label="<?= h($TEXT['placeholder']) ?>" autofocus>
<button type="submit"><?= h($TEXT['button']) ?></button>
</form>
<?php if ($error !== ''): ?>
<p><?= h($error) ?></p>
<?php elseif ($query !== '' && !$results): ?>
<p><?= h(sprintf($TEXT['none'], $query)) ?></p>
<?php endif; ?>
<?php foreach ($results as $r): if (!preg_match('#^https?://#i', $r['url'] ?? '')) continue; ?>
<div class="result">
<a href="<?= h($r['url']) ?>" rel="noopener"><?= h($r['title']) ?></a>
<div class="url"><?= h($r['url']) ?></div>
<?php if (!empty($r['snippet'])): ?><p class="snippet"><?= h($r['snippet']) ?></p><?php endif; ?>
</div>
<?php endforeach; ?>
<?php if (count($results) === $PER_PAGE && $offset + $PER_PAGE <= 90): ?>
<p><a href="?<?= h(http_build_query(['q' => $query, 'start' => $offset + $PER_PAGE])) ?>" rel="nofollow"><?= h($TEXT['more']) ?></a></p>
<?php endif; ?>
<p class="credit"><?= h($TEXT['credit']) ?> <a href="https://polias.eu">Polias</a></p>
</body>
</html>
Connect AI assistants (MCP)KI-Assistenten anbinden (MCP)
So your AI assistant can search Polias itself. More programs (Open WebUI, LibreChat, n8n …) in the developer guide.
Damit Ihr KI-Assistent selbst bei Polias sucht. Weitere Programme (Open WebUI, LibreChat, n8n …) in der Anleitung.
Cursor (.cursor/mcp.json)
{
"mcpServers": {
"polias": {
"url": "https://polias.eu/mcp",
"headers": { "Authorization": "Bearer pol_YOUR_API_KEY" }
}
}
}
Visual Studio Code (.vscode/mcp.json)
{
"servers": {
"polias": {
"type": "http",
"url": "https://polias.eu/mcp",
"headers": { "Authorization": "Bearer pol_YOUR_API_KEY" }
}
}
}
QuestionsFragen
Something not working, or missing a template? Write to us at hallo@polias.eu. All parameters are in the developer guide.
Klappt etwas nicht, oder fehlt Ihnen eine Vorlage? Schreiben Sie uns an hallo@polias.eu. Alle Angaben stehen in der Anleitung für Entwickler.