Agency Import API
Zet advertenties in Seeki via API.
Bulk-import van vastgoedadvertenties vanuit uw CRM of vastgoedbeheersysteem. Eén endpoint, status per item, automatische TTL.
API-sleutel aanvragen
Toegang tot de Agency Import API vereist een actief Seeki agentschap-abonnement. Bij elk abonnement hoort één API-sleutel die is gekoppeld aan uw agentschap-account.
Abonneer u via de For Agents-pagina om te beginnen.
Authenticatie
Elke aanvraag moet uw API-sleutel als Bearer-token in de Authorization-header bevatten.
Authorization: Bearer seeki_live_your_key_hereSleutels die beginnen met seeki_live_ zijn productiesleutels. Stagingsleutels beginnen met seeki_test_. Ze zijn niet uitwisselbaar tussen omgevingen.
Uw eerste import
Stuur een POST-aanvraag naar /v1/listings met een JSON-body die een listings-array bevat. Elk element vertegenwoordigt één pand.
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
}
]
}'Een geslaagde batch geeft HTTP 200 terug met accepted- en rejected-arrays:
{
"accepted": [
{ "external_id": "crm-listing-00123", "import_item_id": "uuid-…" }
],
"rejected": []
}Opbouw van verzoek
De top-level body is { listings: [...] }. Verplichte velden per advertentie:
| Veld | Vereist? | Opmerkingen |
|---|---|---|
| external_id | Vereist | Your CRM’s unique ID. Used for idempotent re-imports and deduplication. |
| listing_type | Vereist | SELL of RENT. |
| real_estate_type | Vereist | APARTMENT, HOUSE, LAND, COMMERCIAL of OTHER. |
| price | Vereist | Numeriek. Gebruik het currency-veld voor de ISO 4217-code (standaard EUR). |
| address OR coordinates | Vereist | Geef ofwel een address-object op (street, city, country_code) ofwel coördinaten ({ lat, lng }). Minstens één moet aanwezig zijn. |
| currency | Optioneel | ISO 4217-code, bijv. EUR, CZK, PLN. Standaard EUR. |
| name, description | Optioneel | Titel van de advertentie en vrije tekst voor de beschrijving. |
| floorage, floor, rooms | Optioneel | Oppervlakte in m², verdiepingsnummer en aantal kamers. |
| images | Optioneel | Array van publieke afbeelding-URL's. De importworker haalt en cachet ze. |
| contact | Optioneel | Naam, e-mailadres en telefoonnummer van de makelaar voor het routeren van aanvragen. |
Bekijk het volledige schema met alle optionele velden in de interactieve API-referentie.
Opbouw van respons en fouten
Het /v1/listings-endpoint geeft altijd HTTP 200 OK terug zolang de aanvraag zelf goed is opgebouwd (geldige JSON, juiste auth-header, binnen de groottelimieten). Fouten op individuele advertenties worden gerapporteerd in de rejected-array — niet als HTTP-foutcode.
Elk afgewezen item bevat external_id, error_code en een leesbaar bericht. Fouten op batchniveau (foute auth, te grote payload) geven een non-200 HTTP-status met een top-level error_code.
Foutcodes
Codes op batchniveau geven HTTP-fouten. Codes per item verschijnen in de rejected-array van een 200-respons.
| error_code | HTTP / bereik | Betekenis |
|---|---|---|
| MISSING_AUTHORIZATION | 401 | Er is geen Authorization-header verzonden. |
| INVALID_KEY | 401 | De sleutel is niet gevonden, ingetrokken of verlopen. |
| SUBSCRIPTION_INACTIVE | 403 | The agency’s subscription is not active or past_due. |
| PAYLOAD_TOO_LARGE | 413 | De request-body overschrijdt de limiet van 25 MB. |
| TOO_MANY_ITEMS | 413 | De listings-array bevat meer dan 5.000 items. |
| VALIDATION_FAILED | per item | Eén of meer verplichte velden ontbreken of hebben een ongeldige waarde. Controleer het message-veld voor details. |
| GEOCODE_ADDRESS_NOT_FOUND | per item | Het opgegeven adres kon niet naar coördinaten worden vertaald. Controleer street, city en country_code. |
| GEOCODE_COORDINATES_INVALID | per item | De opgegeven lat/lng vallen buiten het geldige bereik (lat ±90, lng ±180). |
| INFRA_QUEUE_REJECTED | per item | De workflow-wachtrij heeft het item geweigerd, meestal door een tijdelijke overbelasting. Probeer het na korte tijd opnieuw. |
| INFRA_LOST | per item | De workflow is geaccepteerd maar het resultaat is nooit vastgelegd. Gebruik het retry-endpoint. |
| INTERNAL_ERROR | per item | Er is een onverwachte serverfout opgetreden. Opnieuw proberen kan slagen; neem contact op met support als het probleem aanhoudt. |
Idempotentie / her-imports
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 wordt elk import-item gekoppeld aan een Cloudflare Workflow met de ID:
agency-{agency_id}-{external_id}Verloop van advertentie
Elke geïmporteerde advertentie heeft een TTL van 60 dagen vanaf de meest recente geslaagde import. Zodra de TTL verloopt, wordt de advertentie automatisch offline gehaald door een dagelijkse cronjob.
Om een advertentie onbeperkt online te houden, importeert u hem opnieuw (zelfs met identieke data) vóór het einde van het venster van 60 dagen. Een nachtelijke re-sync van uw actieve advertenties implementeren is het aanbevolen patroon.
Status en opnieuw proberen
Gebruik GET /v1/import-items/{import_item_id}/status om de verwerkingsstatus van één item op te vragen. De import_item_id wordt teruggegeven in de accepted-array van de oorspronkelijke POST-respons.
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"
}Als een item in de status INFRA_LOST of INFRA_QUEUE_REJECTED terechtkomt, plaats het dan opnieuw in de wachtrij zonder de hele batch opnieuw in te dienen:
curl -X POST https://ingest.seeki.eu/v1/import-items/{import_item_id}/retry \
-H "Authorization: Bearer seeki_live_your_key_here"Limieten
- Body-grootte: maximaal 25 MB per verzoek.
- Items per verzoek: maximaal 5.000. Splits grotere batches.
- Er geldt momenteel geen QPS-limiet. Zeer grote pieken kunnen automatisch worden afgeknepen; spreid grote synchronisaties over meerdere aanvragen.
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 gaan
Er zijn twee aparte omgevingen. API-sleutels zijn omgevingsspecifiek — een productiesleutel werkt niet op staging en omgekeerd.
| Omgeving | Basis-URL |
|---|---|
| Staging | https://ingest.seeki.store/v1 |
| Productie | https://ingest.seeki.eu/v1 |
Alle endpoints (/listings, /import-items/{id}/status, /import-items/{id}/retry) zijn identiek in beide omgevingen.
Klaar om te integreren?
Open de interactieve referentie om alle velden te verkennen, aanvragen in de browser uit te proberen en het JSON Schema voor uw validator te downloaden.