Agency Import API
Inserate per API in Seeki übertragen.
Importieren Sie Immobilien-Inserate aus Ihrem CRM oder Ihrer Immobilienverwaltung in großen Mengen. Ein Endpunkt, Status pro Eintrag, automatische TTL.
API-Schlüssel erhalten
Der Zugriff auf die Agency Import API erfordert ein aktives Seeki-Agentur-Abonnement. Jedes Abonnement enthält einen API-Schlüssel, der auf Ihr Agenturkonto beschränkt ist.
Abonnieren Sie auf der Seite Für Agenturen, um zu starten.
Authentifizierung
Jede Anfrage muss Ihren API-Schlüssel als Bearer-Token im Authorization-Header enthalten.
Authorization: Bearer seeki_live_your_key_hereSchlüssel, die mit seeki_live_ beginnen, sind Produktivschlüssel. Staging-Schlüssel beginnen mit seeki_test_. Sie sind zwischen den Umgebungen nicht austauschbar.
Ihr erster Import
Senden Sie eine POST-Anfrage an /v1/listings mit einem JSON-Body, der ein listings-Array enthält. Jedes Element entspricht einer Immobilie.
curl -X POST https://ingest.seeki.eu/v1/listings \
-H "Authorization: Bearer seeki_live_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"listings": [
{
"external_id": "crm-listing-00123",
"listing_type": "SELL",
"real_estate_type": "APARTMENT",
"price": 320000,
"currency": "EUR",
"address": {
"street": "Wenceslas Square 1",
"city": "Prague",
"country_code": "CZ",
"postal_code": "11000"
},
"name": "Sunny 2-bedroom apartment, Wenceslas Square",
"floorage": 65
}
]
}'Ein erfolgreicher Batch liefert HTTP 200 mit den Arrays accepted und rejected zurück:
{
"accepted": [
{ "external_id": "crm-listing-00123", "import_item_id": "uuid-…" }
],
"rejected": []
}Anfrage-Struktur
Der Top-Level-Body lautet { listings: [...] }. Pflichtfelder pro Inserat:
| Feld | Erforderlich? | Hinweise |
|---|---|---|
| external_id | Erforderlich | Your CRM’s unique ID. Used for idempotent re-imports and deduplication. |
| listing_type | Erforderlich | SELL oder RENT. |
| real_estate_type | Erforderlich | APARTMENT, HOUSE, LAND, COMMERCIAL oder OTHER. |
| price | Erforderlich | Numerisch. Verwenden Sie das Feld currency für den ISO-4217-Code (Standard: EUR). |
| address OR coordinates | Erforderlich | Geben Sie entweder ein address-Objekt (street, city, country_code) oder Koordinaten ({ lat, lng }) an. Mindestens eines davon muss vorhanden sein. |
| currency | Optional | ISO-4217-Code, z. B. EUR, CZK, PLN. Standard: EUR. |
| name, description | Optional | Inserattitel und Freitext-Beschreibung. |
| floorage, floor, rooms | Optional | Wohnfläche in m², Etage und Anzahl der Zimmer. |
| images | Optional | Array öffentlicher Bild-URLs. Der Import-Worker lädt sie herunter und cached sie. |
| contact | Optional | Name, E-Mail und Telefonnummer des Maklers für die Anfrageweiterleitung. |
Das vollständige Schema mit allen optionalen Feldern finden Sie in der interaktive API-Referenz.
Antwort-Struktur & Fehler
Der Endpunkt /v1/listings liefert immer HTTP 200 OK zurück, solange die Anfrage selbst korrekt ist (gültiges JSON, korrekter Auth-Header, innerhalb der Größenbeschränkungen). Fehler einzelner Inserate werden im Array rejected gemeldet — nicht als HTTP-Fehlercodes.
Jeder abgelehnte Eintrag enthält external_id, error_code und eine lesbare Nachricht. Batch-Level-Fehler (fehlerhafte Authentifizierung, zu großer Payload) liefern einen HTTP-Status ungleich 200 mit einem error_code auf oberster Ebene.
Fehlercodes
Batch-Level-Codes liefern HTTP-Fehler. Codes pro Eintrag erscheinen im Array rejected einer 200-Antwort.
| error_code | HTTP / Geltungsbereich | Bedeutung |
|---|---|---|
| MISSING_AUTHORIZATION | 401 | Es wurde kein Authorization-Header gesendet. |
| INVALID_KEY | 401 | Der Schlüssel wurde nicht gefunden, wurde widerrufen oder ist abgelaufen. |
| SUBSCRIPTION_INACTIVE | 403 | The agency’s subscription is not active or past_due. |
| PAYLOAD_TOO_LARGE | 413 | Der Request-Body überschreitet das Limit von 25 MB. |
| TOO_MANY_ITEMS | 413 | Das listings-Array enthält mehr als 5.000 Einträge. |
| VALIDATION_FAILED | pro Eintrag | Ein oder mehrere Pflichtfelder fehlen oder enthalten einen ungültigen Wert. Details finden Sie im message-Feld. |
| GEOCODE_ADDRESS_NOT_FOUND | pro Eintrag | Die angegebene Adresse konnte nicht in Koordinaten aufgelöst werden. Prüfen Sie street, city und country_code. |
| GEOCODE_COORDINATES_INVALID | pro Eintrag | Die angegebenen lat/lng-Werte liegen außerhalb des gültigen Bereichs (lat ±90, lng ±180). |
| INFRA_QUEUE_REJECTED | pro Eintrag | Die Workflow-Queue hat den Eintrag abgelehnt, meist aufgrund einer kurzfristigen Überlastung. Versuchen Sie es nach kurzer Verzögerung erneut. |
| INFRA_LOST | pro Eintrag | Der Workflow wurde angenommen, aber sein Ergebnis wurde nie erfasst. Verwenden Sie den Retry-Endpunkt. |
| INTERNAL_ERROR | pro Eintrag | Ein unerwarteter Serverfehler ist aufgetreten. Ein erneuter Versuch kann erfolgreich sein; kontaktieren Sie den Support, falls der Fehler bestehen bleibt. |
Idempotenz / erneute Importe
Re-posting a listing with the same external_id updates the existing record — it does not create a duplicate. The listing’s TTL is refreshed on every successful import.
Intern wird jeder Import-Eintrag auf einen Cloudflare-Workflow mit folgender ID abgebildet:
agency-{agency_id}-{external_id}Ablauf von Inseraten
Jedes importierte Inserat hat eine TTL von 60 Tagen ab dem letzten erfolgreichen Import. Nach Ablauf der TTL wird das Inserat von einem täglichen Cron-Job automatisch depubliziert.
Um ein Inserat dauerhaft online zu halten, importieren Sie es vor Ablauf des 60-Tage-Fensters erneut (auch mit identischen Daten). Eine nächtliche Re-Synchronisation Ihrer aktiven Inserate ist das empfohlene Vorgehen.
Status + Wiederholung
Verwenden Sie GET /v1/import-items/{import_item_id}/status, um den Verarbeitungsstatus eines einzelnen Eintrags abzufragen. Die import_item_id wird im Array accepted der ursprünglichen POST-Antwort zurückgegeben.
curl https://ingest.seeki.eu/v1/import-items/{import_item_id}/status \
-H "Authorization: Bearer seeki_live_your_key_here"{
"import_item_id": "uuid-…",
"external_id": "crm-listing-00123",
"status": "completed",
"listing_id": "uuid-listing"
}Falls ein Eintrag im Status INFRA_LOST oder INFRA_QUEUE_REJECTED endet, stellen Sie ihn erneut in die Queue, ohne den gesamten Batch erneut zu senden:
curl -X POST https://ingest.seeki.eu/v1/import-items/{import_item_id}/retry \
-H "Authorization: Bearer seeki_live_your_key_here"Limits
- Body-Größe: maximal 25 MB pro Anfrage.
- Einträge pro Anfrage: maximal 5.000. Teilen Sie größere Batches auf.
- Aktuell wird kein QPS-Limit erzwungen. Sehr große Bursts können automatisch gedrosselt werden; verteilen Sie hochvolumige Synchronisationen über mehrere Anfragen.
OpenImmo XML / zip intake
OpenImmo is the de-facto real-estate exchange format for the DACH market (Germany, Austria, Switzerland) and is produced by every major CRM in those countries — FlowFact, onOffice, ImmoMaster, edomi, and others. If your CRM already exports OpenImmo, you can POST it directly without remapping fields into Seeki-JSON.
Two delivery flavours are accepted on the same endpoint, distinguished byContent-Type:
application/xml— raw OpenImmo XML, images referenced by absolute URL.application/zip— bundle containingindex.xmlat the root plus the JPGs referenced from<anhang gruppe="INTERN">nodes. We extract every referenced image, host it on Supabase Storage, and rewrite the listing’smedia.imagesarray before publication. Hosted images are removed when the listing expires (60-day default TTL); re-imports refresh them.
curl -X POST https://ingest.seeki.eu/v1/openimmo \
-H "Authorization: Bearer seeki_live_your_key_here" \
-H "Content-Type: application/xml" \
--data-binary @export.xmlcurl -X POST https://ingest.seeki.eu/v1/openimmo \
-H "Authorization: Bearer seeki_live_your_key_here" \
-H "Content-Type: application/zip" \
--data-binary @export.zipTarget spec version: OpenImmo 1.2.x. Body cap: 200 MB. Bigger feeds get a 413 with a Suggested-Chunk-Size: 500 header — split index.xml into multiple POSTs of ≤500 listings each. Spec reference: openimmo.de.
The same per-item error codes from the JSON intake apply — only the request body format differs. Each <immobilie> that fails Zod validation appears in the response’s rejected array with a VALIDATION_FAILED code and the offending field path.
Idealista XML-ML intake
Idealista’s XML-ML (xmlGenerator) is the standard feed format on the Iberian peninsula — used by Idealista itself and the CRMs that export to it for the Spanish (ES) and Portuguese (PT) markets. Country is inferred per record from the <provincia> field; locale follows country.
Images are referenced by URL (<imagenes><imagen url="…"/>), so there is no zip flavour for this format — application/xml only. Listings without an accessible image URL are still accepted; only fields that fail Zod validation are rejected.
curl -X POST https://ingest.seeki.eu/v1/idealista \
-H "Authorization: Bearer seeki_live_your_key_here" \
-H "Content-Type: application/xml" \
--data-binary @feed.xmlTarget spec: Idealista xmlGenerator-1.X. The XML prolog encoding declaration is honoured — feeds shipped as windows-1252 are decoded correctly without manual conversion. Body cap: 200 MB. Spec reference: search Idealista’s help centre for “XML feed schema”.
Same per-item error codes as the JSON intake — see the table above.
Live gehen
Es gibt zwei getrennte Umgebungen. API-Schlüssel sind umgebungsspezifisch — ein Produktivschlüssel funktioniert nicht in Staging und umgekehrt.
| Umgebung | Basis-URL |
|---|---|
| Staging | https://ingest.seeki.store/v1 |
| Produktion | https://ingest.seeki.eu/v1 |
Alle Endpunkte (/listings, /import-items/{id}/status, /import-items/{id}/retry) sind in beiden Umgebungen identisch.
Bereit zu integrieren?
Öffnen Sie die interaktive Referenz, um alle Felder zu erkunden, Anfragen direkt im Browser zu testen und das JSON Schema für Ihren Validator herunterzuladen.