Zum Inhalt springen

Open Beta – hilf uns beim Testen! Alle Inserate sind nur Beispiele.

Inserate aus deinem CRM synchronisieren

Pushe und upserte Inserate aus deinem eigenen CRM/ERP nach WOHNO — mit external_ref, Idempotency-Keys und Signed-URL-Bild-Uploads.

Dieser Guide zeigt, wie du WOHNO mit den Inseraten synchron hältst, die du bereits in deinem eigenen CRM oder ERP verwaltest — Inserate von einem Server erstellen, aktualisieren und entduplizieren, Bilder hochladen und per Webhooks auf Änderungen reagieren.

Welches Problem das löst: Deine Single Source of Truth ist dein CRM. Du möchtest, dass jede Inserats-Änderung dort automatisch und idempotent nach WOHNO fließt, ohne bei Retries Duplikate zu erzeugen.

Beta / dark-shipped. Die Write-Oberfläche für Inserate (Plan 58) ist hinter dem Feature-Flag LISTINGS_WRITE_API_ENABLED gegated. Solange das Flag aus ist, liefern diese Endpoints 404. Bitte deinen WOHNO-Ansprechpartner, es für deine Organisation zu aktivieren. Die Write-Operationen sind x-internal und noch nicht in der öffentlichen Referenz sichtbar.

Voraussetzungen

  • Ein Secret Key (sk_live_…) — diese Endpoints sind immer sk-only. Publishable Keys scheitern mit 403 INSUFFICIENT_SCOPE.
  • Scope listings:write (impliziert listings:read); listings:delete, falls du auch Inserate entfernst.
  • LISTINGS_WRITE_API_ENABLED für deine Organisation aktiviert.

Halte deinen Secret Key auf dem Server. Liefere ihn niemals in einem Browser-Bundle aus.

Schritt 1 — Inserat per eigener ID upserten

Sende den stabilen Identifier deines CRM als external_ref. Das erste POST erstellt das Inserat; spätere POSTs mit der gleichen external_ref aktualisieren das bestehende (org-scoped Upsert), sodass du nie Duplikate erzeugst.

curl -X POST https://wohno.de/api/v1/listings \
  -H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 7c9e6a3d-1f2b-4c8a-9d10-abc123def456" \
  -d '{
    "external_ref": "CRM-48217",
    "title": "Bright 2-room apartment",
    "street": "Beispielstraße",
    "house_number": "12",
    "zip_code": "10115",
    "city": "Berlin",
    "property_type": "apartment",
    "living_area": 58,
    "rooms": 2,
    "rent_cold": 980,
    "status": "draft"
  }'

Antworten:

  • 201 Created mit { "data": ListingPublicDto } bei einem frischen Create.
  • 200 OK mit { "data": ListingPublicDto }, wenn die external_ref bereits existiert (Update/Upsert).

status ist draft (Standard) oder active; nur draft → active veröffentlicht das Inserat. Bei jedem Write läuft dieselbe Moderations- und Geocoding-Pipeline wie im Dashboard-Wizard.

Optional — Inserat einem bestimmten Owner zuweisen

Standardmäßig gehört ein über die API erstelltes Inserat dem Nutzer, der den API-Key erstellt hat. Um es stattdessen einem bestimmten Team-Mitglied zuzuweisen — z. B. dem Makler, der es in deinem CRM betreut — gib dessen E-Mail als owner_email an:

curl -X POST https://wohno.de/api/v1/listings \
  -H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "external_ref": "CRM-48217",
    "title": "Bright 2-room apartment",
    "street": "Beispielstraße",
    "zip_code": "10115",
    "city": "Berlin",
    "property_type": "apartment",
    "living_area": 58,
    "rooms": 2,
    "rent_cold": 980,
    "owner_email": "makler@example.com"
  }'
  • Die E-Mail muss zu einem Mitglied derselben Organisation gehören (Rolle owner, admin oder member).
  • Eine unbekannte Adresse oder ein Nicht-Mitglied wird mit 403 FORBIDDEN abgelehnt — bewusst mit derselben Meldung, damit der Endpoint nicht dazu genutzt werden kann, zu prüfen, welche E-Mails ein WOHNO-Konto haben.
  • owner_email wirkt nur beim Create. Bei einem external_ref-Upsert auf ein bestehendes Inserat wird es ignoriert — der Owner wird nie umgehängt.
  • Weglassen → Fallback auf den Ersteller des API-Keys.

Tipp: Richte deinen Secret Key auf einen dedizierten technischen Nutzer aus. Der Inserats-Owner ist ein echtes Konto; wird ein persönliches Owner-Konto später entfernt, geht der Besitz nicht automatisch über. Ein owner_email pro Datensatz hält jedes Inserat am richtigen Makler — unabhängig davon, welcher Key es gepusht hat.

Schritt 2 — Retries mit Idempotency-Key absichern

Übergib eine clientseitig generierte UUID v4 im Idempotency-Key-Header (wie oben) und verwende sie bei Netzwerk-Retries unverändert wieder.

  • Der Key ist 24 Stunden gültig. Ein wiederholter Request mit demselben Key liefert die gleiche Antwort, ohne die Aktion erneut auszuführen.
  • Denselben Key mit einem anderen Body zu senden, liefert 409 IDEMPOTENCY_KEY_REUSED — ein Key ist an genau einen Request-Body gebunden.

Generiere einen Key pro logischer CRM-Sync-Operation.

Schritt 3 — Lifecycle aktualisieren oder umschalten

Nutze PATCH für partielle Updates. external_ref kann per PATCH nicht geändert werden. Die Lifecycle-Status rented und archived sind hier erreichbar:

curl -X PATCH https://wohno.de/api/v1/listings/9f1c2a3b-1111-2222-3333-444455556666 \
  -H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "rent_cold": 950, "status": "active" }'

Re-Geocoding läuft nur, wenn du die Adresse änderst. Ein draft → active-Übergang emittiert listing.published.

Schritt 4 — Bilder per Signed-URL hochladen

Bild-Uploads nutzen einen zweistufigen Signed-URL-Flow — keine große Binärdatei läuft durch die API. Fordere zuerst eine Upload-URL an:

curl -X POST https://wohno.de/api/v1/listings/9f1c2a3b-1111-2222-3333-444455556666/images \
  -H "X-API-Key: sk_live_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "filename": "living-room.jpg", "content_type": "image/jpeg", "size": 842133, "sort_order": 0 }'

Antwort (201):

{
  "data": {
    "image_id": "img_5f4e3d2c",
    "upload_url": "https://storage.wohno.de/...signed...",
    "upload_token": "...",
    "expires_at": "2026-06-04T12:10:00.000Z"
  }
}

Lade dann die Binärdatei vor expires_at per PUT direkt an upload_url. Erlaubte Typen sind image/jpeg, image/png, image/webp; max. 5 MB. Entferne ein Bild mit DELETE /api/v1/listings/{id}/images?image_id=img_5f4e3d2c.

Schritt 5 — Per Webhooks synchron bleiben

Abonniere listing.*-Events, damit dein CRM von Moderations-Ergebnissen und Publish-Status-Änderungen erfährt, die WOHNO pusht. Das vollständige Setup beschreibt Auf Events mit Webhooks reagieren; die relevanten Event-Typen für diesen Flow sind listing.created, listing.published, listing.updated, listing.deleted, listing.moderated und listing.image.uploaded.

Fehlerbehandlung

CodeHTTPWas passiert istLösung
INSUFFICIENT_SCOPE403pk_-Key genutzt oder listings:write fehltSecret Key mit Write-Scope verwenden.
IDEMPOTENCY_KEY_REUSED409Gleicher Key, anderer BodyFrischen Key pro abweichendem Payload verwenden.
VALIDATION_ERROR400Fehlende/ungültige Felder (siehe details.fields)Body korrigieren; die Antwort listet die fehlerhaften Felder.
FORBIDDEN403Plan-/Quota-Limit (z. B. Free-Inserats-Cap)Plan upgraden oder Volumen reduzieren.
FORBIDDEN403owner_email ist kein Mitglied deiner OrgE-Mail eines bestehenden Org-Mitglieds nutzen (owner/admin/member).
NOT_FOUND404Flag aus, oder Inserat gehört zu anderer OrgFlag und Inserats-Besitz prüfen.

Idempotenz- und Fehler-Details findest du in der Konventions-Referenz.

Best Practices

  • Eine external_ref pro CRM-Datensatz. Genau das macht die Synchronisation über vollständige Re-Importe hinweg idempotent.
  • Sorgfältig batchen. Das Rate-Limit liegt bei 1000 Requests/Stunde pro Key; respektiere Retry-After bei 429.
  • Bilder hochladen, nachdem das Inserat existiert, dann status auf active umstellen.

Nächste Schritte