Ausschreibungsmonitor
Automatische Lieferung neuer Ausschreibungen nach Ihren Filtern — Region, Branchen-Tags, Schlagworte, Wertbereich. Pull-API + E-Mail-Digest + Webhook.
Konzepte
Vier Begriffe, die in allen Endpoints vorkommen:
- Tender — eine konkrete Ausschreibung von einem Portal (NEN, VVZ, E-ZAK, TenderArena, etc.). Mit numerischer ID identifiziert.
- Filter — gespeicherte Kriterien-Set (Region, Branche, Schlüsselwörter, Wert). Wenn eine neue Ausschreibung die Kriterien erfüllt, entsteht ein Match.
- Match — neue Ausschreibung, die in Ihren Filter gefallen ist. Repräsentiert die Verknüpfung (tender × filter) + Timestamp + Ihren Status (markiert / ausgeblendet / gesehen).
- Taxonomy — kontrollierte Vokabulare für Regionen (NUTS), Branchen (Industry-Tags) und CPV-Codes zur Klassifikation der Ausschreibungen.
Schnellstart
Filter können auf zwei Wegen angelegt werden — das Ergebnis ist identisch und ein Filter lässt sich jederzeit über beide Wege bearbeiten.
curl -H "X-Api-Key: mrw_live_…" \ "https://veritra.io/api/v2/leads/tenders/search?qText=rekonstrukce%20mostu&limit=5"
Oben ist eine Ad-hoc-Suche. Für kontinuierliches Monitoring (neue Ausschreibungen passend zu Ihren Kriterien) nutzen Sie Filter + Webhook/E-Mail-Digest — siehe unten.
Ausschreibungssuche (Ad-hoc)
Für einmalige Suchen über alle aktiven Ausschreibungen. Nutzt keinen gespeicherten Filter — Parameter gehen direkt in den Query-String.
/api/v2/leads/tenders/searchQuery-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
| qText* | string | Suchtext (Volltext in title + description). |
| regions | string | NUTS-Leaf-Codes CSV (CZ010,CZ020). |
| cpvPrefixes | string | CPV-Prefixes CSV (45,452). |
| industryTags | string | Industry-Tag-IDs CSV (con_buildings,it_development). |
| minValue | number | Min. geschätzter Wert (CZK). Ausschreibungen ohne Wertangabe gehen durch. |
| maxValue | number | Max. geschätzter Wert (CZK). Ausschreibungen ohne Wertangabe gehen durch. |
| deadlineFrom | string (YYYY-MM-DD) | Abgabefrist >= YYYY-MM-DD. |
| deadlineTo | string (YYYY-MM-DD) | Abgabefrist <= YYYY-MM-DD. |
| sort | "newest" | "deadline" | "value" | Sortierung: newest (Default), deadline (aufsteigend), value (absteigend). |
| limit | number | Ergebnisanzahl, max. 1000 (Standard: 50). Für >1k Ergebnisse nextCursor-Paginierung oder /matches/export verwenden. |
| cursor | string | Keyset-Cursor aus vorheriger Seite (pagination.nextCursor). |
Beispiel
curl -H "X-Api-Key: mrw_live_…" \ "https://veritra.io/api/v2/leads/tenders/search?qText=rekonstrukce®ions=CZ010,CZ020&minValue=500000&limit=10"
/api/v2/leads/tenders/:idResponse: { data: { id, title, description, estimatedValue, deadlineAt, contractingAuthority, documents[], starred, excluded } }.
/api/v2/leads/tenders/:id/emailBody kann recipientEmail enthalten für Weiterleitung an andere E-Mail. Default user.email.
/api/v2/leads/documents/previewQuery: ?url=:original&kind=docx|xlsx. Allowlist-Hosts: NEN, E-ZAK, Tender Arena, Gemin, ProfilZadavatele.
GET /api/v2/leads/documents/preview?url=https://nen.nipez.cz/…/Vyzva.docx&kind=docx → 302 Location: https://rwx-storage…/Tendero/doc-cache-v8/<hash>.html (signed, TTL 10 min)
Katalog & Autocomplete (öffentlich, ohne Schlüssel)
Für UI-Dropdowns und Filter-Erstellung. Server-Cache 1h. Öffentlich, keine Auth erforderlich.
/api/v2/leads/zadavatele?q=praha/api/v2/leads/countries/api/v2/leads/regions?country=CZ/api/v2/leads/regions/catalog?country=CZ&locale=cs/api/v2/leads/taxonomy/industry/api/v2/leads/taxonomy/cpvFilter-Felder und erlaubte Werte
Ein Filter besteht aus den folgenden Feldern. Alle sind optional außer `name`. Ein leeres Feld bedeutet keine Einschränkung in dieser Dimension.
regions string[]
NUTS-Regionen für das gegebene Land (?country=CZ) mit Locale-Labels.
CZTschechienSKSlowakeiPLPolenDEDeutschlandATÖsterreichFRFrankreichESSpanienITItalienNLNiederlandeBEBelgienPTPortugalSESchwedenFIFinnlandDKDänemarkNONorwegenIEIrlandGRGriechenlandRORumänienBGBulgarienHUUngarnHRKroatienSISlowenienLTLitauenLVLettlandEEEstlandLULuxemburgCYZypernMTMaltaCHSchweizISIslandMKNordmazedonienFür den vollen NUTS-Baum eines konkreten Landes:
GET /api/v2/leads/regions/catalog?country=CZ&locale=cs GET /api/v2/leads/regions/catalog?country=DE&locale=de GET /api/v2/leads/regions/catalog?country=FR&locale=en
Beispiel: NUTS-3-Codes für CZ (Regionen) — aufklappen ▸
CZ010Hauptstadt PragCZ020Mittelböhmische RegionCZ031Südböhmische RegionCZ032Pilsner RegionCZ041Karlsbader RegionCZ042Aussiger RegionCZ051Reichenberger RegionCZ052Königgrätzer RegionCZ053Pardubitzer RegionCZ063Region VysočinaCZ064Südmährische RegionCZ071Olmützer RegionCZ072Zliner RegionCZ080Mährisch-Schlesische RegionindustryTags string[] Empfohlen
Multi-Tag-Branchenklassifikation. Eine Ausschreibung kann mehrere Tags haben (z.B. 'stav_pozemni' + 'stav_remesla' bei einer Sanierung). Der Filter trifft eine Ausschreibung, wenn mindestens einer der gewünschten Tags gesetzt ist (JSON_OVERLAPS).
Warum industryTags besser sind als CPV: Unsere industryTags kombinieren LLM-Klassifikation des Titels/Beschreibung der Ausschreibung mit CPV-Mapping und Regex-Hinweisen — sie erfassen relevante Ausschreibungen auch bei Auftraggebern, die CPV-Codes nachlässig vergeben. Ein reiner CPV-Filter ist exakt, hängt aber von der Disziplin der Auftraggeber ab, die in CZ schwach ist.
con_buildingsHochbau und Sanierungcon_civilTiefbau (Straßen, Brücken, Wasser)con_tradesBaugewerke und Teilarbeitencon_energy_efficiencyEnergieeinsparung & erneuerbare Energiencon_materialsBaumaterialiendes_documentationPlanungsdokumentation und Studiendes_supervision_ohsBauüberwachung und Arbeitsschutzdes_surveyingVermessung und Flurneuordnungit_developmentSoftwareentwicklung und Integrationit_licensingSoftwarelizenzen und Abonnementsit_hardwareHardware und Infrastrukturit_cybersecurityCybersicherheitit_data_aiDaten, Analytik, KI/MLtelecom_internetTelekom, Internet, Mobilfunkprof_marketingMarketing, PR, Werbungprof_legalRechtsdienstleistungenprof_accountingBuchhaltung, Förderungen, Auditprof_hrHR, Personalbeschaffungprof_translationÜbersetzung und Dolmetschenprof_insuranceVersicherung und Finanzenops_cleaningReinigungsdiensteops_securitySicherheit und Empfangops_maintenanceWartung und Service von Anlagenops_wasteAbfallwirtschaftops_facilityImmobilienverwaltungcat_cateringVerpflegung, Cateringcat_accommodationUnterkunft und Konferenzencat_foodLebensmittel und Getränketrans_transportPersonen- und Güterverkehrtrans_vehiclesFahrzeuge, Teile, Leasinghealth_pharmaArzneimittel und Pharmahealth_devicesMedizingeräte und -materialhealth_careGesundheits- und Sozialwesengoods_furnitureMöbel und Innenausstattunggoods_clothingBekleidung, PSA, Uniformengoods_electricalElektromaterialgoods_machineryIndustriemaschinenenergy_fuelsKraftstoffe und Brennstoffeenergy_power_heatStrom und Wärmeenergy_waterWasserversorgungnat_forestryForstwirtschaftnat_greeneryGrünpflege und Gartenbaunat_agricultureLandwirtschaftdefense_safetyFeuerwehr, Militär, Verteidigungsci_labLabor- und Messgerätesci_researchForschung und Entwicklungedu_trainingBildung und Schulungculture_mediaKultur, Bücher, Mediencategories string[] Weniger genau
CPV-Präfixe (Common Procurement Vocabulary) beliebiger Länge — Match über `LIKE 'präfix%'`. Also '45' erfasst alle Bau-Hauptgruppen, '4523' nur Tiefbau, '45316110' nur Straßenbeleuchtung.
03Landwirtschaft, Forstwirtschaft, Fischerei09Brennstoffe und Energie15Lebensmittel und Getränke18Kleidung, Schuhe, PSA22Druckerzeugnisse, Bücher30Büromaschinen, IT-Ausrüstung31Elektrische Maschinen, Kabel, Beleuchtung32Radio, TV, Telekommunikation33Medizintechnik, Arzneimittel34Fahrzeuge, Transport35Sicherheit, Feuerwehr- und Militärtechnik38Labor- und Messgeräte39Möbel, Innenausstattung42Industriemaschinen44Baumaterialien und Konstruktionen45Bauarbeiten48Software und Lizenzen50Reparatur und Wartung55Gastronomie, Unterkunft60Transport (Beförderung)64Post, Telekommunikationsdienste65Versorgungsleistungen (Strom, Wasser)66Finanz- und Versicherungsdienste70Immobilien und Facility Management71Architektur, Planung, Ingenieurdienste72IT-Dienste (Entwicklung, Integration, Support)73Forschung und Entwicklung75Öffentliche Verwaltung, Verteidigung77Land-, forst- und gartenbauliche Dienste79Unternehmensdienste (Recht, Buchhaltung, HR, Marketing)80Bildung und Schulung85Gesundheits- und Sozialfürsorge90Abfall, Umwelt, Reinigung92Kultur, Sport, Freizeit98Sonstige Dienste für die ÖffentlichkeitVollständiger Katalog (9.454 Codes) verfügbar unter /docs/leads/cpv — durchsuchbar und nach Abteilungen gruppiert.
keywords string[]
LIKE-Match in Titel und Beschreibung der Ausschreibung. Case-insensitive. OR zwischen Einträgen. Sinnvoll als Sicherheitsnetz, falls industryTags/CPV nicht alles erfasst (z.B. spezifischer Ausschreibungstyp, der nur im Text auftaucht).
"keywords": ["Sanierung", "Beleuchtung", "Kindergarten"]
minValue / maxValue number | null
Geschätzter Wertbereich der Ausschreibung in CZK. Sie können nur minValue, nur maxValue oder beides setzen.
emailDigest boolean
Wenn true, erhalten Sie 1× täglich (5:00 UTC) eine E-Mail mit den neuen Treffern dieses Filters. Standard true. Deaktivierung durch Bearbeiten des Filters. Webhooks werden separat auf Konto-Ebene konfiguriert (siehe unten).
name string · active boolean
`name` — max. 120 Zeichen, Pflichtfeld. `active` — wenn false, wird der Filter aus dem Cron ausgenommen (keine neuen Treffer, kein Digest, kein Webhook). Pausieren ohne Löschen.
Filterlogik
Felder kombinieren wie folgt:
MATCH = (Auftraggeber.NUTS3 ∈ expand(regions))
AND (minValue ≤ estimatedValue ≤ maxValue ODER estimatedValue ist null oder 0)
AND (industry_or_cpv ODER keyword_match)
# expand(regions): NUTS-Codes werden auf NUTS-3-Blätter erweitert
# (CZ → 14 Regionen, CZ01 → CZ010, CZ010 → CZ010).
industry_or_cpv:
wenn industryTags gesetzt → JSON_OVERLAPS(industryTags, tender.industryTags)
sonst categories gesetzt → tender.cpvCode LIKE ANY (categories + "%")
sonst → false (kein Industry-Filter angewendet)
keyword_match:
wenn keywords gesetzt → tender.title oder description LIKE ANY (%kw%)
sonst → false
# Wenn Sie keine industryTags / categories / keywords angeben,
# werden alle Ausschreibungen zurückgegeben, die regions und value range erfüllen.industryTags hat Vorrang vor categories — wenn Sie beide angeben, wird nur industryTags verwendet (categories wird ignoriert). keywords funktionieren unabhängig (sie sind im OR-Zweig mit industry_or_cpv).
Endpunkte zur Filterverwaltung
Verwenden Sie für die Filterverwaltung den Management-Key (mrw_live_…). Er hat eigene Rate-Limits und verbraucht keine LEADS-Credits, sodass die Filterverwaltung Ihren täglichen Lead-Abruf nicht beeinflusst.
/api/v2/leads/filters/api/v2/leads/filters/api/v2/leads/filters/:id/api/v2/leads/filters/:id/api/v2/leads/filters/:id/api/v2/leads/filters/:id/matches/export?format=csv|xlsx|json&view=all|starred|excludedBody-Parameter (POST / PUT) — gemeinsam
| Parameter | Typ | Beschreibung |
|---|---|---|
| name* | string | Filtername (max. 120 Zeichen) |
| regions | string[] | NUTS-Codes (z. B. `CZ010`). Beliebige Ebenen mischbar. Leeres Array = alle Regionen. |
| industryTags | string[] | Empfohlener Weg. Tag-IDs aus unserer Taxonomie (z.B. 'stav_pozemni', 'it_vyvoj'). Multi-Tag — OR zwischen Einträgen. |
| categories | string[] | CPV-Präfixe beliebiger Länge (z.B. '45', '4523', '45316110'). Weniger genau als industryTags. |
| keywords | string[] | Schlagworte — LIKE-Match in Titel und Beschreibung (OR zwischen Einträgen). |
| minValue | number | null | Min. geschätzter Wert (CZK). Ausschreibungen ohne Wertangabe gehen durch. |
| maxValue | number | null | Max. geschätzter Wert (CZK). Ausschreibungen ohne Wertangabe gehen durch. |
| emailDigest | boolean | Täglicher E-Mail-Digest (Standard: true) |
| active | boolean | Aktiver Filter (Standard: true) |
Webhooks werden nicht mehr pro Filter konfiguriert — siehe Abschnitt Webhook unten (Konto-Endpunkte). Das Feld webhookUrl wird aus Sicherheitsgründen mit HTTP 410 abgelehnt.
Beispiele
Bauarbeiten in Prag über 500 Tsd. CZK
curl -X POST -H "X-Api-Key: mrw_live_…" \
-H "Content-Type: application/json" \
-d '{
"name": "Bauarbeiten Prag 500k+",
"regions": ["CZ010"],
"industryTags": ["con_buildings", "con_trades"],
"minValue": 500000
}' \
https://veritra.io/api/v2/leads/filtersIT-Entwicklung und SW-Lizenzen (alle Regionen)
curl -X POST -H "X-Api-Key: mrw_live_…" \
-H "Content-Type: application/json" \
-d '{
"name": "IT-Entwicklung + SW-Lizenzen",
"industryTags": ["it_development", "it_licensing", "it_data_ai"],
"keywords": ["Informationssystem", "Modul"]
}' \
https://veritra.io/api/v2/leads/filtersÖffentliche Beleuchtung (CZ) — Tags + Keywords Kombination
curl -X POST -H "X-Api-Key: mrw_live_…" \
-H "Content-Type: application/json" \
-d '{
"name": "Öffentliche Beleuchtung (CZ)",
"industryTags": ["goods_electrical", "con_civil"],
"keywords": ["Beleuchtung", "Straßenbeleuchtung", "öffentliche Beleuchtung", "Lampen"],
"minValue": 200000
}' \
https://veritra.io/api/v2/leads/filtersFilter deaktivieren
curl -X PATCH -H "X-Api-Key: mrw_live_…" \
-H "Content-Type: application/json" \
-d '{"active": false}' \
https://veritra.io/api/v2/leads/filters/<id>Zustellung — Webhook vs. Polling
Zwei Wege, neue Ausschreibungen ins ERP zu bekommen. Die meisten Integratoren kombinieren beide.
Webhook (Push)
Tendero schickt POST an deinen Endpoint innerhalb von ~2 Sekunden nach Match. Event leads.match.created mit voller Tender-Payload.
Plus: Echtzeit, kein Polling-Overhead, Server-side Gating.
Minus: erfordert öffentlich erreichbaren Endpoint (HTTPS), HMAC-Verifikation, Idempotency-Handling.
Polling (Pull)
Dein ERP ruft GET /api/v2/leads/matches?since=… periodisch auf (z. B. alle 5 min). Gibt Matches seit dem Timestamp zurück.
Plus: kein öffentlicher Endpoint, einfache Implementierung, restart-freundlich.
Minus: Latenz 5-10 min, Rate-Limit (60 req/min Mgmt-API), unnötige Leer-Antworten.
Treffer abrufen
/api/v2/leads/matchesQuery-Parameter
| Parameter | Typ | Beschreibung |
|---|---|---|
| filterId | string | Auf einen bestimmten Filter einschränken |
| qText | string | Suchtext (Volltext in title + description). |
| since | string (ISO 8601 datetime) | Nur Treffer seit diesem Datum (ISO-Datetime) |
| delivered | boolean | false = nur unzugestellte, true = nur zugestellte |
| view | "starred" | "excluded" | Spezielle View: starred (Favoriten) | excluded (versteckt). |
| sort | "newest" | "deadline" | "value" | Sortierung: newest (Default), deadline (aufsteigend), value (absteigend). |
| limit | number | Ergebnisanzahl, max. 1000 (Standard: 50). Für >1k Ergebnisse nextCursor-Paginierung oder /matches/export verwenden. |
| cursor | string | Keyset-Cursor aus vorheriger Seite (pagination.nextCursor). |
Zurückgegebene Treffer werden automatisch markiert als delivered=true. Jeder Request verbraucht 1 Credit.
matchId-Formate
matchId hat zwei Formate je nach Herkunft:
cm…(cuid-Präfix) — zurückgegeben aus vorberechneter LeadMatch-Tabelle (täglicher Cron). Stabil über Calls hinweg, verwendbar für mark-as-viewed.live-12345synthetischer Präfix für live-erkannte Matches via Search / Browse-Modus (qText, view=starred/excluded). Nicht in LeadMatch-Tabelle → mark-as-viewed ist no-op. tenderId ist der Bindestrich-Suffix.
Beispiel
curl -H "X-Api-Key: mrw_leads_…" \ "https://veritra.io/api/v2/leads/matches?delivered=false&limit=10"
Antwort
{
"data": [
{
"matchId": "cm…",
"filterId": "cm…",
"filterName": "Bauarbeiten Prag",
"matchedAt": "2026-04-03T06:00:00.000Z",
"viewedAt": null,
"delivered": true,
"tender": {
"id": 12345,
"title": "Brückensanierung Reg.-Nr. 123",
"estimatedValue": 12500000,
"deadlineAt": "2026-05-15T22:00:00.000Z",
"publishedAt": "2026-04-01T08:00:00.000Z",
"firstSeenAt": "2026-04-01T08:30:00.000Z",
"url": "https://nen.nipez.cz/...",
"portalType": "NEN",
"cpvCode": "45000000",
"tenderType": "OFFERS",
"contractingAuthority": {
"ico": "12345678",
"name": "Město Praha",
"region": "Praha",
"district": "Praha 1"
},
"documents": [
{ "name": "Výzva.pdf", "url": "https://nen.nipez.cz/…", "fileType": "pdf", "fileSizeBytes": 320000 }
],
"starred": false,
"excluded": false
}
}
],
"pagination": { "nextCursor": "eyJmaXJzdFNlZW5BdC…", "totalCount": 42 }
}Für nächste Seite, übergib pagination.nextCursor als ?cursor= Parameter.
Match-Aktionen
Star (Favorit), exclude (ausblenden) und view (als gelesen markieren) sind Per-Tender-Preferences in UserTenderPreference.
/api/v2/leads/matches/:matchIdResponse: gleiche Struktur wie Matches-List-Item.
/api/v2/leads/matches/:matchId/star{ "starred": true }/api/v2/leads/matches/:matchId/exclude{ "excluded": true }/api/v2/leads/matches/:matchId/viewNo-op für synthetische live-:id-Matches (keine Zeile zum Markieren).
/api/v2/leads/preferences{
"data": {
"starred": [12345, 67890],
"excluded": [54321]
}
}Taxonomy
Statische Referenzkataloge für Filter-Values. Locale-aware Labels.
/api/v2/leads/taxonomy/industry?locale=cs{
"data": {
"locale": "cs",
"areas": [{ "id": "construction", "icon": "🏗️", "label": "Stavebnictví" }, …],
"tags": [
{ "id": "con_buildings", "area": "construction", "label": "Pozemní stavby", "cpvPrefixes": ["452"] },
…
]
}
}/api/v2/leads/taxonomy/cpv?locale=csResponse: Baumstruktur Divisions → Groups → Classes → Categories → Subcategories.
Webhook
Webhook-Endpoints (CRUD, Secret-Rotation) sind account-level — einmalig dokumentiert in Account-API → Webhooks. Dieser Abschnitt behandelt nur das leads-spezifische Event-Payload (leads.match.created) und HMAC-Verifizierung.
Event-Zustellung
Bei einem neuen Match senden wir ein Event vom Typ leads.match.created mit HMAC-SHA256-Signatur im Header X-Signature-256, Idempotency-Key in X-Idempotency-Key und Typ in X-Event-Type. Bei Fehlschlag erfolgen Retries mit exponentiellem Backoff bis zu ~33 Stunden.
Retry-Policy
Wenn dein Endpoint non-2xx zurückgibt (oder nicht innerhalb von 10s antwortet), retry Tendero mit exponential backoff: 1min, 5min, 30min, 2h, 12h, 24h. Nach 6 Fehlschlägen wird der Webhook als failed markiert und im Dashboard markiert. Idempotency-Key bleibt für jeden Retry gleich — dein Endpoint MUSS deduplizieren (sonst wird derselbe Match 6× verarbeitet).
Endpoints per API verwalten
Webhook-Endpoints können ohne Dashboard verwaltet werden. Limit: 5 Endpoints pro Konto.
/api/v2/account/webhooks/api/v2/account/webhooks/api/v2/account/webhooks/:id/api/v2/account/webhooks/:id/api/v2/account/webhooks/:id/api/v2/account/webhooks/:id/rotate-secret/api/v2/account/webhooks/:id/test/api/v2/account/webhooks/:id/deliveries/api/v2/account/webhooks/:id/deliveries/:deliveryId/replayHMAC-Signaturverifikation
Server signiert Payload als HMAC-SHA256(secret, raw_body) und schickt im X-Signature-256-Header im sha256=hex-Format. Verifiziere in Constant-Time, sonst ist die Integration anfällig für Timing-Angriffe.
// Node.js (Express)
import crypto from "node:crypto";
const WEBHOOK_SECRET = process.env.MRICKWOOD_WEBHOOK_SECRET!;
function verify(rawBody: string, sig: string | undefined): boolean {
if (!sig) return false;
const expected = "sha256=" + crypto
.createHmac("sha256", WEBHOOK_SECRET)
.update(rawBody)
.digest("hex");
// Constant-time comparison (timing-safe)
const a = Buffer.from(sig);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
app.post("/webhooks/veritra",
express.raw({ type: "application/json" }),
async (req, res) => {
const raw = req.body.toString("utf8");
if (!verify(raw, req.header("X-Signature-256"))) {
return res.status(401).send("Invalid signature");
}
const idempKey = req.header("X-Idempotency-Key")!;
const evt = JSON.parse(raw);
// Idempotency: store idempKey, skip if already processed
if (await alreadyProcessed(idempKey)) return res.status(200).send("ok");
await processEvent(evt);
await markProcessed(idempKey);
res.status(200).send("ok"); // Must be 2xx within 10s
},
);# Python (Flask)
import hmac, hashlib, os
from flask import Flask, request, abort
WEBHOOK_SECRET = os.environ["MRICKWOOD_WEBHOOK_SECRET"]
def verify(raw: bytes, sig: str | None) -> bool:
if not sig: return False
expected = "sha256=" + hmac.new(
WEBHOOK_SECRET.encode(), raw, hashlib.sha256
).hexdigest()
return hmac.compare_digest(sig, expected)
@app.post("/webhooks/mrickwood")
def webhook():
raw = request.get_data()
if not verify(raw, request.headers.get("X-Signature-256")):
abort(401)
# ... idempotency check + process
return "ok", 200{
"id": "evt_…",
"type": "leads.match.created",
"createdAt": "2026-04-03T06:00:00.000Z",
"data": {
"filterId": "cm…",
"filterName": "Bauarbeiten Prag",
"matchId": "cm…",
"tender": { "id": "12345", "title": "…", "estimatedValue": 12500000 }
}
}E-Mail-Digest
Mit emailDigest: true erhalten Sie eine tägliche E-Mail mit den neuen Aufträgen. Der Digest wird morgens (5:00 UTC) an Ihre Konto-E-Mail gesendet. Lässt sich durch Bearbeiten des Filters deaktivieren.
Limits
| Parameter | Typ | Beschreibung |
|---|---|---|
| Testphase | 500 req/Monat | 1 Tag kostenlos. Keine Karte / Abrechnungsprofil nötig. Default ApiKey.requestsLimit. |
| Bezahlter Plan | unbegrenzt | Monatslimit aufgehoben. Nur das technische Rate Limit 100/h/Schlüssel gilt. |
| Filter | 20 | Max. Anzahl aktiver Filter pro Konto. |
| Webhook-Endpoints | 5 | Max. Anzahl aktiver Webhook-URLs pro Konto. |
Bei Überschreitung des Monatslimits antwortet die API mit 429 und einem Retry-After-Header. Das Limit wird am 1. des Monats zurückgesetzt.