Skip to main content
Seeki.eu

API de Importación para Agencias

Envíe anuncios a Seeki mediante API.

Importe en bloque anuncios inmobiliarios desde su CRM o sistema de gestión de propiedades. Un endpoint, estado por elemento, TTL automático.

Obtener una clave de API

El acceso a la API de importación de agencias requiere una suscripción de agencia Seeki activa. Cada suscripción incluye una clave API asociada a la cuenta de su agencia.

Suscríbase en la página Para Agentes para empezar.

La interfaz de gestión de claves (ver, rotar, revocar claves) llegará en una próxima actualización del panel. Por ahora, su clave API se envía por correo electrónico al activar su suscripción. Contacte con info@seeki.eu si necesita una nueva clave.

Autenticación

Cada solicitud debe incluir su clave API como token Bearer en la cabecera Authorization.

HTTP header
Authorization: Bearer seeki_live_your_key_here

Las claves que comienzan por seeki_live_ son claves de producción. Las claves de staging comienzan por seeki_test_. No son intercambiables entre entornos.

Su primera importación

Envíe una solicitud POST a /v1/listings con un cuerpo JSON que contenga un array listings. Cada elemento representa una propiedad.

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
      }
    ]
  }'

Un lote correcto devuelve HTTP 200 con los arrays accepted y rejected:

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

Estructura de la petición

El cuerpo de nivel superior es { listings: [...] }. Campos obligatorios por anuncio:

Campo¿Obligatorio?Notas
external_idObligatorioYour CRM’s unique ID. Used for idempotent re-imports and deduplication.
listing_typeObligatorioSELL o RENT.
real_estate_typeObligatorioAPARTMENT, HOUSE, LAND, COMMERCIAL u OTHER.
priceObligatorioNumérico. Utilice el campo currency para el código ISO 4217 (por defecto EUR).
address OR coordinatesObligatorioProporcione un objeto address (street, city, country_code) o coordinates ({ lat, lng }). Debe estar presente al menos uno.
currencyOpcionalCódigo ISO 4217, p. ej. EUR, CZK, PLN. Por defecto EUR.
name, descriptionOpcionalTítulo del anuncio y descripción de texto libre.
floorage, floor, roomsOpcionalTamaño de la propiedad en m², número de planta y número de habitaciones.
imagesOpcionalArray de URLs de imágenes públicas. El worker de importación las descarga y almacena en caché.
contactOpcionalNombre, correo electrónico y teléfono del agente para el enrutamiento de consultas.

Consulte el esquema completo con todos los campos opcionales en la referencia interactiva de la API.

Estructura de la respuesta y errores

El endpoint /v1/listings siempre devuelve HTTP 200 OK siempre que la propia solicitud esté bien formada (JSON válido, cabecera de autenticación correcta, dentro de los límites de tamaño). Los fallos de anuncios individuales se reportan dentro del array rejected — no como códigos de error HTTP.

Cada elemento rechazado incluye external_id, error_code y un mensaje legible. Los errores a nivel de lote (autenticación incorrecta, payload demasiado grande) devuelven un estado HTTP distinto de 200 con un error_code de nivel superior.

Códigos de error

Los códigos de nivel de lote devuelven errores HTTP. Los códigos por elemento aparecen en el array rejected de una respuesta 200.

error_codeHTTP / ámbitoSignificado
MISSING_AUTHORIZATION401No se ha enviado la cabecera Authorization.
INVALID_KEY401La clave no se ha encontrado, ha sido revocada o ha caducado.
SUBSCRIPTION_INACTIVE403The agency’s subscription is not active or past_due.
PAYLOAD_TOO_LARGE413El cuerpo de la solicitud excede el límite de 25 MB.
TOO_MANY_ITEMS413El array listings contiene más de 5.000 elementos.
VALIDATION_FAILEDpor elementoFaltan uno o varios campos obligatorios o tienen un valor no válido. Consulte el campo message para más detalles.
GEOCODE_ADDRESS_NOT_FOUNDpor elementoLa dirección proporcionada no se ha podido resolver a coordenadas. Verifique street, city y country_code.
GEOCODE_COORDINATES_INVALIDpor elementoLos valores lat/lng proporcionados están fuera de los rangos válidos (lat ±90, lng ±180).
INFRA_QUEUE_REJECTEDpor elementoLa cola del workflow ha rechazado el elemento, normalmente por una sobrecarga transitoria. Reintente tras una breve espera.
INFRA_LOSTpor elementoEl workflow se aceptó, pero su resultado no se ha registrado. Utilice el endpoint de reintento.
INTERNAL_ERRORpor elementoSe ha producido un error inesperado en el servidor. Reintentar puede funcionar; contacte con soporte si persiste.

Idempotencia / reimportaciones

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.

Internamente, cada elemento de importación se asigna a un Cloudflare Workflow con el ID:

Workflow ID pattern
agency-{agency_id}-{external_id}

Caducidad de anuncios

Cada anuncio importado tiene un TTL de 60 días desde la importación correcta más reciente. Una vez que el TTL caduca, el anuncio se despublica automáticamente mediante un cron diario.

Para mantener un anuncio publicado indefinidamente, vuelva a importarlo (incluso con datos idénticos) antes de que se cumpla la ventana de 60 días. Se recomienda implementar una resincronización nocturna de sus anuncios activos.

Estado y reintento

Utilice GET /v1/import-items/{import_item_id}/status para consultar el estado de procesamiento de un único elemento. El import_item_id se devuelve en el array accepted de la respuesta POST original.

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"
}

Si un elemento termina en estado INFRA_LOST o INFRA_QUEUE_REJECTED, vuelva a encolarlo sin reenviar el lote completo:

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"

Límites

  • Tamaño del cuerpo: 25 MB como máximo por petición.
  • Elementos por petición: 5000 como máximo. Divida los lotes más grandes.
  • Hoy no se aplica ningún límite de QPS. Las ráfagas muy grandes pueden ser limitadas automáticamente; reparta las sincronizaciones de gran volumen entre varias solicitudes.

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.

Pasar a producción

Existen dos entornos separados. Las claves API están limitadas al entorno — una clave de producción no funcionará en staging, y viceversa.

EntornoURL base
Staginghttps://ingest.seeki.store/v1
Producciónhttps://ingest.seeki.eu/v1

Todos los endpoints (/listings, /import-items/{id}/status, /import-items/{id}/retry) son idénticos en ambos entornos.

¿Listo para integrar?

Abra la referencia interactiva para explorar todos los campos, probar solicitudes en el navegador y descargar el JSON Schema para su validador.