Zum Inhalt springen

Bald geht's los: Suche & Bewerbung starten am 30. September 2026. Richte schon jetzt dein Profil ein.

Einen Discovery-Aggregator bauen

Aggregiere öffentliche Inserate organisationsübergreifend mit Cursor-Pagination und ETag-Caching und überwache deinen eigenen API-Verbrauch mit dem Usage-Endpoint.

Dieser Guide zeigt, wie du einen organisationsübergreifenden Aggregator-Feed für Inserate baust — ein Portal oder eine Vergleichsseite, die öffentliche Inserate diskret und effizient abruft — und wie du deinen eigenen Verbrauch mit dem Usage-Endpoint im Blick behältst.

Welches Problem das löst: Du betreibst einen Aggregator und brauchst einen sauberen, paginierten, cachebaren Feed öffentlicher Inserate, der diskret vermarktete Objekte respektiert, plus eine Möglichkeit, deine monatliche Quota zu überwachen.

Allgemein verfügbar. Discovery (Plan 60) und Usage (Plan 61) sind live und in der öffentlichen Referenz dokumentiert — kein Feature-Flag gatet sie. Discovery gehört zum Marktplatz-Launch-Gate: vor dem öffentlichen Marktplatz-Launch liefern Aufrufe von GET /discovery/listings 403 LAUNCH_PENDING. Usage ist nicht gegatet und schon jetzt verfügbar.

Voraussetzungen

  • Für Discovery: ein Publishable Key (pk_live_…) mit Origin-Allowlist — discovery:read ist auf der Publishable-Whitelist — oder ein Secret Key.
  • Für Usage-Monitoring: ein Secret Key (sk_live_…) mit usage:read. Usage ist sk-only (Geschäftszahlen dürfen nicht in einem Browser-Key liegen); ein pk_-Key wird mit 403 INSUFFICIENT_SCOPE abgelehnt.
  • Ein kostenpflichtiger Plan mit API-Zugang. Vor dem öffentlichen Marktplatz-Launch liefern Discovery-Aufrufe 403 LAUNCH_PENDING; Usage ist davon nicht betroffen.

Schritt 1 — Durch den Discovery-Feed blättern

Discovery liefert ein reduziertes DiscoveryListingDto. Diskret vermarktete, inaktive und gesperrte Inserate sind strukturell ausgeschlossen, Geo-Koordinaten werden auf ~110 m gerundet, und Straße/Hausnummer werden nie zurückgegeben.

curl "https://wohno.de/api/v1/discovery/listings?city=Berlin&rooms_min=2&limit=50" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Origin: https://aggregator.example.com"

Antwort (200, cursor-paginiert):

{
  "data": [
    {
      "id": "9f1c2a3b-...",
      "title": "Bright 2-room apartment",
      "city": "Berlin",
      "zip": "10115",
      "rooms": 2,
      "rent_max": 980,
      "property_type": "apartment",
      "lat": 52.53,
      "lng": 13.38
    }
  ],
  "pagination": { "next_cursor": "eyJpZCI6...", "has_more": true, "limit": 50 }
}

Verfügbare Filter: city, zip (1–5 Ziffern), rooms_min, rent_max, property_type. limit ist 1–50. Reiche pagination.next_cursor als nächstes ?cursor= weiter, solange has_more true ist.

Schritt 2 — Mit ETags cachen

Jede Antwort trägt einen ETag. Speichere ihn und sende ihn als If-None-Match zurück, um ein günstiges 304 Not Modified zu erhalten, wenn sich nichts geändert hat — das spart Bandbreite und zählt günstiger gegen deine Quota:

curl "https://wohno.de/api/v1/discovery/listings?city=Berlin&limit=50" \
  -H "X-API-Key: pk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Origin: https://aggregator.example.com" \
  -H 'If-None-Match: W/"l3-1a2b3c4d5e6f7a8b"' \
  -i

Ein 304 kommt ohne Body zurück — verwende deine gecachte Seite wieder.

Schritt 3 — Diskrete Inserate respektieren

Du musst nichts Besonderes tun: Diskret vermarktete, inaktive und gesperrte Inserate erscheinen in diesem Feed nie (durchgesetzt durch die View public_discovery_listings). Versuche nicht, IDs mit anderen Endpoints gegenzuprüfen, um sie wieder offenzulegen.

Schritt 4 — Deinen Verbrauch überwachen

Rufe deine eigene Quota/deinen Verbrauch für den aktuellen Monat mit einem Secret Key ab:

curl "https://wohno.de/api/v1/usage" \
  -H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxx"

Antwort (200):

{
  "data": {
    "plan": "plus",
    "api_requests": {
      "used": 3450,
      "limit": 10000,
      "reset_at": "2026-07-01T00:00:00.000Z"
    },
    "webhook_deliveries": {
      "used": 120,
      "limit": 5000,
      "reset_at": "2026-07-01T00:00:00.000Z"
    },
    "embed_impressions": {
      "used": 8800,
      "limit": 50000,
      "reset_at": "2026-07-01T00:00:00.000Z"
    }
  }
}
  • Frage einen vergangenen Monat mit ?period=YYYY-MM ab (Europe/Berlin). Ein zukünftiger Zeitraum liefert 400.
  • Ein limit von -1 bedeutet unbegrenzt (Premium).
  • Ist der Counter-Store (Redis) kurz nicht verfügbar, erhältst du statt eines Fehlers einen Snapshot-Fallback mit "stale": true — behandle ihn als ungefähr.

Baue eine einfache Warnung: Alarm, wenn used / limit >= 0.8. (Dieselbe Schwelle treibt den Header X-Quota-Status: soft-warning bei jeder API-Antwort.)

Fehlerbehandlung

CodeHTTPWas passiert istLösung
VALIDATION_ERROR400limit > 50, ungültiges zip oder zukünftiges periodQuery-Parameter korrigieren.
INSUFFICIENT_SCOPE403pk_-Key auf /usage, oder fehlender ScopeSecret Key mit usage:read verwenden.
ORIGIN_NOT_ALLOWED403Discovery-pk_-Call von nicht erlaubter DomainDomain unter Einstellungen → API hinzufügen.
LAUNCH_PENDING403Discovery vor dem Marktplatz-Launch aufgerufenAb dem Launch verfügbar; Usage ist nicht betroffen.
RATE_LIMITED429Discovery über 300 req / 300 sPer ETags cachen; Retry-After respektieren.

Siehe die Konventions-Referenz.

Best Practices

  • Aggressiv cachen mit ETags — Discovery ist auf 300 Requests pro 300 Sekunden rate-limitiert.
  • Mit Cursorn paginieren, niemals mit Offsets; Cursor sind stabil bei gleichzeitigen Inserts/Deletes.
  • Achte auf die 80-%-Linie. Verdrahte einen Usage-Alarm, bevor du das Monatslimit erreichst.

Nächste Schritte