API de Importação para Agências
Envie anúncios para o Seeki via API.
Importe em massa anúncios imobiliários do seu CRM ou sistema de gestão de imóveis. Um endpoint, estado por item, TTL automático.
Obter uma chave de API
O acesso à API de Importação de Agência requer uma subscrição de agência Seeki ativa. Cada subscrição inclui uma chave de API com âmbito limitado à sua conta de agência.
Subscreva na página Para Agentes para começar.
Autenticação
Cada pedido deve incluir a sua chave de API como token Bearer no cabeçalho Authorization.
Authorization: Bearer seeki_live_your_key_hereAs chaves que começam por seeki_live_ são chaves de produção. As chaves de staging começam por seeki_test_. Não são intercambiáveis entre ambientes.
A sua primeira importação
Envie um pedido POST para /v1/listings com um corpo JSON que contenha um array listings. Cada elemento representa um imóvel.
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
}
]
}'Um lote bem-sucedido devolve HTTP 200 com arrays accepted e rejected:
{
"accepted": [
{ "external_id": "crm-listing-00123", "import_item_id": "uuid-…" }
],
"rejected": []
}Estrutura do pedido
O corpo de nível superior é { listings: [...] }. Campos obrigatórios por anúncio:
| Campo | Obrigatório? | Notas |
|---|---|---|
| external_id | Obrigatório | Your CRM’s unique ID. Used for idempotent re-imports and deduplication. |
| listing_type | Obrigatório | SELL ou RENT. |
| real_estate_type | Obrigatório | APARTMENT, HOUSE, LAND, COMMERCIAL ou OTHER. |
| price | Obrigatório | Numérico. Utilize o campo currency para o código ISO 4217 (predefinição: EUR). |
| address OR coordinates | Obrigatório | Forneça um objeto address (street, city, country_code) ou coordenadas ({ lat, lng }). Pelo menos um deve estar presente. |
| currency | Opcional | Código ISO 4217, por exemplo, EUR, CZK, PLN. Predefinição: EUR. |
| name, description | Opcional | Título do anúncio e descrição em texto livre. |
| floorage, floor, rooms | Opcional | Tamanho do imóvel em m², número do piso e número de divisões. |
| images | Opcional | Array de URLs de imagens públicas. O worker de importação obtém-nas e coloca-as em cache. |
| contact | Opcional | Nome, e-mail e telefone do agente para encaminhamento de consultas. |
Consulte o esquema completo com todos os campos opcionais em referência interativa da API.
Estrutura de resposta e erros
O endpoint /v1/listings devolve sempre HTTP 200 OK desde que o próprio pedido esteja bem formado (JSON válido, cabeçalho de autenticação correto, dentro dos limites de tamanho). As falhas de anúncios individuais são reportadas dentro do array rejected — não como códigos de erro HTTP.
Cada item rejeitado inclui external_id, error_code e uma mensagem legível por humanos. Os erros ao nível do lote (autenticação inválida, payload demasiado grande) devolvem um estado HTTP não-200 com um error_code de nível superior.
Códigos de erro
Os códigos ao nível do lote devolvem erros HTTP. Os códigos por item aparecem no array rejected de uma resposta 200.
| error_code | HTTP / âmbito | Significado |
|---|---|---|
| MISSING_AUTHORIZATION | 401 | Não foi enviado nenhum cabeçalho Authorization. |
| INVALID_KEY | 401 | A chave não foi encontrada, foi revogada ou expirou. |
| SUBSCRIPTION_INACTIVE | 403 | The agency’s subscription is not active or past_due. |
| PAYLOAD_TOO_LARGE | 413 | O corpo do pedido excede o limite de 25 MB. |
| TOO_MANY_ITEMS | 413 | O array listings contém mais de 5.000 itens. |
| VALIDATION_FAILED | por item | Um ou mais campos obrigatórios estão em falta ou contêm um valor inválido. Verifique o campo message para mais detalhes. |
| GEOCODE_ADDRESS_NOT_FOUND | por item | O endereço fornecido não pôde ser convertido em coordenadas. Verifique street, city e country_code. |
| GEOCODE_COORDINATES_INVALID | por item | As coordenadas lat/lng fornecidas estão fora dos intervalos válidos (lat ±90, lng ±180). |
| INFRA_QUEUE_REJECTED | por item | A fila do workflow rejeitou o item, normalmente devido a uma sobrecarga transitória. Tente novamente após uma breve espera. |
| INFRA_LOST | por item | O workflow foi aceite, mas o seu resultado nunca foi registado. Utilize o endpoint de repetição. |
| INTERNAL_ERROR | por item | Ocorreu um erro inesperado no servidor. Repetir poderá ser bem-sucedido; contacte o suporte se persistir. |
Idempotência / reimportações
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 item de importação é mapeado para um Cloudflare Workflow com o ID:
agency-{agency_id}-{external_id}Expiração de anúncios
Cada anúncio importado tem um TTL de 60 dias a partir da última importação bem-sucedida. Quando o TTL expira, o anúncio é automaticamente despublicado por um cron job diário.
Para manter um anúncio ativo indefinidamente, reimporte-o (mesmo com dados idênticos) antes do fim da janela de 60 dias. Implementar uma re-sincronização noturna dos seus anúncios ativos é o padrão recomendado.
Estado + nova tentativa
Utilize GET /v1/import-items/{import_item_id}/status para consultar o estado de processamento de um único item. O import_item_id é devolvido no array accepted da resposta POST original.
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"
}Se um item terminar num estado INFRA_LOST ou INFRA_QUEUE_REJECTED, recoloque-o em fila sem reenviar o lote completo:
curl -X POST https://ingest.seeki.eu/v1/import-items/{import_item_id}/retry \
-H "Authorization: Bearer seeki_live_your_key_here"Limites
- Tamanho do corpo: 25 MB máximo por pedido.
- Itens por pedido: 5000 máximo. Divida lotes maiores.
- Atualmente não é aplicado qualquer limite de QPS. Picos muito grandes podem ser limitados automaticamente; distribua sincronizações de grande volume por vários pedidos.
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.
Entrar em produção
Existem dois ambientes separados. As chaves de API têm âmbito por ambiente — uma chave de produção não funcionará em staging, e vice-versa.
| Ambiente | URL base |
|---|---|
| Staging | https://ingest.seeki.store/v1 |
| Produção | https://ingest.seeki.eu/v1 |
Todos os endpoints (/listings, /import-items/{id}/status, /import-items/{id}/retry) são idênticos em ambos os ambientes.
Pronto para integrar?
Abra a referência interativa para explorar todos os campos, experimentar pedidos no browser e descarregar o JSON Schema para o seu validador.