Seu site com chave publicável
Liste imóveis com filtros, receba formulários e visitas, agende compromissos e monte um buscador guiado.
Crie uma chave publicável
No ByDomu, Configurações › API Keys › Nova chave › Publicável. Serve em qualquer plano pago, sem solicitação, e só alcança o público: portal:read, leads:write, booking:write, finder:write, events:write.
Pode ficar no navegador (a API responde com CORS aberto), mas todos os seus visitantes dividem o limite: 300 requisições e 60 escritas por minuto. Para o inventário, peça no seu servidor e guarde em cache; deixe no navegador só os formulários. Uma chave secreta no navegador recebe 403 SECRET_KEY_IN_BROWSER.
GET /propertiesGET /properties/{id}GET /properties/featuredGET /filtersGET /agentsGET /portalPOST /leadsPOST /leads/schedulePOST /booking/{slug}POST /finderPOST /eventsListe imóveis com filtros
Só saem os imóveis ativos e publicados no portal, nunca as notas internas nem os campos personalizados. Se a localização for aproximada, address e zipCode chegam null e as coordenadas arredondadas.
// Clave publicable: puede ir en el navegador. Mejor aún, en tu servidor con caché.
const API = "https://api.bydomu.com/v1";
const KEY = "domu_pk_live_XXXXXXXX";
const params = new URLSearchParams({
transactionType: "RENT", // SALE | RENT | SALE_OR_RENT
type: "APARTMENT",
city: "Medellín", // coincidencia parcial
priceMax: "4000000",
bedroomsMin: "2",
hasPetFriendly: "1", // los has* se mandan solo cuando aplican
sortBy: "price", // price | createdAt | area
sortOrder: "asc",
pageSize: "12", // máximo 48
});
const res = await fetch(`${API}/properties?${params}`, { headers: { "X-API-Key": KEY } });
const { data, meta } = await res.json(); // meta: { total, page, pageSize, totalPages }Receba o formulário de contato
Cria ou atualiza o contato com o imóvel e os UTMs, e soma o analytics do portal. Um 400 diz em palavras qual campo falhou: mostre no formulário.
await fetch("https://api.bydomu.com/v1/leads", {
method: "POST",
headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({
firstName: "Laura", // obligatorio (2-100)
phone: "+573000000001", // obligatorio (7-20)
email: "[email protected]",
message: "¿Sigue disponible?",
propertyId: "clx1prop001", // en la ficha de una propiedad
interestedIn: "RENT", // SALE | RENT | SALE_OR_RENT
utmSource: new URLSearchParams(location.search).get("utm_source") ?? undefined,
}),
});
// 201 → { "data": { "success": true } }Se você escuta webhooks: o formulário dispara lead.submitted, mas hoje esse evento só traz a resposta da API; os dados da pessoa chegam em contact.created.
Visitas e compromissos
POST /leads/schedule registra uma solicitação de visita com data e faixa preferidas; não cria o compromisso: a imobiliária confirma depois.
await fetch("https://api.bydomu.com/v1/leads/schedule", {
method: "POST",
headers: { "X-API-Key": KEY, "Content-Type": "application/json" },
body: JSON.stringify({
firstName: "Laura",
phone: "+573000000001",
propertyId: "clx1prop001", // obligatorio
preferredDate: "2026-10-04",
preferredTime: "morning", // morning | afternoon | evening
}),
});Para agendar de verdade, use a agenda online de cada corretor: os horários livres e o compromisso em um horário livre (fica CONFIRMED se a página confirma sozinha; senão, SCHEDULED). Estas três respostas vêm duplamente envelopadas: { data: { data: … } }.
// 1. Asesores con agenda en línea (cada uno con su slug)
const agents = await get("/booking/agents");
// 2. Horas libres de un mes. OJO: month va de 0 (enero) a 11 (diciembre)
const { data: { data: availability } } = await get("/booking/carlos-rodriguez/availability?month=9&year=2026");
// availability = { configured: true, availableDates: [{ date: "2026-10-05", slots: ["09:00", "10:00"] }] }
// 3. Agendar en un espacio libre
const res = await post("/booking/carlos-rodriguez", {
firstName: "Laura",
phone: "+573000000001",
date: "2026-10-05",
startTime: "09:00",
type: "SHOWING",
propertyId: "clx1prop001",
});
// 201 → { "data": { "data": { "appointmentId": "…", "status": "CONFIRMED" | "SCHEDULED", "ownerNotified": … } } }Monte um buscador guiado
Pergunte passo a passo o que a pessoa procura e envie tudo no final: fica como contato e a resposta traz até 12 imóveis que combinam, do melhor ao pior, com a pontuação (0-100) e o detalhe do cálculo.
const res = await post("/finder", {
transactionType: "SALE", // SALE | RENT
propertyType: "APARTMENT",
city: "Bogotá",
neighborhood: "Chapinero",
budgetMin: 250000000,
budgetMax: 450000000,
minBedrooms: 2,
amenities: ["parking", "gym"],
firstName: "Laura",
phone: "+573000000001",
subscribedToAlerts: true,
});
// 201 → { "data": { "contact": { "id": "…" }, "total": 7,
// "properties": [{ "id": "…", "title": "…", "price": 450000000, "matchScore": 87,
// "breakdown": [{ "criterio": "presupuesto", "puntos": 30, "estado": "match" }], … }] } }Conte visitas e cliques
Com events:write, seu site alimenta o analytics do portal no ByDomu. A resposta é imediata e não confirma que o evento foi salvo.
await post("/events", { type: "PROPERTY_VIEW", propertyId: "clx1prop001", referrer: document.referrer });
// PAGE_VIEW | PROPERTY_VIEW | SEARCH | LEAD_FORM | WHATSAPP_CLICK | CALL_CLICK
// SCHEDULE_CLICK | SHARE_CLICK | FINDER_SUBMIT → 200 { "data": { "success": true } }Se algo falhar
- 400Um campo não cumpre o esquema (nome curto demais, telefone inválido, pageSize acima de 48, month fora de 0-11).
- 403Você usou uma publicável em um endpoint privado (a mensagem diz quais pode usar) ou uma secreta no navegador.
- 404O imóvel ou o slug da agenda não é da sua imobiliária.
- 429Seus visitantes esgotaram o limite da chave: sirva o inventário de um cache.