Skip to main content
Seeki.eu

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.

Een UI voor sleutelbeheer (sleutels bekijken, roteren, intrekken) komt in een toekomstige dashboardupdate. Voorlopig wordt uw API-sleutel per e-mail verstuurd zodra uw abonnement is geactiveerd. Neem contact op met info@seeki.eu als u een nieuwe sleutel nodig heeft.

Authenticatie

Elke aanvraag moet uw API-sleutel als Bearer-token in de Authorization-header bevatten.

HTTP header
Authorization: Bearer seeki_live_your_key_here

Sleutels 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
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:

200 OK
{
  "accepted": [
    { "external_id": "crm-listing-00123", "import_item_id": "uuid-…" }
  ],
  "rejected": []
}

Opbouw van verzoek

De top-level body is { listings: [...] }. Verplichte velden per advertentie:

VeldVereist?Opmerkingen
external_idVereistYour CRM’s unique ID. Used for idempotent re-imports and deduplication.
listing_typeVereistSELL of RENT.
real_estate_typeVereistAPARTMENT, HOUSE, LAND, COMMERCIAL of OTHER.
priceVereistNumeriek. Gebruik het currency-veld voor de ISO 4217-code (standaard EUR).
address OR coordinatesVereistGeef ofwel een address-object op (street, city, country_code) ofwel coördinaten ({ lat, lng }). Minstens één moet aanwezig zijn.
currencyOptioneelISO 4217-code, bijv. EUR, CZK, PLN. Standaard EUR.
name, descriptionOptioneelTitel van de advertentie en vrije tekst voor de beschrijving.
floorage, floor, roomsOptioneelOppervlakte in m², verdiepingsnummer en aantal kamers.
imagesOptioneelArray van publieke afbeelding-URL's. De importworker haalt en cachet ze.
contactOptioneelNaam, 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_codeHTTP / bereikBetekenis
MISSING_AUTHORIZATION401Er is geen Authorization-header verzonden.
INVALID_KEY401De sleutel is niet gevonden, ingetrokken of verlopen.
SUBSCRIPTION_INACTIVE403The agency’s subscription is not active or past_due.
PAYLOAD_TOO_LARGE413De request-body overschrijdt de limiet van 25 MB.
TOO_MANY_ITEMS413De listings-array bevat meer dan 5.000 items.
VALIDATION_FAILEDper itemEén of meer verplichte velden ontbreken of hebben een ongeldige waarde. Controleer het message-veld voor details.
GEOCODE_ADDRESS_NOT_FOUNDper itemHet opgegeven adres kon niet naar coördinaten worden vertaald. Controleer street, city en country_code.
GEOCODE_COORDINATES_INVALIDper itemDe opgegeven lat/lng vallen buiten het geldige bereik (lat ±90, lng ±180).
INFRA_QUEUE_REJECTEDper itemDe workflow-wachtrij heeft het item geweigerd, meestal door een tijdelijke overbelasting. Probeer het na korte tijd opnieuw.
INFRA_LOSTper itemDe workflow is geaccepteerd maar het resultaat is nooit vastgelegd. Gebruik het retry-endpoint.
INTERNAL_ERRORper itemEr 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:

Workflow ID pattern
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.

GET /import-items/{id}/status
curl https://ingest.seeki.eu/v1/import-items/{import_item_id}/status \
  -H "Authorization: Bearer seeki_live_your_key_here"
Response
{
  "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:

POST /import-items/{id}/retry
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 containing index.xml at 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’s media.images array before publication. Hosted images are removed when the listing expires (60-day default TTL); re-imports refresh them.
curl — XML
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.xml
curl — zip
curl -X POST https://ingest.seeki.eu/v1/openimmo \
  -H "Authorization: Bearer seeki_live_your_key_here" \
  -H "Content-Type: application/zip" \
  --data-binary @export.zip

Target 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
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.xml

Target 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.

OmgevingBasis-URL
Staginghttps://ingest.seeki.store/v1
Productiehttps://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.