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.
