/**
* SDK oficial da API ImobyFlow — TypeScript / Node 18+ (versão do contrato 1.0.0).
* Official ImobyFlow API SDK — TypeScript / Node 18+.
*
* Gerado do mesmo contrato do portal: https://imobyflow.com.br/desenvolvedores
* Uso / usage:
*
* import { ImobyFlow } from './imobyflow';
* const api = new ImobyFlow(process.env.IMOBYFLOW_API_KEY!);
* const { data } = await api.getMe();
* for await (const imovel of api.listPropertiesAll({ status: 'ACTIVE' })) console.log(imovel.id);
*
* A chave é SÓ do servidor: nunca a ponha no navegador do seu cliente.
* The key is SERVER-SIDE only: never ship it to your end user's browser.
*/
import { createHmac, randomUUID, timingSafeEqual } from 'node:crypto';
export const API_VERSION = "1.0.0";
/** Erro no formato RFC 9457 (`application/problem+json`). · Error in RFC 9457 format (`application/problem+json`). */
export interface Problem {
/** Endereço da página deste erro, com a causa e o conserto. · URL of this error page, with the cause and the fix. */
type: string;
/** O nome do erro, na língua do `Accept-Language`. · Error name, in the `Accept-Language` language. */
title: string;
/** O código HTTP. · The HTTP status code. */
status: number;
/** Código estável — é por ele que o seu sistema decide o que fazer. · Stable code — your system should branch on it. */
code: string;
/** Id da requisição. Mande junto quando falar com o suporte. · Request id. Include it when contacting support. */
requestId: string;
/** Explicação do caso (quando houver). · Explanation of this case (when available). */
detail?: string;
/** Todos os problemas do pedido de uma vez — não só o primeiro. · All problems in the request at once — not just the first one. */
invalidParams?: Array<{ name: string; reason: string; [key: string]: unknown; }>;
}
/** Os limites da faixa de uso da conta. · The account's usage tier limits. */
export interface Limits {
/** Chamadas por segundo. · Calls per second. */
ratePerSecond: number;
/** Pico tolerado num instante. · Short burst allowed. */
burst: number;
/** Chamadas por mês (mês de calendário, UTC). · Calls per month (calendar month, UTC). */
monthlyQuota: number;
/** Chaves ativas ao mesmo tempo. · Active keys at the same time. */
maxKeys: number;
/** Endereços de webhook. · Webhook endpoints. */
maxWebhooks: number;
}
/** Quem é a conta, o que a chave pode fazer e quanto da cota já foi usado. · Who the account is, what the key can do and how much of the quota is used. */
export interface Me {
/** A conta dona da chave. · The account that owns the key. */
account: { id: string; name: string | null; type: string | null; plan: string | null; };
/** A liberação da API. · API access. */
access: { status: string | null; tier: string; pilotUntil: string | null; limits: Limits; };
/** A chave usada nesta chamada. · The key used in this call. */
key: { id: string | null; name: string | null; scopes: Array<"properties:read" | "properties:write" | "leads:read" | "leads:write" | "radar:read" | "radar:write" | "partnerships:read" | "partnerships:write" | "team:read" | "launches:read" | "launches:write" | "captacao:read" | "captacao:accept" | "events:read" | "webhooks:manage">; expiresAt: string | null; };
/** O uso do mês. · Monthly usage. */
usage: { month: string; calls: number; monthlyQuota: number; remaining: number; };
/** A cota de imóveis do plano. · The plan's property quota. */
properties: { active: number; limit: number | null; };
}
/** Um valor aceito e o seu rótulo. · An accepted value and its label. */
export interface ValueLabel {
/** O valor que vai no campo. · The value to send in the field. */
value: string;
/** O rótulo, na língua do `Accept-Language`. · The label, in the `Accept-Language` language. */
label: string;
}
/** Uma categoria de imóvel e os seus subtipos. · A property category and its subtypes. */
export interface PropertyTypeGroup {
/** A categoria. · The category. */
category: "RESIDENCIAL" | "COMERCIAL" | "TERRENO" | "RURAL";
/** Rótulo da categoria. · Category label. */
label: string;
/** Os subtipos da categoria — é o subtipo que vai em `type`. · The subtypes in the category — the subtype is what goes in `type`. */
types: Array;
}
/** Uma permissão que uma chave pode ter. · A permission a key can have. */
export interface ScopeInfo {
/** A permissão. · The permission. */
id: "properties:read" | "properties:write" | "leads:read" | "leads:write" | "radar:read" | "radar:write" | "partnerships:read" | "partnerships:write" | "team:read" | "launches:read" | "launches:write" | "captacao:read" | "captacao:accept" | "events:read" | "webhooks:manage";
/** O grupo, para exibir. · The group, for display. */
group: string;
/** O nome, para exibir. · The name, for display. */
label: string;
/** O que ela permite. · What it allows. */
description: string;
}
/** Um tipo de evento. · An event type. */
export interface EventTypeInfo {
/** O tipo do evento. · The event type. */
type: "property.created" | "property.updated" | "property.deleted" | "property.restored" | "property.purged" | "lead.created" | "lead.updated" | "lead.deleted" | "lead.restored" | "lead.purged" | "radar.client_summary" | "partnership.created" | "partnership.updated" | "captacao.offer_received" | "captacao.offer_accepted" | "captacao.offer_withdrawn";
/** A permissão de leitura que dá acesso a ele. · The read permission that grants access to it. */
scope: "properties:read" | "properties:write" | "leads:read" | "leads:write" | "radar:read" | "radar:write" | "partnerships:read" | "partnerships:write" | "team:read" | "launches:read" | "launches:write" | "captacao:read" | "captacao:accept" | "events:read" | "webhooks:manage";
/** O que ele avisa. · What it signals. */
description: string;
}
/** Uma cidade do catálogo. · A catalog city. */
export interface City {
/** Código do IBGE, 7 dígitos — a forma mais segura de mandar a cidade. · IBGE code, 7 digits — the safest way to send the city. */
cityId: string;
/** Nome da cidade. · City name. */
name: string;
/** Estado (UF). · State (UF). */
uf: string;
/** Identificador da cidade no catálogo. · City identifier in the catalog. */
citySlug: string;
}
/** Um bairro do catálogo. · A catalog neighborhood. */
export interface Neighborhood {
/** O identificador do bairro — o valor de `neighborhoodSlug` na escrita. · The neighborhood identifier — the `neighborhoodSlug` value for writes. */
neighborhoodSlug: string;
/** Nome do bairro. · Neighborhood name. */
name: string;
}
/** O endereço completo — o imóvel é da própria conta. · The full address — the property belongs to the account itself. */
export interface Address {
/** Nome do bairro. · Neighborhood name. */
neighborhood: string | null;
/** Bairro do catálogo. Nulo quando o bairro ainda não foi reconhecido — aí o imóvel fica fora das recomendações até a curadoria decidir. · Catalog neighborhood. Null when the neighborhood is not recognized yet — the property stays out of recommendations until curation decides. */
neighborhoodSlug: string | null;
/** Nome da cidade. · City name. */
city: string | null;
/** Código do IBGE. · IBGE code. */
cityId: string | null;
/** Identificador da cidade no catálogo. · City identifier in the catalog. */
citySlug: string | null;
/** Estado (UF). · State (UF). */
state: string | null;
/** Rua. · Street. */
street: string | null;
/** Número. · Number. */
number: string | null;
/** Complemento. · Complement. */
complement: string | null;
}
/** O endereço até o bairro. · The address down to the neighborhood. */
export interface AddressArea {
/** Nome do bairro. · Neighborhood name. */
neighborhood: string | null;
/** Bairro do catálogo. · Catalog neighborhood. */
neighborhoodSlug: string | null;
/** Nome da cidade. · City name. */
city: string | null;
/** Código do IBGE. · IBGE code. */
cityId: string | null;
/** Identificador da cidade no catálogo. · City identifier in the catalog. */
citySlug: string | null;
/** Estado (UF). · State (UF). */
state: string | null;
}
/** As condições para parceiros. · Terms for partners. */
export interface PartnershipTerms {
/** Comissão de venda oferecida a parceiros, em %. · Sale commission offered to partners, in %. */
commissionPercent: number | null;
/** Comissão de locação, em aluguéis. · Rent commission, in months of rent. */
rentCommissionMonths: number | null;
/** Parte da comissão que fica com quem captou, em %. · Share of the commission kept by the listing side, in %. */
splitListingPercent: number | null;
}
/** A situação do imóvel nas recomendações (Radar). · The property's status in recommendations (Radar). */
export interface PropertyRadar {
/** Entra nas recomendações agora (ativo e sem pendência). · Is in recommendations right now (active and with no pending item). */
eligible: boolean;
/** O que falta para entrar nas recomendações. A capa é obrigatória. · What is missing to enter recommendations. A cover photo is required. */
pending: Array<"CITY_MISSING" | "CITY_NOT_IN_CATALOG" | "NEIGHBORHOOD_MISSING" | "NEIGHBORHOOD_NOT_IN_CATALOG" | "TYPE_MISSING" | "PURPOSE_MISSING" | "SALE_PRICE_MISSING" | "RENT_PRICE_MISSING" | "COVER_PHOTO_MISSING" | "OTHER">;
/** As mesmas pendências, por extenso. · The same pending items, spelled out. */
labels: Array;
}
/** A análise do imóvel pela ImobyFlow antes de ele aparecer para parceiros. Imóvel novo pela API nasce em análise. · ImobyFlow's review before the property is shown to partners. New properties from the API start under review. */
export interface Curation {
/** `PENDING`, `APPROVED` ou `REJECTED`. · `PENDING`, `APPROVED` or `REJECTED`. */
status: string | null;
/** O motivo da recusa, em código. · The rejection reason, as a code. */
reason: "LANCAMENTO" | "SEM_VALOR" | "QUALIDADE_BAIXA" | "NAO_ANGARIACAO" | "MARCA_DAGUA" | "FOTOS_INSUFICIENTES" | "DADOS_INCOERENTES" | "OUTRO" | null;
/** O motivo por extenso. · The reason, spelled out. */
label: string | null;
}
/** A régua dos 60 dias: imóvel não confirmado sai do ar. Gravar o imóvel pela API (ou confirmar) renova a data. · The 60-day rule: unconfirmed properties go offline. Writing the property through the API (or confirming it) renews the date. */
export interface Confirmation {
/** Última confirmação de que segue disponível. · Last confirmation that it is still available. */
lastConfirmedAt: string | null;
/** Quando a confirmação vence (a cada 60 dias). · When the confirmation is due (every 60 days). */
dueAt: string | null;
/** Quando o aviso de confirmação foi mandado. · When the confirmation notice was sent. */
noticeAt: string | null;
/** Quando sai do ar sem resposta (7 dias depois do aviso). · When it goes offline without an answer (7 days after the notice). */
offlineAt: string | null;
}
/** Dados de lançamento (empreendimento e tipologia). · New-development data (development and unit type). */
export interface LaunchBlock {
/** Estágio da obra. · Construction stage. */
constructionStage: "LAUNCH" | "OFF_PLAN" | "NEW" | "READY" | null;
/** Previsão de entrega. · Expected delivery. */
deliveryDate: string | null;
/** Andamento da obra, em %. · Construction progress, in %. */
constructionProgress: number | null;
/** Unidades no total. · Total units. */
unitsTotal: number | null;
/** Unidades disponíveis. · Available units. */
unitsAvailable: number | null;
/** Unidades reservadas. · Reserved units. */
unitsReserved: number | null;
/** Unidades vendidas. · Sold units. */
unitsSold: number | null;
/** As plantas. · The floor plans. */
floorPlans: Array;
}
/** O download das fotos mandadas por endereço. Ele acontece depois da resposta — é aqui que você vê se a galeria entrou. · Download of the photos sent by URL. It happens after the response — this is where you see whether the gallery made it. */
export interface PhotoSync {
/** `QUEUED` (na fila), `DONE`, `PARTIAL` (algumas falharam), `FAILED` ou `NOT_QUEUED` (a fila recusou — o próximo pedido tenta de novo). · `QUEUED`, `DONE`, `PARTIAL` (some failed), `FAILED` or `NOT_QUEUED` (the queue refused — the next request retries). */
state: string;
/** Fotos pedidas. · Photos requested. */
requested: number | null;
/** Fotos baixadas e gravadas. · Photos downloaded and stored. */
ingested: number | null;
/** Fotos que falharam. · Photos that failed. */
failed: number | null;
/** Quando entrou na fila. · When it was queued. */
queuedAt: string | null;
/** Quando terminou. · When it finished. */
finishedAt: string | null;
}
/** Um imóvel da carteira da conta. · A property in the account's portfolio. */
export interface Property {
/** Id do imóvel. · Property id. */
id: string;
/** O código do imóvel no SEU sistema. · The property's code in YOUR system. */
externalRef: string | null;
/** `PROPERTY` (avulso), `DEVELOPMENT` (empreendimento) ou `TYPOLOGY` (tipologia de um empreendimento). · `PROPERTY` (standalone), `DEVELOPMENT` (new development) or `TYPOLOGY` (unit type of a development). */
kind: "PROPERTY" | "DEVELOPMENT" | "TYPOLOGY";
/** O empreendimento desta tipologia. · The development of this unit type. */
developmentId: string | null;
/** Situação. `DELETED` = na lixeira (30 dias). · Status. `DELETED` = in the trash (30 days). */
status: "ACTIVE" | "INACTIVE" | "SOLD" | "RENTED" | "DELETED";
/** Subtipo (veja as listas de valores). · Subtype (see the reference lists). */
type: "APARTAMENTO" | "CASA_RUA" | "CASA_CONDOMINIO" | "CASA_VILA" | "STUDIO" | "FLAT" | "COBERTURA" | "SALA_COMERCIAL" | "LOJA_PONTO" | "GALPAO" | "PREDIO" | "TERRENO_RUA" | "TERRENO_CONDOMINIO" | "CHACARA_SITIO" | "FAZENDA" | null;
/** Categoria do subtipo. · The subtype's category. */
category: "RESIDENCIAL" | "COMERCIAL" | "TERRENO" | "RURAL" | null;
/** Finalidades: `VENDA`, `LOCACAO` ou as duas. · Purposes: `VENDA` (sale), `LOCACAO` (rent) or both. */
purposes: Array<"VENDA" | "LOCACAO">;
/** Preço de venda, em reais. · Sale price, in BRL. */
salePrice: number | null;
/** Aluguel mensal, em reais. · Monthly rent, in BRL. */
rentPrice: number | null;
/** Título do anúncio. · Listing title. */
title: string | null;
/** Descrição, em texto corrido. · Description, as plain text. */
description: string | null;
/** Endereço. · Address. */
address: Address;
/** Quartos. · Bedrooms. */
bedrooms: number | null;
/** Suítes. · Suites. */
suites: number | null;
/** Banheiros. · Bathrooms. */
bathrooms: number | null;
/** Vagas de garagem. · Parking spots. */
parkingSpots: number | null;
/** Área privativa total, em m² — a que se compara entre imóveis. · Total private area, in m² — the comparable one. */
area: number | null;
/** Área coberta, em m² (só exibição). · Covered area, in m² (display only). */
privateArea: number | null;
/** Itens do imóvel e do condomínio. · Property and building amenities. */
amenities: Array;
/** A capa (a 1ª foto). Sem capa o imóvel não entra nas recomendações. · The cover (1st photo). Without a cover the property is left out of recommendations. */
coverPhoto: string | null;
/** A galeria, na ordem. · The gallery, in order. */
photos: Array;
/** Endereço do anúncio no seu site. · Listing URL on your website. */
listingUrl: string | null;
/** O corretor responsável da equipe. · The responsible broker on the team. */
captador: { accountId: string; name: string | null; } | null;
/** Nome do captador em texto (quem não está na equipe). · Listing agent name as text (someone not on the team). */
captadorName: string | null;
/** Compartilhado com parceiros. · Shared with partners. */
sharedToNetwork: boolean;
/** Condições para parceiros. · Partner terms. */
partnershipTerms: PartnershipTerms;
/** Situação nas recomendações. · Recommendation status. */
radar: PropertyRadar;
/** Análise da ImobyFlow. · ImobyFlow's review. */
curation: Curation;
/** A confirmação de disponibilidade. · Availability confirmation. */
confirmation: Confirmation;
/** Por que está arquivado (só com `status` = `INACTIVE`). · Why it is archived (only when `status` = `INACTIVE`). */
inactiveReason: string | null;
/** Quando foi para a lixeira. · When it was moved to the trash. */
deletedAt: string | null;
/** Dados de lançamento (só empreendimento e tipologia). · New-development data (development and unit type only). */
launch: LaunchBlock | null;
/** O download das fotos mandadas por endereço. · Download of the photos sent by URL. */
photoSync: PhotoSync | null;
/** Quando foi criado (UTC). · When it was created (UTC). */
createdAt: string;
/** Última alteração (UTC). · Last change (UTC). */
updatedAt: string;
}
/** O endereço. Vem inteiro quando vem. · The address. Send it whole when you send it. */
export interface AddressInput {
/** Código do IBGE (7 dígitos). Com ele, `city` e `state` são dispensáveis. · IBGE code (7 digits). With it, `city` and `state` are not needed. */
cityId?: string;
/** Nome da cidade (com `state`). Nome desconhecido volta 400 com sugestões. · City name (with `state`). An unknown name returns 400 with suggestions. */
city?: string;
/** UF, 2 letras. · State (UF), 2 letters. */
state?: string;
/** Bairro pelo identificador do catálogo — o caminho garantido. · Neighborhood by catalog identifier — the guaranteed path. */
neighborhoodSlug?: string;
/** Bairro em texto. Ele passa pelo dicionário de apelidos; o que não for reconhecido fica pendente para a curadoria, nunca vira um bairro inventado. · Neighborhood as text. It goes through the alias dictionary; anything unrecognized waits for curation and never becomes a made-up neighborhood. */
neighborhood?: string;
/** Rua. · Street. */
street?: string;
/** Número. · Number. */
number?: string;
/** Complemento. · Complement. */
complement?: string;
}
/** Os campos que a API aceita no imóvel. Campo desconhecido é erro (400). Campo ausente não apaga; para limpar, mande `null`. · The fields the API accepts for a property. Unknown fields are an error (400). Absent fields are kept; to clear one, send `null`. */
export interface PropertyInput {
/** O código do imóvel no seu sistema (só no POST; no PUT ele vai no caminho). · The property's code in your system (POST only; in PUT it goes in the path). */
externalRef?: string;
/** Título. Marcação HTML é removida. · Title. HTML markup is stripped. */
title?: string;
/** Descrição. `
` e `
` viram quebra de linha; o resto da marcação sai. · Description. `
` and `` become line breaks; other markup is stripped. */
description?: string;
/** Subtipo. · Subtype. */
type?: "APARTAMENTO" | "CASA_RUA" | "CASA_CONDOMINIO" | "CASA_VILA" | "STUDIO" | "FLAT" | "COBERTURA" | "SALA_COMERCIAL" | "LOJA_PONTO" | "GALPAO" | "PREDIO" | "TERRENO_RUA" | "TERRENO_CONDOMINIO" | "CHACARA_SITIO" | "FAZENDA";
/** Finalidades. · Purposes. */
purposes?: Array<"VENDA" | "LOCACAO">;
/** Preço de venda, em reais. Obrigatório com `VENDA`. · Sale price, in BRL. Required with `VENDA`. */
salePrice?: number | null;
/** Aluguel, em reais. Obrigatório com `LOCACAO`. · Rent, in BRL. Required with `LOCACAO`. */
rentPrice?: number | null;
/** Endereço. · Address. */
address?: AddressInput;
/** Quartos. · Bedrooms. */
bedrooms?: number | null;
/** Suítes. · Suites. */
suites?: number | null;
/** Banheiros. · Bathrooms. */
bathrooms?: number | null;
/** Vagas. · Parking spots. */
parkingSpots?: number | null;
/** Área privativa total, em m². · Total private area, in m². */
area?: number | null;
/** Área coberta, em m². · Covered area, in m². */
privateArea?: number | null;
/** Endereço do anúncio no seu site (http ou https). · Listing URL on your website (http or https). */
listingUrl?: string | null;
/** Nome do captador em texto. · Listing agent name as text. */
captadorName?: string | null;
/** Id do corretor responsável da equipe. · Id of the responsible broker on the team. */
captadorAccountId?: string | null;
/** Condições para parceiros. · Partner terms. */
partnershipTerms?: PartnershipTerms;
/** Até 30 endereços; a 1ª é a capa. Baixadas depois da resposta (veja `photoSync`). Ausente = a galeria fica como está; lista vazia = tirar as fotos. · Up to 30 URLs; the 1st is the cover. Downloaded after the response (see `photoSync`). Absent = gallery unchanged; empty list = remove the photos. */
photos?: Array;
}
/** O desfecho da escrita. · The write outcome. */
export interface PropertyWriteResult {
/** O que aconteceu: `CREATED`, `UPDATED`, `UNCHANGED` (nada mudou, nada gravado), `CONFIRMED` (só a data de disponibilidade), `STATUS_SET`, `DELETED`, `ALREADY_DELETED`… · What happened: `CREATED`, `UPDATED`, `UNCHANGED` (nothing changed, nothing written), `CONFIRMED` (only the availability date), `STATUS_SET`, `DELETED`, `ALREADY_DELETED`… */
outcome: string;
/** Foi um ensaio — nada foi gravado. · It was a dry run — nothing was written. */
dryRun: boolean;
/** Campos que a equipe editou na tela e que por isso não foram sobrescritos — a edição na tela vence. · Fields the team edited in the dashboard, so they were not overwritten — dashboard edits win. */
conflicts: Array;
/** A galeria: `UNCHANGED`, `QUEUED`, `ALREADY_QUEUED` ou `CLEARED`. Nulo quando o pedido não falou de fotos. · The gallery: `UNCHANGED`, `QUEUED`, `ALREADY_QUEUED` or `CLEARED`. Null when the request did not mention photos. */
photos: string | null;
}
/** Um telefone. · A phone number. */
export interface Phone {
/** Só dígitos, com DDD (10 a 13). · Digits only, with area code (10 to 13). */
number: string;
/** É WhatsApp. · Is WhatsApp. */
isWhatsApp: boolean;
/** Rótulo livre (`celular`, `trabalho`…). · Free label (`mobile`, `work`…). */
label: string | null;
}
/** Uma região de interesse. · A region of interest. */
export interface Location {
/** Código do IBGE. · IBGE code. */
cityId: string | null;
/** Identificador da cidade. · City identifier. */
citySlug: string | null;
/** Nome da cidade. · City name. */
cityName: string | null;
/** Estado. · State. */
uf: string | null;
/** Bairro do catálogo (nulo = a cidade inteira). · Catalog neighborhood (null = the whole city). */
neighborhoodSlug: string | null;
/** Nome do bairro. · Neighborhood name. */
neighborhoodName: string | null;
/** `PREFERRED` (preferido) ou `ACCEPTABLE` (aceitável) — pesa na nota da recomendação. · `PREFERRED` or `ACCEPTABLE` — it weighs on the recommendation score. */
preference: "PREFERRED" | "ACCEPTABLE";
}
/** O perfil de busca — é ele que liga as recomendações. · The search profile — it is what drives recommendations. */
export interface Interest {
/** Finalidades: `VENDA`, `LOCACAO` ou as duas. · Purposes: `VENDA` (sale), `LOCACAO` (rent) or both. */
purposes: Array<"VENDA" | "LOCACAO">;
/** Tipos de imóvel procurados. · Property types wanted. */
propertyTypes: Array<"APARTAMENTO" | "CASA_RUA" | "CASA_CONDOMINIO" | "CASA_VILA" | "STUDIO" | "FLAT" | "COBERTURA" | "SALA_COMERCIAL" | "LOJA_PONTO" | "GALPAO" | "PREDIO" | "TERRENO_RUA" | "TERRENO_CONDOMINIO" | "CHACARA_SITIO" | "FAZENDA">;
/** Regiões de interesse. · Regions of interest. */
locations: Array;
/** Aceita bairros parecidos com os escolhidos. · Accepts neighborhoods similar to the chosen ones. */
similarNeighborhoods: boolean;
/** Compra: piso, em reais. · Purchase: minimum, in BRL. */
salePriceMin: number | null;
/** Compra: teto, em reais. · Purchase: maximum, in BRL. */
salePriceMax: number | null;
/** Aluguel: piso, em reais. · Rent: minimum, in BRL. */
rentPriceMin: number | null;
/** Aluguel: teto, em reais. · Rent: maximum, in BRL. */
rentPriceMax: number | null;
/** Quartos, no mínimo. · Minimum bedrooms. */
bedrooms: number | null;
/** Banheiros, no mínimo. · Minimum bathrooms. */
bathrooms: number | null;
/** Vagas, no mínimo. · Minimum parking spots. */
parkingSpots: number | null;
/** Área mínima, em m². · Minimum area, in m². */
areaMin: number | null;
}
/** A situação do cliente nas recomendações. · The client's status in recommendations. */
export interface LeadRadar {
/** Recebe recomendações agora (ativo e sem pendência). · Receives recommendations right now (active and with no pending item). */
eligible: boolean;
/** O que falta no perfil de busca. · What is missing in the search profile. */
pending: Array<"PURPOSE_MISSING" | "PROPERTY_TYPES_MISSING" | "CITY_MISSING" | "CITY_NOT_IN_CATALOG" | "BUDGET_MISSING" | "SALE_BUDGET_MISSING" | "RENT_BUDGET_MISSING" | "OTHER">;
/** As mesmas pendências, por extenso. · The same pending items, spelled out. */
labels: Array;
}
/** Um cliente da conta. Nome, telefone e e-mail são dado pessoal — a imobiliária é a controladora. · A client of the account. Name, phone and e-mail are personal data — the agency is the controller. */
export interface Lead {
/** Id do cliente. · Client id. */
id: string;
/** O código do cliente no SEU sistema. · The client's code in YOUR system. */
externalRef: string | null;
/** O corretor responsável (ou a própria imobiliária). · The responsible broker (or the agency itself). */
ownerAccountId: string | null;
/** `ACTIVE`, `ARCHIVED` ou `DELETED` (lixeira). · `ACTIVE`, `ARCHIVED` or `DELETED` (trash). */
state: "ACTIVE" | "ARCHIVED" | "DELETED";
/** Etapa do atendimento. · Funnel stage. */
status: "NEW" | "ATTENDING" | "PROPOSAL" | "WON" | "LOST" | null;
/** Nome. · Name. */
name: string | null;
/** Telefones. · Phones. */
phones: Array;
/** E-mail. · E-mail. */
email: string | null;
/** Por onde chegou: `MANUAL`, `IMPORT_CSV`, `EMAIL`, `WEBHOOK`, `META_ADS`, `PORTAL_API`, `CRM_API` (pela API)… · Where it came from: `MANUAL`, `IMPORT_CSV`, `EMAIL`, `WEBHOOK`, `META_ADS`, `PORTAL_API`, `CRM_API` (through the API)… */
source: string;
/** Detalhe da origem (o portal, o nome do sistema). · Source detail (the portal, the system name). */
sourceDetail: string | null;
/** O imóvel que trouxe o cliente, quando houver. · The property that brought the client, if any. */
sourcePropertyId: string | null;
/** Crédito pré-aprovado. · Pre-approved credit. */
preApproved: boolean;
/** O perfil (sem nome nem contato) pode receber imóveis de parceiros. · The profile (without name or contact) may receive partner properties. */
sharedToNetwork: boolean;
/** Anotações. · Notes. */
notes: string | null;
/** Perfil de busca. · Search profile. */
interest: Interest;
/** Situação nas recomendações. · Recommendation status. */
radar: LeadRadar;
/** Última movimentação — anda pela data que o seu sistema manda e pelos atendimentos, nunca pela sincronização. · Last activity — moves with the date your system sends and with interactions, never with sync itself. */
lastActivityAt: string | null;
/** Quando foi arquivado. · When it was archived. */
archivedAt: string | null;
/** Por que foi arquivado (`MANUAL`, `INACTIVITY`, `IMPORT`…). · Why it was archived (`MANUAL`, `INACTIVITY`, `IMPORT`…). */
archivedReason: string | null;
/** Quando foi para a lixeira. · When it was moved to the trash. */
deletedAt: string | null;
/** Quando foi criado (UTC). · When it was created (UTC). */
createdAt: string;
/** Última alteração (UTC). · Last change (UTC). */
updatedAt: string;
}
/** Um telefone. Também aceita só o número, em texto. · A phone. A plain string with the number is also accepted. */
export interface PhoneInput {
/** Com DDD; só os dígitos contam. · With area code; only digits count. */
number?: string;
/** É WhatsApp (padrão: sim). · Is WhatsApp (default: yes). */
isWhatsApp?: boolean;
/** Rótulo livre. · Free label. */
label?: string;
}
/** Uma região de interesse. · A region of interest. */
export interface LocationInput {
/** Código do IBGE. · IBGE code. */
cityId?: string;
/** Nome da cidade (com `uf`). · City name (with `uf`). */
cityName?: string;
/** Estado. · State. */
uf?: string;
/** Bairro do catálogo. · Catalog neighborhood. */
neighborhoodSlug?: string;
/** Bairro em texto. Área de mercado ("Ecoville") vira os bairros do catálogo que ela cobre. · Neighborhood as text. Market areas ("Ecoville") expand into the catalog neighborhoods they cover. */
neighborhoodName?: string;
/** `PREFERRED` (padrão) ou `ACCEPTABLE`. · `PREFERRED` (default) or `ACCEPTABLE`. */
preference?: "PREFERRED" | "ACCEPTABLE";
}
/** O perfil de busca. É mesclado campo a campo: mandar só o teto não apaga as regiões. · The search profile. Merged field by field: sending only the maximum does not erase the regions. */
export interface InterestInput {
/** Finalidades. · Purposes. */
purposes?: Array<"VENDA" | "LOCACAO">;
/** Tipos procurados. · Types wanted. */
propertyTypes?: Array<"APARTAMENTO" | "CASA_RUA" | "CASA_CONDOMINIO" | "CASA_VILA" | "STUDIO" | "FLAT" | "COBERTURA" | "SALA_COMERCIAL" | "LOJA_PONTO" | "GALPAO" | "PREDIO" | "TERRENO_RUA" | "TERRENO_CONDOMINIO" | "CHACARA_SITIO" | "FAZENDA">;
/** Regiões (até 20). Quando vem, vem inteira. · Regions (up to 20). Send the whole list when you send it. */
locations?: Array;
/** Aceita bairros parecidos. · Accepts similar neighborhoods. */
similarNeighborhoods?: boolean;
/** Compra: piso. · Purchase: minimum. */
salePriceMin?: number | null;
/** Compra: teto. Abaixo do piso é recusado. · Purchase: maximum. Below the minimum is refused. */
salePriceMax?: number | null;
/** Aluguel: piso. · Rent: minimum. */
rentPriceMin?: number | null;
/** Aluguel: teto. Abaixo do piso é recusado. · Rent: maximum. Below the minimum is refused. */
rentPriceMax?: number | null;
/** Quartos, no mínimo. · Minimum bedrooms. */
bedrooms?: number | null;
/** Banheiros, no mínimo. · Minimum bathrooms. */
bathrooms?: number | null;
/** Vagas, no mínimo. · Minimum parking spots. */
parkingSpots?: number | null;
/** Área mínima, em m². · Minimum area, in m². */
areaMin?: number | null;
}
/** Os campos que a API aceita no cliente. Campo desconhecido é erro; campo ausente não apaga. · The fields the API accepts for a client. Unknown fields are an error; absent fields are kept. */
export interface LeadInput {
/** O código do cliente no seu sistema (só no POST). · The client's code in your system (POST only). */
externalRef?: string;
/** Nome. Obrigatório na criação. · Name. Required on creation. */
name?: string;
/** Até 5 telefones. Na criação, telefone ou e-mail. · Up to 5 phones. On creation, a phone or an e-mail. */
phones?: Array;
/** E-mail. · E-mail. */
email?: string | null;
/** Etapa do atendimento. · Funnel stage. */
status?: "NEW" | "ATTENDING" | "PROPOSAL" | "WON" | "LOST";
/** Anotações. · Notes. */
notes?: string;
/** Crédito pré-aprovado. · Pre-approved credit. */
preApproved?: boolean;
/** O perfil pode receber imóveis de parceiros. · The profile may receive partner properties. */
sharedToNetwork?: boolean;
/** Perfil de busca. · Search profile. */
interest?: InterestInput;
/** O corretor responsável, pelo id. · The responsible broker, by id. */
ownerAccountId?: string;
/** O corretor responsável, pelo e-mail — é como o seu sistema o conhece. Sem responsável, vale a distribuição da imobiliária. · The responsible broker, by e-mail — the way your system knows them. Without one, the agency's distribution rule applies. */
ownerEmail?: string;
/** A última movimentação no SEU sistema. Só anda para a frente. Mais de 60 dias atrás na criação = o cliente entra arquivado (base histórica). · The last activity in YOUR system. It only moves forward. More than 60 days ago on creation = the client is created archived (historical base). */
lastActivityAt?: string;
/** Obrigatório `true` na criação: a imobiliária declara ter a base legal para tratar o dado (Termos da API). · Must be `true` on creation: the agency declares it has the legal basis to process the data (API Terms). */
consentGiven?: boolean;
}
/** O desfecho da escrita. · The write outcome. */
export interface LeadWriteResult {
/** O que aconteceu: `CREATED`, `UPDATED`, `UNCHANGED`, `LINKED` (o código passou a apontar para um cliente que já existia pelo contato), `ARCHIVED` (criado arquivado, base histórica), `STATE_SET` (arquivado ou reativado), `ADDED` (atendimento registrado), `DELETED`, `ALREADY_DELETED`. · What happened: `CREATED`, `UPDATED`, `UNCHANGED`, `LINKED` (the code now points to a client that already existed by contact), `ARCHIVED` (created archived, historical base), `STATE_SET` (archived or reactivated), `ADDED` (interaction logged), `DELETED`, `ALREADY_DELETED`. */
outcome: string;
/** Foi um ensaio — nada foi gravado. · It was a dry run — nothing was written. */
dryRun: boolean;
/** O atendimento registrado (só em `POST /leads/{leadId}/interactions`). · The logged interaction (only in `POST /leads/{leadId}/interactions`). */
interaction?: { id: string; type: string; note: string | null; at: string | null; };
}
/** O retrato do imóvel no par — o mesmo do card. Campos que a tela esconde saem nulos. · The property snapshot in the pair — the same as the card. Fields the dashboard hides come back null. */
export interface PropertySnapshot {
/** Título. · Title. */
title: string | null;
/** Subtipo. · Subtype. */
type: string | null;
/** Finalidade do par. · Purpose of the pair. */
purpose: string | null;
/** Finalidades do imóvel. · The property's purposes. */
purposes: Array;
/** Preço (venda, ou aluguel quando o par é de locação). · Price (sale, or rent when the pair is a rental). */
price: number | null;
/** O preço é "a partir de" (lançamento). · The price is a "starting at" price (new development). */
priceFrom: boolean;
/** Aluguel. · Rent. */
rentPrice: number | null;
/** Cidade. · City. */
city: string | null;
/** Bairro. · Neighborhood. */
neighborhood: string | null;
/** Quartos. · Bedrooms. */
bedrooms: number | null;
/** Banheiros. · Bathrooms. */
bathrooms: number | null;
/** Vagas. · Parking spots. */
parkingSpots: number | null;
/** Área, em m². · Area, in m². */
area: number | null;
/** Capa. · Cover photo. */
coverPhoto: string | null;
/** Anúncio (nulo quando a tela também esconde). · Listing URL (null when the dashboard hides it too). */
listingUrl: string | null;
/** Comissão de venda, em %. · Sale commission, in %. */
commissionPercent: number | null;
/** Comissão de locação, em aluguéis. · Rent commission, in months. */
rentCommissionMonths: number | null;
/** Parte de quem captou, em %. · Listing side share, in %. */
splitListingPercent: number | null;
/** Última confirmação de disponibilidade. · Last availability confirmation. */
lastConfirmedAt: string | null;
/** Entrega (lançamento). · Delivery (new development). */
deliveryDate: string | null;
/** Empreendimento. · Development. */
developmentId: string | null;
/** Nome do empreendimento. · Development name. */
developmentName: string | null;
}
/** O retrato do cliente no par. · The client snapshot in the pair. */
export interface ClientSnapshot {
/** O cliente é de parceiro e está mascarado. · The client belongs to a partner and is masked. */
masked: boolean;
/** Etapa do atendimento. · Funnel stage. */
status: string | null;
/** Crédito pré-aprovado. · Pre-approved credit. */
preApproved: boolean;
/** Finalidades procuradas. · Purposes wanted. */
purposes: Array;
/** Tipos procurados. · Types wanted. */
propertyTypes: Array;
/** Regiões, por extenso. · Regions, spelled out. */
regions: Array;
/** Piso. · Minimum. */
priceMin: number | null;
/** Teto. · Maximum. */
priceMax: number | null;
/** Quartos. · Bedrooms. */
bedrooms: number | null;
/** Vagas. · Parking spots. */
parkingSpots: number | null;
/** Área mínima. · Minimum area. */
areaMin: number | null;
/** Nome — só com a permissão `leads:read` na chave e só quando a tela também mostra. Telefone, nunca. · Name — only with the `leads:read` permission on the key and only when the dashboard shows it too. Phone, never. */
name: string | null;
}
/** O parceiro do outro lado. · The partner on the other side. */
export interface Counterpart {
/** Id da conta do parceiro. · Partner's account id. */
accountId: string;
/** Nome. · Name. */
name: string | null;
/** Tipo de conta. · Account type. */
type: string | null;
/** Imobiliária do parceiro. · Partner's agency. */
organization: string | null;
/** CRECI. · Broker license (CRECI). */
creci: string | null;
/** CRECI conferido. · License verified. */
creciVerified: boolean;
/** Telefone. · Phone. */
phone: string | null;
}
/** Uma oportunidade: um imóvel que serve a um cliente. · An opportunity: a property that fits a client. */
export interface Match {
/** Id da oportunidade (`m#{imóvel}#{cliente}#{lado}`). Tem `#`: mande codificado (`%23`) no caminho. · Opportunity id (`m#{property}#{client}#{side}`). It contains `#`: URL-encode it (`%23`) in the path. */
id: string;
/** `INTERNAL` (da própria carteira), `NETWORK` (com parceiros) ou `LAUNCH` (lançamento). · `INTERNAL` (own portfolio), `NETWORK` (with partners) or `LAUNCH` (new development). */
scope: "INTERNAL" | "NETWORK" | "LAUNCH";
/** `NEW`, `FAVORITED`, `ARCHIVED` ou `REQUESTED` (virou pedido de parceria). · `NEW`, `FAVORITED`, `ARCHIVED` or `REQUESTED` (became a partnership request). */
status: string;
/** Nota de 0 a 100. · Score from 0 to 100. */
score: number;
/** Por que combina. · Why it matches. */
reasons: Array;
/** O que não combina. · What doesn't match. */
gaps: Array;
/** Imóvel. · Property. */
propertyId: string | null;
/** Cliente. · Client. */
leadId: string | null;
/** O corretor da casa que recebe a oportunidade. · The in-house broker who gets the opportunity. */
ownerAccountId: string | null;
/** Nome dele. · Their name. */
ownerName: string | null;
/** Oportunidade de parceiro sem assinatura ativa — o parceiro fica escondido, como na tela. · Partner opportunity without an active subscription — the partner stays hidden, as in the dashboard. */
locked: boolean;
/** Deixou de combinar depois de uma mudança. · No longer matches after a change. */
lostRelevance: boolean;
/** O imóvel. · The property. */
property: PropertySnapshot | null;
/** O cliente. · The client. */
client: ClientSnapshot | null;
/** O parceiro (nulo quando é da casa ou está escondido). · The partner (null when in-house or hidden). */
counterpart: Counterpart | null;
/** Quando foi criado (UTC). · When it was created (UTC). */
createdAt: string;
/** Última alteração (UTC). · Last change (UTC). */
updatedAt: string;
}
/** O desfecho. · The outcome. */
export interface MatchWriteResult {
/** `APPLIED`; em ensaio, `WOULD_APPLY`. · `APPLIED`; in a dry run, `WOULD_APPLY`. */
outcome: string;
/** Foi um ensaio. · It was a dry run. */
dryRun: boolean;
}
/** Uma ponta da parceria. · One side of the partnership. */
export interface Party {
/** Id da conta. · Account id. */
accountId: string | null;
/** Nome. · Name. */
name: string | null;
/** Tipo de conta. · Account type. */
type: string | null;
}
/** Uma parceria. · A partnership. */
export interface Partnership {
/** Id da parceria. · Partnership id. */
id: string;
/** Etapa. · Stage. */
status: "PENDING" | "ACCEPTED" | "DECLINED" | "CANCELLED" | "LEAD_REGISTERED" | "CONTACTED" | "NEGOTIATING" | "PROPOSAL" | "WON" | "LOST";
/** `CLIENT_FOR_PROPERTY` ou `PROPERTY_FOR_CLIENT`. · `CLIENT_FOR_PROPERTY` or `PROPERTY_FOR_CLIENT`. */
kind: string | null;
/** Imóvel. · Property. */
propertyId: string | null;
/** Cliente. · Client. */
leadId: string | null;
/** A oportunidade de origem. · The originating opportunity. */
matchId: string | null;
/** Empreendimento (registro em lançamento). · Development (new-development registration). */
developmentId: string | null;
/** Nome do empreendimento. · Development name. */
developmentTitle: string | null;
/** Nota da oportunidade. · Opportunity score. */
score: number | null;
/** Resumo. · Summary. */
summary: string | null;
/** Por que combina. · Why it matches. */
reasons: Array;
/** Mensagem do pedido. · Request message. */
message: string | null;
/** O lado da conta: `REQUESTER` (pediu) ou `ADDRESSEE` (recebeu). · The account's side: `REQUESTER` or `ADDRESSEE`. */
ourSide: string | null;
/** O corretor da casa na parceria. · The in-house broker in the partnership. */
ourBrokerId: string | null;
/** A conta pode mover a etapa — só o lado que captou o cliente pode. · The account can move the stage — only the side that brought the client can. */
canMoveFunnel: boolean;
/** Quem pediu. · Requester. */
requester: Party | null;
/** Quem recebeu. · Addressee. */
addressee: Party | null;
/** O parceiro do outro lado. · The partner on the other side. */
counterpart: { name: string | null; type: string | null; organization: string | null; contactName: string | null; phone: string | null; email: string | null; creci: string | null; creciVerified: boolean; };
/** O imóvel. · The property. */
property: PropertySnapshot | null;
/** O cliente. · The client. */
client: ClientSnapshot | null;
/** Último avanço de etapa. · Last stage move. */
lastProgressAt: string | null;
/** Até quando o cliente fica protegido (lançamento). · Until when the client is protected (new development). */
protectedUntil: string | null;
/** Quando o imóvel saiu do ar. · When the property went off the market. */
propertyOffMarketAt: string | null;
/** Quando foi criado (UTC). · When it was created (UTC). */
createdAt: string;
/** Última alteração (UTC). · Last change (UTC). */
updatedAt: string;
}
/** O desfecho. · The outcome. */
export interface PartnershipWriteResult {
/** O que aconteceu. · What happened. */
outcome: string;
/** Foi um ensaio. · It was a dry run. */
dryRun: boolean;
}
/** Uma pessoa da equipe. · A team member. */
export interface Member {
/** Id da pessoa na plataforma. · The person's platform id. */
accountId: string;
/** Nome. · Name. */
name: string | null;
/** E-mail — é por ele que o seu sistema reconhece o corretor. · E-mail — your system matches the broker by it. */
email: string | null;
/** Telefone. · Phone. */
phone: string | null;
/** Foto. · Photo. */
photoUrl: string | null;
/** CRECI (quem tem — a equipe também tem estagiários e administrativos). · Broker license (if any — the team also has interns and office staff). */
creci: string | null;
/** CRECI conferido. · License verified. */
creciVerified: boolean;
/** `active` ou `suspended`. · `active` or `suspended`. */
status: string;
/** Pode cadastrar imóvel e ser o responsável por ele. · Can register properties and be responsible for them. */
canCaptureProperties: boolean;
/** Supervisiona parte da equipe. · Supervises part of the team. */
isSupervisor: boolean;
/** O supervisor desta pessoa. · This person's supervisor. */
supervisorId: string | null;
/** Entra na distribuição de clientes. · Takes part in client distribution. */
receivesLeadDistribution: boolean;
/** Primeiro acesso. · First access. */
firstAccessAt: string | null;
}
/** A sincronização do feed do CRM. Nunca traz o link nem o token. · The CRM feed sync. Never includes the link or the token. */
export interface FeedSync {
/** O link do feed do CRM está cadastrado na conta. · The CRM feed link is set up on the account. */
configured: boolean;
/** O CRM do link (o formato do feed). · The CRM behind the link (the feed format). */
connector: string | null;
/** A sincronização de 6 em 6 horas está ligada. · The 6-hourly sync is on. */
autoSync: boolean;
/** Como terminou a última sincronização (a mesma situação da tela) — `QUEUED` enquanto ela anda. · How the last sync ended (the same status as the dashboard) — `QUEUED` while it runs. */
status: string | null;
/** A frase da última sincronização, a mesma da tela. · The last sync message, the same as in the dashboard. */
message: string | null;
/** Quando a última terminou. · When the last one finished. */
lastSyncAt: string | null;
/** Imóveis no feed na última leitura. · Properties in the feed at the last read. */
feedCount: number | null;
/** O que a última sincronização fez. · What the last sync did. */
counts: { created: number | null; updated: number | null; archived: number | null; skipped: number | null; unchanged: number | null; confirmed: number | null; };
/** Imóveis com campo editado na tela que o feed quis mudar — esperam a decisão em Imóveis › Importar. · Properties with a field edited in the dashboard that the feed tried to change — awaiting a decision under Properties › Import. */
conflicts: number;
/** A sincronização agendada por `POST /v1/feed/sync` para o fim da janela (nulo = nenhuma). · The sync scheduled by `POST /v1/feed/sync` for the end of the window (null = none). */
scheduledFor: string | null;
}
/** O desfecho. · The outcome. */
export interface FeedSyncResult {
/** `QUEUED` (sincroniza já) · `SCHEDULED` (agendada para o fim da janela de 10 minutos) · `ALREADY_SCHEDULED` (já havia uma agendada — nada novo). · `QUEUED` (syncs now) · `SCHEDULED` (scheduled for the end of the 10-minute window) · `ALREADY_SCHEDULED` (one was already scheduled — nothing new). */
outcome: "QUEUED" | "SCHEDULED" | "ALREADY_SCHEDULED";
/** Foi ensaio (nada enfileirado). · It was a dry run (nothing queued). */
dryRun: boolean;
}
/** Uma tipologia do empreendimento. · A unit type of the development. */
export interface Typology {
/** Id da tipologia. · Unit type id. */
id: string;
/** Nome. · Name. */
title: string | null;
/** Subtipo. · Subtype. */
type: string | null;
/** Situação. · Status. */
status: string;
/** Preço. · Price. */
salePrice: number | null;
/** Quartos. · Bedrooms. */
bedrooms: number | null;
/** Suítes. · Suites. */
suites: number | null;
/** Banheiros. · Bathrooms. */
bathrooms: number | null;
/** Vagas. · Parking spots. */
parkingSpots: number | null;
/** Área privativa, em m². · Private area, in m². */
area: number | null;
/** Área coberta, em m². · Covered area, in m². */
privateArea: number | null;
/** Capa. · Cover photo. */
coverPhoto: string | null;
/** Plantas. · Floor plans. */
floorPlans: Array;
/** Itens da unidade. · Unit features. */
unitFeatures: Array;
/** Unidades disponíveis. · Available units. */
unitsAvailable: number | null;
/** Unidades no total. · Total units. */
unitsTotal: number | null;
}
/** Um empreendimento do catálogo de lançamentos. · A development in the new-development catalog. */
export interface Launch {
/** Id do empreendimento. · Development id. */
id: string;
/** Nome. · Name. */
title: string | null;
/** Construtora. · Developer. */
developer: string | null;
/** Endereço até o bairro (a rua não sai no catálogo). · Address down to the neighborhood (the street is not in the catalog). */
address: AddressArea;
/** Estágio da obra. · Construction stage. */
constructionStage: "LAUNCH" | "OFF_PLAN" | "NEW" | "READY" | null;
/** Previsão de entrega. · Expected delivery. */
deliveryDate: string | null;
/** Andamento da obra, em %. · Construction progress, in %. */
constructionProgress: number | null;
/** Capa. · Cover photo. */
coverPhoto: string | null;
/** Itens do empreendimento. · Development amenities. */
amenities: Array;
/** Comissão para o corretor, em %. · Broker commission, in %. */
commissionPercent: number | null;
/** Menor preço entre as tipologias. · Lowest unit-type price. */
priceMin: number | null;
/** Maior preço. · Highest price. */
priceMax: number | null;
/** Quantas tipologias. · How many unit types. */
typologyCount: number;
/** As tipologias. · The unit types. */
typologies: Array;
}
/** Um proprietário da Captação. Os campos depois de `createdAt` só existem depois do aceite. · A Captação owner. The fields after `createdAt` only exist after accepting. */
export interface CaptacaoOffer {
/** Id do proprietário na mesa. · The owner's id on the desk. */
id: string;
/** Situação. · Status. */
status: string | null;
/** Venda ou locação. · Sale or rent. */
purpose: string | null;
/** Subtipo. · Subtype. */
propertyType: string | null;
/** Cidade. · City. */
city: string | null;
/** Identificador da cidade. · City identifier. */
citySlug: string | null;
/** Bairro. · Neighborhood. */
neighborhood: string | null;
/** Quartos. · Bedrooms. */
bedrooms: number | null;
/** Suítes. · Suites. */
suites: number | null;
/** Banheiros. · Bathrooms. */
bathrooms: number | null;
/** Vagas. · Parking spots. */
parkingSpots: number | null;
/** Área útil que o proprietário declarou. · Usable area declared by the owner. */
usableAreaDeclared: number | null;
/** Área total que o proprietário declarou. · Total area declared by the owner. */
areaDeclared: number | null;
/** Valor que o proprietário espera. · Price the owner expects. */
priceExpected: number | null;
/** Prazo para vender: `AGORA`, `TRES_MESES`, `SEIS_MESES` ou `PESQUISANDO`. · Time frame to sell: `AGORA` (now), `TRES_MESES` (3 months), `SEIS_MESES` (6 months) or `PESQUISANDO` (just researching). */
sellTimeframe: string | null;
/** Ocupação: `PROPRIO` (o dono mora), `ALUGADO` ou `VAZIO`. · Occupancy: `PROPRIO` (owner lives there), `ALUGADO` (rented) or `VAZIO` (empty). */
occupancy: string | null;
/** Quem cadastrou: `DONO`, `COPROPRIETARIO`, `REPRESENTANTE` ou `OUTRO` (não é o proprietário). · Who registered: `DONO` (owner), `COPROPRIETARIO` (co-owner), `REPRESENTANTE` (legal representative) or `OUTRO` (not the owner). */
ownerRelation: string | null;
/** Aceita exclusividade: `SIM` ou `NAO`. · Accepts exclusivity: `SIM` (yes) or `NAO` (no). */
exclusivityOpenness: string | null;
/** Disse que já anuncia em outro lugar. · Said it is already listed elsewhere. */
alreadyListedDeclared: boolean;
/** O preço do contato, em centavos — o que o aceite debita. · The contact price, in cents — what accepting debits. */
priceCents: number | null;
/** Até quando dá para aceitar (o prazo corre só das 9h às 17h, nos dias de atendimento). · Accept deadline (the clock runs only 9am–5pm on service days). */
deadline: string | null;
/** Quantos clientes da conta combinam. · How many account clients match. */
matchingClients: { city: number | null; neighborhood: number | null; };
/** A procura medida pela plataforma. · Demand measured by the platform. */
demand: { available: boolean; people: number | null; scope: string | null; scopeName: string | null; asOf: string | null; label: string | null; } | null;
/** Imóveis parecidos à venda no bairro. · Similar properties for sale in the neighborhood. */
stockNeighborhood: number | null;
/** Nome mascarado (antes do aceite). · Masked name (before accepting). */
ownerNameMasked: string | null;
/** Como o telefone do proprietário foi confirmado. · How the owner's phone was verified. */
ownerPhoneVerifiedVia: string | null;
/** Quando. · When. */
ownerPhoneVerifiedAt: string | null;
/** O contato já foi liberado para a conta (aceito). Antes disso, `owner` e `address` NÃO existem na resposta. · The contact was released to the account (accepted). Before that, `owner` and `address` do NOT exist in the response. */
revealed: boolean;
/** Quando foi criado (UTC). · When it was created (UTC). */
createdAt: string;
/** O proprietário (só depois do aceite). · The owner (only after accepting). */
owner?: { name: string | null; phone: string | null; email: string | null; };
/** O endereço (só depois do aceite). · The address (only after accepting). */
address?: { street: string | null; number: string | null; complement: string | null; neighborhood: string | null; city: string | null; };
/** Quando foi aceito. · When it was accepted. */
acceptedAt?: string | null;
/** Como foi aceito: pela tela ou pela API (com a chave, o IP e a versão do termo). · How it was accepted: in the dashboard or through the API (with the key, the IP and the terms version). */
acceptedVia?: { [key: string]: unknown; } | null;
/** Até quando cabe pedir devolução. · Refund request deadline. */
refundUntil?: string | null;
/** Quando foi devolvido. · When it was refunded. */
refundedAt?: string | null;
/** Quando o imóvel foi vendido. · When the property was sold. */
soldAt?: string | null;
/** Etapa na mesa. · Stage on the desk. */
stage?: string | null;
/** Etapa por extenso. · Stage, spelled out. */
stageLabel?: string | null;
/** Motivo da perda. · Lost reason. */
lostReason?: string | null;
/** Anotação. · Note. */
note?: string | null;
/** Aba da mesa: `ACTIVE`, `CAPTURED` ou `ARCHIVED`. · Desk tab: `ACTIVE`, `CAPTURED` or `ARCHIVED`. */
tab?: string | null;
}
/** O resumo da mesa. · Desk summary. */
export interface CaptacaoSummary {
/** Proprietários na vez da conta agora. · Owners offered to the account right now. */
pendingCount: number;
/** Crédito, em centavos. · Credit, in cents. */
balanceCents: number;
/** Assinatura do módulo em dia. · Module subscription active. */
subscriptionActive: boolean;
/** O módulo está valendo na plataforma. · The module is on for the platform. */
platformActive: boolean;
/** A conta pausou o recebimento. · The account paused receiving owners. */
paused: boolean;
/** Pausa automática (prazos vencidos em sequência). · Automatic pause (deadlines missed in a row). */
pausedAuto: boolean;
/** Prazos vencidos em sequência. · Deadlines missed in a row. */
expiredStreak: number;
/** A pausa automática vem depois de quantos. · Automatic pause after how many. */
autoPauseAfter: number | null;
/** Em ativação (antes da 1ª recarga). · In activation (before the first top-up). */
inActivation: boolean;
/** Aceites até a 1ª recarga. · Accepts until the first top-up. */
leadsToFirstCharge: number | null;
/** Recarga em andamento. · Top-up in progress. */
rechargePending: boolean;
/** Cidades atendidas. · Cities served. */
operatingCities: Array;
/** Finalidades atendidas. · Purposes served. */
purposes: Array;
/** Dias de atendimento. · Service days. */
serviceDays: Array;
}
/** O desfecho do aceite. · The accept outcome. */
export interface CaptacaoAcceptResult {
/** `ACCEPTED`, `ALREADY_ACCEPTED` (sem segundo débito) ou, em ensaio, `WOULD_ACCEPT`. · `ACCEPTED`, `ALREADY_ACCEPTED` (no second debit) or, in a dry run, `WOULD_ACCEPT`. */
outcome: string;
/** Foi um ensaio — nada foi debitado. · It was a dry run — nothing was debited. */
dryRun: boolean;
/** O valor debitado (ou que seria), em centavos. · The amount debited (or that would be), in cents. */
priceCents: number | null;
}
/** Um evento. · An event. */
export interface Event {
/** Id do evento (`evt_…`) — o mesmo `webhook-id` da entrega. Use-o para não processar duas vezes. · Event id (`evt_…`) — the same `webhook-id` as the delivery. Use it to avoid processing twice. */
id: string;
/** Tipo. · Type. */
type: "property.created" | "property.updated" | "property.deleted" | "property.restored" | "property.purged" | "lead.created" | "lead.updated" | "lead.deleted" | "lead.restored" | "lead.purged" | "radar.client_summary" | "partnership.created" | "partnership.updated" | "captacao.offer_received" | "captacao.offer_accepted" | "captacao.offer_withdrawn";
/** Quando foi registrado (UTC). · When it was recorded (UTC). */
createdAt: string;
/** O que mudou, enxuto: ids, o estado e `changedFields` (os NOMES dos campos que mudaram). Nunca nome, telefone, e-mail ou endereço — busque o detalhe pela leitura do recurso. · What changed, lean: ids, state and `changedFields` (the NAMES of the changed fields). Never name, phone, e-mail or address — fetch the detail by reading the resource. */
data: { [key: string]: unknown; };
}
/** Um endereço de webhook. O segredo nunca sai aqui. · A webhook endpoint. The secret never comes back here. */
export interface Webhook {
/** Id do endereço (`wh_…`). · Endpoint id (`wh_…`). */
id: string;
/** O endereço (só HTTPS). · The URL (HTTPS only). */
url: string;
/** Os tipos que ele recebe (vazio = todos os que a conta lê). · The types it receives (empty = all the account can read). */
types: Array<"property.created" | "property.updated" | "property.deleted" | "property.restored" | "property.purged" | "lead.created" | "lead.updated" | "lead.deleted" | "lead.restored" | "lead.purged" | "radar.client_summary" | "partnership.created" | "partnership.updated" | "captacao.offer_received" | "captacao.offer_accepted" | "captacao.offer_withdrawn">;
/** Descrição. · Description. */
description: string | null;
/** `ACTIVE` ou `DISABLED`. · `ACTIVE` or `DISABLED`. */
status: "ACTIVE" | "DISABLED";
/** Quando foi desligado. · When it was disabled. */
disabledAt: string | null;
/** `GONE_410` (o seu sistema respondeu 410), `FAILURE_RATE` (metade ou mais das entregas falhou em 48 h) ou `MANUAL`. · `GONE_410` (your system answered 410), `FAILURE_RATE` (half or more of the deliveries failed in 48 h) or `MANUAL`. */
disabledReason: string | null;
/** Última troca do segredo. · Last secret rotation. */
secretRotatedAt: string | null;
/** Até quando o segredo anterior ainda assina junto (24 h depois da troca). · Until when the previous secret still signs alongside (24 h after rotation). */
previousSecretValidUntil: string | null;
/** Quando foi criado (UTC). · When it was created (UTC). */
createdAt: string;
/** Última alteração (UTC). · Last change (UTC). */
updatedAt: string;
}
/** Um endereço novo. · A new endpoint. */
export interface WebhookCreate {
/** O endereço, só HTTPS e público. Credencial na URL é recusada. · The URL, HTTPS and public only. Credentials in the URL are refused. */
url: string;
/** Os tipos (ausente = todos os que a conta lê). · The types (absent = all the account can read). */
types?: Array<"property.created" | "property.updated" | "property.deleted" | "property.restored" | "property.purged" | "lead.created" | "lead.updated" | "lead.deleted" | "lead.restored" | "lead.purged" | "radar.client_summary" | "partnership.created" | "partnership.updated" | "captacao.offer_received" | "captacao.offer_accepted" | "captacao.offer_withdrawn">;
/** Descrição. · Description. */
description?: string | null;
}
/** O que mudar no endereço. · What to change on the endpoint. */
export interface WebhookUpdate {
/** O endereço. · The URL. */
url?: string;
/** Os tipos. · The types. */
types?: Array<"property.created" | "property.updated" | "property.deleted" | "property.restored" | "property.purged" | "lead.created" | "lead.updated" | "lead.deleted" | "lead.restored" | "lead.purged" | "radar.client_summary" | "partnership.created" | "partnership.updated" | "captacao.offer_received" | "captacao.offer_accepted" | "captacao.offer_withdrawn">;
/** Descrição. · Description. */
description?: string | null;
/** `ACTIVE` religa (limpa o motivo do desligamento) e `DISABLED` desliga. · `ACTIVE` re-enables (clears the disable reason) and `DISABLED` disables. */
status?: "ACTIVE" | "DISABLED";
}
/** Uma entrega de evento a um endereço. · One event delivery to an endpoint. */
export interface Delivery {
/** Id da entrega (`dlv_…`). · Delivery id (`dlv_…`). */
id: string;
/** O evento entregue. · The delivered event. */
eventId: string | null;
/** Tipo do evento. · Event type. */
type: string | null;
/** `PENDING`, `RETRYING`, `DELIVERED`, `FAILED` (esgotou as tentativas) ou `SKIPPED` (o endereço estava desligado). · `PENDING`, `RETRYING`, `DELIVERED`, `FAILED` (out of retries) or `SKIPPED` (the endpoint was disabled). */
status: string;
/** Tentativas feitas. · Attempts made. */
attempts: number;
/** Último código HTTP do seu sistema. · Last HTTP status from your system. */
lastStatusCode: number | null;
/** Último erro. · Last error. */
lastError: string | null;
/** Última tentativa. · Last attempt. */
lastAttemptAt: string | null;
/** Próxima tentativa (1 min, 5 min, 30 min, 2 h, 6 h e 12 h). · Next attempt (1 min, 5 min, 30 min, 2 h, 6 h and 12 h). */
nextAttemptAt: string | null;
/** Quando foi entregue. · When it was delivered. */
deliveredAt: string | null;
/** Quando a entrega foi aberta. · When the delivery was opened. */
createdAt: string | null;
}
/** O resultado do evento de teste (`webhook.test`). · The test event result (`webhook.test`). */
export interface WebhookTestResult {
/** O seu sistema respondeu 2xx. · Your system answered 2xx. */
delivered: boolean;
/** O código que ele respondeu. · The status it answered. */
statusCode: number | null;
/** O motivo da falha. · The failure reason. */
error: string | null;
/** Tempo da entrega, em ms. · Delivery time, in ms. */
ms: number | null;
}
/** O lote recebido. · The received batch. */
export interface BatchCreated {
/** Id do lote (`b-…`). · Batch id (`b-…`). */
id: string;
/** `properties` ou `leads`. · `properties` or `leads`. */
type: "properties" | "leads";
/** `QUEUED`, ou `DONE` quando nenhum item era válido. · `QUEUED`, or `DONE` when no item was valid. */
status: "QUEUED" | "RUNNING" | "DONE";
/** Itens recebidos. · Items received. */
total: number;
/** Itens que seguiram para o processamento. · Items queued for processing. */
accepted: number;
/** Itens recusados na forma (veja o resultado). · Items rejected on shape (see the result). */
rejected: number;
/** O lote inteiro é um ensaio. · The whole batch is a dry run. */
dryRun: boolean;
}
/** O resultado de um item. · One item result. */
export interface BatchItem {
/** Posição no pedido. · Position in the request. */
index: number;
/** O código do item. · The item's code. */
externalRef: string | null;
/** O desfecho do item — os mesmos do PUT pelo código, mais `PENDING` (ainda na fila) e `REJECTED`. · The item's outcome — the same as the PUT by code, plus `PENDING` (still queued) and `REJECTED`. */
outcome: string;
/** O id do imóvel ou cliente. · The property or client id. */
id: string | null;
/** O código de erro, quando recusado. · The error code, when refused. */
code: string | null;
/** Detalhe. · Detail. */
detail: string | null;
/** Os problemas de forma. · Shape problems. */
invalidParams: Array<{ [key: string]: unknown; }> | null;
/** A galeria (imóveis). · The gallery (properties). */
photos: string | null;
}
/** Um lote, com o desfecho de cada item. · A batch, with each item outcome. */
export interface Batch {
/** Id do lote. · Batch id. */
id: string;
/** `properties` ou `leads`. · `properties` or `leads`. */
type: "properties" | "leads";
/** `QUEUED`, `RUNNING` ou `DONE`. · `QUEUED`, `RUNNING` or `DONE`. */
status: "QUEUED" | "RUNNING" | "DONE";
/** Ensaio. · Dry run. */
dryRun: boolean;
/** Itens. · Items. */
total: number | null;
/** Itens com desfecho. · Items with an outcome. */
processed: number | null;
/** Contagem por desfecho (`CREATED`, `UPDATED`, `REJECTED`…). · Count per outcome (`CREATED`, `UPDATED`, `REJECTED`…). */
counts: Record;
/** Quando foi recebido. · When it was received. */
createdAt: string | null;
/** Quando começou. · When it started. */
startedAt: string | null;
/** Quando terminou. · When it finished. */
finishedAt: string | null;
/** O desfecho de cada item, na ordem do pedido. · Each item outcome, in request order. */
results: Array;
}
/** O desfecho de um imóvel na confirmação. · One property outcome in the confirmation. */
export interface ConfirmItem {
/** O id pedido (quando o pedido veio por `ids`). · The requested id (when the request used `ids`). */
id?: string;
/** O código pedido (quando o pedido veio por `refs`). · The requested code (when the request used `refs`). */
ref?: string;
/** O imóvel achado (nulo quando não achou). · The property found (null when not found). */
propertyId: string | null;
/** `CONFIRMED`, `ALREADY_CONFIRMED` (há menos de 24 h — não regrava) ou `NOT_FOUND`. · `CONFIRMED`, `ALREADY_CONFIRMED` (less than 24 h ago — not rewritten) or `NOT_FOUND`. */
outcome: "CONFIRMED" | "ALREADY_CONFIRMED" | "NOT_FOUND";
}
/** O erro da API (application/problem+json). Decida pelo `code`, nunca pelo texto. */
export class ImobyFlowError extends Error {
readonly status: number;
readonly code: string | null;
readonly title: string | null;
readonly type: string | null;
readonly requestId: string | null;
readonly detail: string | null;
readonly invalidParams: Array<{ name: string; reason: string }>;
readonly body: unknown;
constructor(status: number, body: unknown, requestId: string | null) {
const p = (body && typeof body === 'object' ? body : {}) as Record;
super(`${status} ${String(p.code ?? '')}: ${String(p.title ?? '')}`.trim());
this.name = 'ImobyFlowError';
this.status = status;
this.code = typeof p.code === 'string' ? p.code : null;
this.title = typeof p.title === 'string' ? p.title : null;
this.type = typeof p.type === 'string' ? p.type : null;
this.requestId = typeof p.requestId === 'string' ? p.requestId : requestId;
this.detail = typeof p.detail === 'string' ? p.detail : null;
this.invalidParams = Array.isArray(p.invalidParams) ? (p.invalidParams as Array<{ name: string; reason: string }>) : [];
this.body = body;
}
}
export interface ImobyFlowOptions {
/** Padrão / default: https://api.imobyflow.com.br/v1 */
baseUrl?: string;
/** `pt-BR` (padrão) ou `en`: a língua dos rótulos e das mensagens de erro. */
language?: 'pt-BR' | 'en';
/** Tempo máximo de cada tentativa, em ms (padrão 30000). */
timeoutMs?: number;
/** Novas tentativas em 429, 502, 503, 504 e falha de rede (padrão 2). */
maxRetries?: number;
/** A primeira espera, em ms; dobra a cada tentativa (padrão 500). */
retryBaseMs?: number;
/** Outro `fetch` (testes, proxy). */
fetch?: typeof fetch;
}
interface OpMeta {
method: string;
path: string;
query: readonly string[];
dryRun: boolean;
idempotency: boolean;
}
const RETRY_STATUS = new Set([429, 502, 503, 504]);
const espera = (ms: number) => new Promise((r) => setTimeout(r, ms));
export class ImobyFlow {
readonly baseUrl: string;
readonly language: string;
readonly timeoutMs: number;
readonly maxRetries: number;
readonly retryBaseMs: number;
#key: string;
#fetch: typeof fetch;
constructor(apiKey: string, options: ImobyFlowOptions = {}) {
// "Bearer " colado junto sai ANTES de conferir: é o erro de cópia mais comum.
const chave = String(apiKey ?? '').trim().replace(/^bearer\s+/i, '');
if (!chave || /\s/.test(chave)) throw new Error('ImobyFlow: chave da API ausente ou inválida.');
this.#key = chave;
this.baseUrl = (options.baseUrl ?? "https://api.imobyflow.com.br/v1").replace(/\/+$/, '');
this.language = options.language ?? 'pt-BR';
this.timeoutMs = options.timeoutMs ?? 30000;
this.maxRetries = options.maxRetries ?? 2;
this.retryBaseMs = options.retryBaseMs ?? 500;
this.#fetch = options.fetch ?? fetch;
}
/** Chamada crua, para quem precisar de uma rota antes de ela entrar no SDK. */
async call(op: OpMeta, path: Record, options: Record, body?: unknown): Promise {
let caminho = op.path;
for (const [nome, valor] of Object.entries(path)) {
if (valor === undefined || valor === null || String(valor) === '') throw new Error(`ImobyFlow: ${nome} é obrigatório.`);
caminho = caminho.replace(`{${nome}}`, encodeURIComponent(String(valor)));
}
const qs = new URLSearchParams();
for (const nome of op.query) {
const v = options[nome];
if (v !== undefined && v !== null && v !== '') qs.set(nome, String(v));
}
if (op.dryRun && options.dryRun) qs.set('dryRun', 'true');
const url = this.baseUrl + caminho + (qs.toString() ? `?${qs}` : '');
const headers: Record = {
Authorization: `Bearer ${this.#key}`,
Accept: 'application/json',
'Accept-Language': this.language,
'User-Agent': `imobyflow-sdk-typescript/${API_VERSION}`,
};
// A MESMA chave em todas as tentativas: a re-tentativa devolve a resposta da primeira.
const chave = op.idempotency ? String(options.idempotencyKey ?? randomUUID()) : undefined;
if (chave) headers['Idempotency-Key'] = chave;
if (body !== undefined) headers['Content-Type'] = 'application/json';
const podeRepetir = op.method === 'GET' || Boolean(chave);
for (let tentativa = 0; ; tentativa++) {
const abort = new AbortController();
const relogio = setTimeout(() => abort.abort(), this.timeoutMs);
let res: Response;
try {
res = await this.#fetch(url, {
method: op.method,
headers,
body: body === undefined ? undefined : JSON.stringify(body),
signal: abort.signal,
});
} catch (erro) {
clearTimeout(relogio);
if (podeRepetir && tentativa < this.maxRetries) {
await espera(this.retryBaseMs * 2 ** tentativa);
continue;
}
throw erro;
}
clearTimeout(relogio);
const texto = await res.text();
let dado: unknown = null;
try {
dado = texto ? JSON.parse(texto) : null;
} catch {
dado = texto;
}
if (res.ok) return dado;
if (podeRepetir && RETRY_STATUS.has(res.status) && tentativa < this.maxRetries) {
const depois = Number(res.headers.get('retry-after'));
await espera(Number.isFinite(depois) && depois > 0 ? depois * 1000 : this.retryBaseMs * 2 ** tentativa);
continue;
}
throw new ImobyFlowError(res.status, dado, res.headers.get('x-request-id'));
}
}
/** Quem sou eu · Who am I
* `GET /v1/me` */
getMe(): Promise<{ data: Me; }> {
return this.call({"method":"GET","path":"/me","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Me; }>;
}
/** Tipos de imóvel · Property types
* `GET /v1/reference/property-types` */
getPropertyTypes(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/reference/property-types","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Finalidades · Purposes
* `GET /v1/reference/purposes` */
getPurposes(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/reference/purposes","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Status do imóvel · Property statuses
* `GET /v1/reference/property-statuses` */
getPropertyStatuses(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/reference/property-statuses","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Etapas do cliente · Client stages
* `GET /v1/reference/lead-statuses` */
getLeadStatuses(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/reference/lead-statuses","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Etapas da parceria · Partnership stages
* `GET /v1/reference/partnership-statuses` */
getPartnershipStatuses(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/reference/partnership-statuses","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Estágios da obra · Construction stages
* `GET /v1/reference/construction-stages` */
getConstructionStages(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/reference/construction-stages","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Permissões · Permissions
* `GET /v1/reference/scopes` */
getScopes(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/reference/scopes","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Tipos de evento · Event types
* `GET /v1/reference/event-types` */
getEventTypes(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/reference/event-types","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Cidades · Cities
* `GET /v1/geo/cities` */
listCities(options: { uf?: string; q?: string; limit?: number; cursor?: string } = {}): Promise<{ data: Array; nextCursor: string | null; total: number; }> {
return this.call({"method":"GET","path":"/geo/cities","query":["uf","q","limit","cursor"],"dryRun":false,"idempotency":false}, { }, options) as Promise<{ data: Array; nextCursor: string | null; total: number; }>;
}
/** Todas as páginas de `listCities`, item a item · every page of `listCities`, item by item. */
async *listCitiesAll(options: Omit<{ uf?: string; q?: string; limit?: number; cursor?: string }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listCities({ ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Bairros de uma cidade · A city's neighborhoods
* `GET /v1/geo/cities/{cityId}/neighborhoods` */
listNeighborhoods(cityId: string, options: { limit?: number; cursor?: string } = {}): Promise<{ data: Array; nextCursor: string | null; total: number; }> {
return this.call({"method":"GET","path":"/geo/cities/{cityId}/neighborhoods","query":["limit","cursor"],"dryRun":false,"idempotency":false}, { cityId }, options) as Promise<{ data: Array; nextCursor: string | null; total: number; }>;
}
/** Todas as páginas de `listNeighborhoods`, item a item · every page of `listNeighborhoods`, item by item. */
async *listNeighborhoodsAll(cityId: string, options: Omit<{ limit?: number; cursor?: string }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listNeighborhoods(cityId, { ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Listar a carteira · List the portfolio
* `GET /v1/properties` — permissão `properties:read` */
listProperties(options: { limit?: number; cursor?: string; status?: "ACTIVE" | "INACTIVE" | "SOLD" | "RENTED" | "DELETED"; purpose?: "VENDA" | "LOCACAO"; type?: "APARTAMENTO" | "CASA_RUA" | "CASA_CONDOMINIO" | "CASA_VILA" | "STUDIO" | "FLAT" | "COBERTURA" | "SALA_COMERCIAL" | "LOJA_PONTO" | "GALPAO" | "PREDIO" | "TERRENO_RUA" | "TERRENO_CONDOMINIO" | "CHACARA_SITIO" | "FAZENDA"; citySlug?: string; updatedSince?: string; radar?: "pending" | "ready" } = {}): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/properties","query":["limit","cursor","status","purpose","type","citySlug","updatedSince","radar"],"dryRun":false,"idempotency":false}, { }, options) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Todas as páginas de `listProperties`, item a item · every page of `listProperties`, item by item. */
async *listPropertiesAll(options: Omit<{ limit?: number; cursor?: string; status?: "ACTIVE" | "INACTIVE" | "SOLD" | "RENTED" | "DELETED"; purpose?: "VENDA" | "LOCACAO"; type?: "APARTAMENTO" | "CASA_RUA" | "CASA_CONDOMINIO" | "CASA_VILA" | "STUDIO" | "FLAT" | "COBERTURA" | "SALA_COMERCIAL" | "LOJA_PONTO" | "GALPAO" | "PREDIO" | "TERRENO_RUA" | "TERRENO_CONDOMINIO" | "CHACARA_SITIO" | "FAZENDA"; citySlug?: string; updatedSince?: string; radar?: "pending" | "ready" }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listProperties({ ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Um imóvel pelo seu código · One property by your code
* `GET /v1/properties/by-ref/{ref}` — permissão `properties:read` */
getPropertyByRef(ref: string): Promise<{ data: Property; }> {
return this.call({"method":"GET","path":"/properties/by-ref/{ref}","query":[],"dryRun":false,"idempotency":false}, { ref }, {}) as Promise<{ data: Property; }>;
}
/** Um imóvel · One property
* `GET /v1/properties/{propertyId}` — permissão `properties:read` */
getProperty(propertyId: string): Promise<{ data: Property; }> {
return this.call({"method":"GET","path":"/properties/{propertyId}","query":[],"dryRun":false,"idempotency":false}, { propertyId }, {}) as Promise<{ data: Property; }>;
}
/** Oportunidades de um imóvel · A property's opportunities
* `GET /v1/properties/{propertyId}/matches` — permissão `radar:read` */
listPropertyMatches(propertyId: string): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/properties/{propertyId}/matches","query":[],"dryRun":false,"idempotency":false}, { propertyId }, {}) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Listar clientes · List clients
* `GET /v1/leads` — permissão `leads:read` */
listLeads(options: { limit?: number; cursor?: string; state?: "ACTIVE" | "ARCHIVED" | "DELETED"; status?: "NEW" | "ATTENDING" | "PROPOSAL" | "WON" | "LOST"; ownerAccountId?: string; updatedSince?: string; radar?: "pending" | "ready" } = {}): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/leads","query":["limit","cursor","state","status","ownerAccountId","updatedSince","radar"],"dryRun":false,"idempotency":false}, { }, options) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Todas as páginas de `listLeads`, item a item · every page of `listLeads`, item by item. */
async *listLeadsAll(options: Omit<{ limit?: number; cursor?: string; state?: "ACTIVE" | "ARCHIVED" | "DELETED"; status?: "NEW" | "ATTENDING" | "PROPOSAL" | "WON" | "LOST"; ownerAccountId?: string; updatedSince?: string; radar?: "pending" | "ready" }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listLeads({ ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Um cliente · One client
* `GET /v1/leads/{leadId}` — permissão `leads:read` */
getLead(leadId: string): Promise<{ data: Lead; }> {
return this.call({"method":"GET","path":"/leads/{leadId}","query":[],"dryRun":false,"idempotency":false}, { leadId }, {}) as Promise<{ data: Lead; }>;
}
/** Um cliente pelo seu código · One client by your code
* `GET /v1/leads/by-ref/{ref}` — permissão `leads:read` */
getLeadByRef(ref: string): Promise<{ data: Lead; }> {
return this.call({"method":"GET","path":"/leads/by-ref/{ref}","query":[],"dryRun":false,"idempotency":false}, { ref }, {}) as Promise<{ data: Lead; }>;
}
/** Oportunidades de um cliente · A client's opportunities
* `GET /v1/leads/{leadId}/matches` — permissão `radar:read` */
listLeadMatches(leadId: string): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/leads/{leadId}/matches","query":[],"dryRun":false,"idempotency":false}, { leadId }, {}) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Oportunidades da conta · The account's opportunities
* `GET /v1/matches` — permissão `radar:read` */
listMatches(options: { limit?: number; cursor?: string; status?: "NEW" | "FAVORITED" | "ARCHIVED" | "REQUESTED"; scope?: "INTERNAL" | "NETWORK" | "LAUNCH"; ownerAccountId?: string } = {}): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/matches","query":["limit","cursor","status","scope","ownerAccountId"],"dryRun":false,"idempotency":false}, { }, options) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Todas as páginas de `listMatches`, item a item · every page of `listMatches`, item by item. */
async *listMatchesAll(options: Omit<{ limit?: number; cursor?: string; status?: "NEW" | "FAVORITED" | "ARCHIVED" | "REQUESTED"; scope?: "INTERNAL" | "NETWORK" | "LAUNCH"; ownerAccountId?: string }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listMatches({ ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Parcerias da equipe · The team's partnerships
* `GET /v1/partnerships` — permissão `partnerships:read` */
listPartnerships(options: { status?: "PENDING" | "ACCEPTED" | "DECLINED" | "CANCELLED" | "LEAD_REGISTERED" | "CONTACTED" | "NEGOTIATING" | "PROPOSAL" | "WON" | "LOST"; updatedSince?: string } = {}): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/partnerships","query":["status","updatedSince"],"dryRun":false,"idempotency":false}, { }, options) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Uma parceria · One partnership
* `GET /v1/partnerships/{partnershipId}` — permissão `partnerships:read` */
getPartnership(partnershipId: string): Promise<{ data: Partnership; }> {
return this.call({"method":"GET","path":"/partnerships/{partnershipId}","query":[],"dryRun":false,"idempotency":false}, { partnershipId }, {}) as Promise<{ data: Partnership; }>;
}
/** A equipe · The team
* `GET /v1/team` — permissão `team:read` */
listTeam(): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/team","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Estado da sincronização do feed · Feed sync status
* `GET /v1/feed` — permissão `properties:read` */
getFeed(): Promise<{ data: FeedSync; }> {
return this.call({"method":"GET","path":"/feed","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: FeedSync; }>;
}
/** Sincronizar o feed agora · Sync the feed now
* `POST /v1/feed/sync` — permissão `properties:write` — aceita `dryRun` */
syncFeed(options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: FeedSync; result: FeedSyncResult; }> {
return this.call({"method":"POST","path":"/feed/sync","query":[],"dryRun":true,"idempotency":true}, { }, options) as Promise<{ data: FeedSync; result: FeedSyncResult; }>;
}
/** Lançamentos da cidade · The city's new developments
* `GET /v1/launches` — permissão `launches:read` */
listLaunches(options: { limit?: number; cursor?: string; citySlug?: string; neighborhood?: string; type?: "APARTAMENTO" | "CASA_RUA" | "CASA_CONDOMINIO" | "CASA_VILA" | "STUDIO" | "FLAT" | "COBERTURA" | "SALA_COMERCIAL" | "LOJA_PONTO" | "GALPAO" | "PREDIO" | "TERRENO_RUA" | "TERRENO_CONDOMINIO" | "CHACARA_SITIO" | "FAZENDA"; stage?: "LAUNCH" | "OFF_PLAN" | "NEW" | "READY"; priceMin?: number; priceMax?: number; q?: string } = {}): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/launches","query":["limit","cursor","citySlug","neighborhood","type","stage","priceMin","priceMax","q"],"dryRun":false,"idempotency":false}, { }, options) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Todas as páginas de `listLaunches`, item a item · every page of `listLaunches`, item by item. */
async *listLaunchesAll(options: Omit<{ limit?: number; cursor?: string; citySlug?: string; neighborhood?: string; type?: "APARTAMENTO" | "CASA_RUA" | "CASA_CONDOMINIO" | "CASA_VILA" | "STUDIO" | "FLAT" | "COBERTURA" | "SALA_COMERCIAL" | "LOJA_PONTO" | "GALPAO" | "PREDIO" | "TERRENO_RUA" | "TERRENO_CONDOMINIO" | "CHACARA_SITIO" | "FAZENDA"; stage?: "LAUNCH" | "OFF_PLAN" | "NEW" | "READY"; priceMin?: number; priceMax?: number; q?: string }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listLaunches({ ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Criar ou atualizar pelo seu código · Create or update by your code
* `PUT /v1/properties/by-ref/{ref}` — permissão `properties:write` — aceita `dryRun` */
putPropertyByRef(ref: string, body: PropertyInput, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Property; result: PropertyWriteResult; }> {
return this.call({"method":"PUT","path":"/properties/by-ref/{ref}","query":[],"dryRun":true,"idempotency":true}, { ref }, options, body) as Promise<{ data: Property; result: PropertyWriteResult; }>;
}
/** Cadastrar um imóvel · Create a property
* `POST /v1/properties` — permissão `properties:write` — aceita `dryRun` */
createProperty(body: PropertyInput, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Property; result: PropertyWriteResult; }> {
return this.call({"method":"POST","path":"/properties","query":[],"dryRun":true,"idempotency":true}, { }, options, body) as Promise<{ data: Property; result: PropertyWriteResult; }>;
}
/** Alterar parte de um imóvel · Partially update a property
* `PATCH /v1/properties/{propertyId}` — permissão `properties:write` — aceita `dryRun` */
patchProperty(propertyId: string, body: PropertyInput, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Property; result: PropertyWriteResult; }> {
return this.call({"method":"PATCH","path":"/properties/{propertyId}","query":[],"dryRun":true,"idempotency":true}, { propertyId }, options, body) as Promise<{ data: Property; result: PropertyWriteResult; }>;
}
/** Mudar o status · Change the status
* `POST /v1/properties/{propertyId}/status` — permissão `properties:write` — aceita `dryRun` */
setPropertyStatus(propertyId: string, body: { status: "ACTIVE" | "INACTIVE" | "SOLD" | "RENTED"; }, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Property; result: PropertyWriteResult; }> {
return this.call({"method":"POST","path":"/properties/{propertyId}/status","query":[],"dryRun":true,"idempotency":true}, { propertyId }, options, body) as Promise<{ data: Property; result: PropertyWriteResult; }>;
}
/** Confirmar disponibilidade em lote · Confirm availability in bulk
* `POST /v1/properties/confirm` — permissão `properties:write` — aceita `dryRun` */
confirmProperties(body: { ids?: Array; refs?: Array; }, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Array; result: { dryRun: boolean; summary: Record; }; }> {
return this.call({"method":"POST","path":"/properties/confirm","query":[],"dryRun":true,"idempotency":true}, { }, options, body) as Promise<{ data: Array; result: { dryRun: boolean; summary: Record; }; }>;
}
/** Criar, atualizar ou vincular pelo seu código · Create, update or link by your code
* `PUT /v1/leads/by-ref/{ref}` — permissão `leads:write` — aceita `dryRun` */
putLeadByRef(ref: string, body: LeadInput, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Lead; result: LeadWriteResult; }> {
return this.call({"method":"PUT","path":"/leads/by-ref/{ref}","query":[],"dryRun":true,"idempotency":true}, { ref }, options, body) as Promise<{ data: Lead; result: LeadWriteResult; }>;
}
/** Cadastrar um cliente · Create a client
* `POST /v1/leads` — permissão `leads:write` — aceita `dryRun` */
createLead(body: LeadInput, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Lead; result: LeadWriteResult; }> {
return this.call({"method":"POST","path":"/leads","query":[],"dryRun":true,"idempotency":true}, { }, options, body) as Promise<{ data: Lead; result: LeadWriteResult; }>;
}
/** Alterar parte de um cliente · Partially update a client
* `PATCH /v1/leads/{leadId}` — permissão `leads:write` — aceita `dryRun` */
patchLead(leadId: string, body: LeadInput, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Lead; result: LeadWriteResult; }> {
return this.call({"method":"PATCH","path":"/leads/{leadId}","query":[],"dryRun":true,"idempotency":true}, { leadId }, options, body) as Promise<{ data: Lead; result: LeadWriteResult; }>;
}
/** Arquivar ou reativar · Archive or reactivate
* `POST /v1/leads/{leadId}/state` — permissão `leads:write` — aceita `dryRun` */
setLeadState(leadId: string, body: { state: "ACTIVE" | "ARCHIVED"; }, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Lead; result: LeadWriteResult; }> {
return this.call({"method":"POST","path":"/leads/{leadId}/state","query":[],"dryRun":true,"idempotency":true}, { leadId }, options, body) as Promise<{ data: Lead; result: LeadWriteResult; }>;
}
/** Registrar um atendimento · Log an interaction
* `POST /v1/leads/{leadId}/interactions` — permissão `leads:write` — aceita `dryRun` */
addLeadInteraction(leadId: string, body: { type: "CONTACT" | "VISIT" | "PROPOSAL" | "NOTE"; note?: string; at?: string; }, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Lead; result: LeadWriteResult; }> {
return this.call({"method":"POST","path":"/leads/{leadId}/interactions","query":[],"dryRun":true,"idempotency":true}, { leadId }, options, body) as Promise<{ data: Lead; result: LeadWriteResult; }>;
}
/** Mandar para a lixeira · Move to the trash
* `DELETE /v1/properties/{propertyId}` — permissão `properties:write` — aceita `dryRun` */
deleteProperty(propertyId: string, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Property; result: PropertyWriteResult; }> {
return this.call({"method":"DELETE","path":"/properties/{propertyId}","query":[],"dryRun":true,"idempotency":true}, { propertyId }, options) as Promise<{ data: Property; result: PropertyWriteResult; }>;
}
/** Mandar para a lixeira · Move to the trash
* `DELETE /v1/leads/{leadId}` — permissão `leads:write` — aceita `dryRun` */
deleteLead(leadId: string, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Lead; result: LeadWriteResult; }> {
return this.call({"method":"DELETE","path":"/leads/{leadId}","query":[],"dryRun":true,"idempotency":true}, { leadId }, options) as Promise<{ data: Lead; result: LeadWriteResult; }>;
}
/** Descartar oportunidade · Dismiss an opportunity
* `POST /v1/matches/{matchId}/dismiss` — permissão `radar:write` — aceita `dryRun` */
dismissMatch(matchId: string, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Match; result: MatchWriteResult; }> {
return this.call({"method":"POST","path":"/matches/{matchId}/dismiss","query":[],"dryRun":true,"idempotency":true}, { matchId }, options) as Promise<{ data: Match; result: MatchWriteResult; }>;
}
/** Restaurar oportunidade · Restore an opportunity
* `POST /v1/matches/{matchId}/restore` — permissão `radar:write` — aceita `dryRun` */
restoreMatch(matchId: string, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Match; result: MatchWriteResult; }> {
return this.call({"method":"POST","path":"/matches/{matchId}/restore","query":[],"dryRun":true,"idempotency":true}, { matchId }, options) as Promise<{ data: Match; result: MatchWriteResult; }>;
}
/** Mover a etapa da parceria · Move the partnership stage
* `POST /v1/partnerships/{partnershipId}/status` — permissão `partnerships:write` — aceita `dryRun` */
setPartnershipStatus(partnershipId: string, body: { status: "PENDING" | "ACCEPTED" | "DECLINED" | "CANCELLED" | "LEAD_REGISTERED" | "CONTACTED" | "NEGOTIATING" | "PROPOSAL" | "WON" | "LOST"; }, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: Partnership; result: PartnershipWriteResult; }> {
return this.call({"method":"POST","path":"/partnerships/{partnershipId}/status","query":[],"dryRun":true,"idempotency":true}, { partnershipId }, options, body) as Promise<{ data: Partnership; result: PartnershipWriteResult; }>;
}
/** Proprietários na vez da conta · Owners offered to the account
* `GET /v1/captacao/offers` — permissão `captacao:read` */
listCaptacaoOffers(): Promise<{ data: Array; summary: CaptacaoSummary; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/captacao/offers","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; summary: CaptacaoSummary; nextCursor: string | null; }>;
}
/** Um proprietário · One owner
* `GET /v1/captacao/offers/{offerId}` — permissão `captacao:read` */
getCaptacaoOffer(offerId: string): Promise<{ data: CaptacaoOffer; }> {
return this.call({"method":"GET","path":"/captacao/offers/{offerId}","query":[],"dryRun":false,"idempotency":false}, { offerId }, {}) as Promise<{ data: CaptacaoOffer; }>;
}
/** Proprietários aceitos · Accepted owners
* `GET /v1/captacao/owners` — permissão `captacao:read` */
listCaptacaoOwners(options: { tab?: "ACTIVE" | "CAPTURED" | "ARCHIVED"; cursor?: string } = {}): Promise<{ data: Array; nextCursor: string | null; total: number | null; counts: Record | null; }> {
return this.call({"method":"GET","path":"/captacao/owners","query":["tab","cursor"],"dryRun":false,"idempotency":false}, { }, options) as Promise<{ data: Array; nextCursor: string | null; total: number | null; counts: Record | null; }>;
}
/** Todas as páginas de `listCaptacaoOwners`, item a item · every page of `listCaptacaoOwners`, item by item. */
async *listCaptacaoOwnersAll(options: Omit<{ tab?: "ACTIVE" | "CAPTURED" | "ARCHIVED"; cursor?: string }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listCaptacaoOwners({ ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Aceitar um proprietário · Accept an owner
* `POST /v1/captacao/offers/{offerId}/accept` — permissão `captacao:accept` — aceita `dryRun` */
acceptCaptacaoOffer(offerId: string, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: CaptacaoOffer; result: CaptacaoAcceptResult; }> {
return this.call({"method":"POST","path":"/captacao/offers/{offerId}/accept","query":[],"dryRun":true,"idempotency":true}, { offerId }, options) as Promise<{ data: CaptacaoOffer; result: CaptacaoAcceptResult; }>;
}
/** O que mudou · What changed
* `GET /v1/events` — permissão `events:read` */
listEvents(options: { limit?: number; cursor?: string; since?: string; types?: string } = {}): Promise<{ data: Array; nextCursor: string; hasMore: boolean; }> {
return this.call({"method":"GET","path":"/events","query":["limit","cursor","since","types"],"dryRun":false,"idempotency":false}, { }, options) as Promise<{ data: Array; nextCursor: string; hasMore: boolean; }>;
}
/** Todas as páginas de `listEvents`, item a item · every page of `listEvents`, item by item. */
async *listEventsAll(options: Omit<{ limit?: number; cursor?: string; since?: string; types?: string }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listEvents({ ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Endereços cadastrados · Registered endpoints
* `GET /v1/webhooks` — permissão `webhooks:manage` */
listWebhooks(): Promise<{ data: Array; }> {
return this.call({"method":"GET","path":"/webhooks","query":[],"dryRun":false,"idempotency":false}, { }, {}) as Promise<{ data: Array; }>;
}
/** Cadastrar um endereço · Register an endpoint
* `POST /v1/webhooks` — permissão `webhooks:manage` */
createWebhook(body: WebhookCreate): Promise<{ data: Webhook; secret: string; }> {
return this.call({"method":"POST","path":"/webhooks","query":[],"dryRun":false,"idempotency":false}, { }, {}, body) as Promise<{ data: Webhook; secret: string; }>;
}
/** Alterar um endereço · Update an endpoint
* `PATCH /v1/webhooks/{webhookId}` — permissão `webhooks:manage` */
updateWebhook(webhookId: string, body: WebhookUpdate, options: { idempotencyKey?: string } = {}): Promise<{ data: Webhook; }> {
return this.call({"method":"PATCH","path":"/webhooks/{webhookId}","query":[],"dryRun":false,"idempotency":true}, { webhookId }, options, body) as Promise<{ data: Webhook; }>;
}
/** Apagar um endereço · Delete an endpoint
* `DELETE /v1/webhooks/{webhookId}` — permissão `webhooks:manage` */
deleteWebhook(webhookId: string, options: { idempotencyKey?: string } = {}): Promise<{ data: Webhook; result: { outcome: string; }; }> {
return this.call({"method":"DELETE","path":"/webhooks/{webhookId}","query":[],"dryRun":false,"idempotency":true}, { webhookId }, options) as Promise<{ data: Webhook; result: { outcome: string; }; }>;
}
/** Trocar o segredo · Rotate the secret
* `POST /v1/webhooks/{webhookId}/rotate-secret` — permissão `webhooks:manage` */
rotateWebhookSecret(webhookId: string): Promise<{ data: Webhook; secret: string; }> {
return this.call({"method":"POST","path":"/webhooks/{webhookId}/rotate-secret","query":[],"dryRun":false,"idempotency":false}, { webhookId }, {}) as Promise<{ data: Webhook; secret: string; }>;
}
/** Mandar um evento de teste · Send a test event
* `POST /v1/webhooks/{webhookId}/test` — permissão `webhooks:manage` */
testWebhook(webhookId: string, options: { idempotencyKey?: string } = {}): Promise<{ data: WebhookTestResult; }> {
return this.call({"method":"POST","path":"/webhooks/{webhookId}/test","query":[],"dryRun":false,"idempotency":true}, { webhookId }, options) as Promise<{ data: WebhookTestResult; }>;
}
/** Entregas de um endereço · An endpoint's deliveries
* `GET /v1/webhooks/{webhookId}/deliveries` — permissão `webhooks:manage` */
listWebhookDeliveries(webhookId: string, options: { limit?: number; cursor?: string } = {}): Promise<{ data: Array; nextCursor: string | null; }> {
return this.call({"method":"GET","path":"/webhooks/{webhookId}/deliveries","query":["limit","cursor"],"dryRun":false,"idempotency":false}, { webhookId }, options) as Promise<{ data: Array; nextCursor: string | null; }>;
}
/** Todas as páginas de `listWebhookDeliveries`, item a item · every page of `listWebhookDeliveries`, item by item. */
async *listWebhookDeliveriesAll(webhookId: string, options: Omit<{ limit?: number; cursor?: string }, 'cursor'> = {}): AsyncGenerator {
const vistos = new Set();
let cursor: string | null | undefined;
do {
const pagina = await this.listWebhookDeliveries(webhookId, { ...options, cursor: cursor ?? undefined });
for (const item of pagina.data) yield item;
cursor = pagina.nextCursor;
if (cursor && vistos.has(cursor)) break; // cursor repetido: para em vez de rodar para sempre
if (cursor) vistos.add(cursor);
} while (cursor);
}
/** Reenviar uma entrega · Redeliver
* `POST /v1/webhooks/{webhookId}/deliveries/{deliveryId}/retry` — permissão `webhooks:manage` */
retryWebhookDelivery(webhookId: string, deliveryId: string, options: { idempotencyKey?: string } = {}): Promise<{ data: Delivery; result: { outcome: "SCHEDULED" | "ALREADY_SCHEDULED"; }; }> {
return this.call({"method":"POST","path":"/webhooks/{webhookId}/deliveries/{deliveryId}/retry","query":[],"dryRun":false,"idempotency":true}, { webhookId, deliveryId }, options) as Promise<{ data: Delivery; result: { outcome: "SCHEDULED" | "ALREADY_SCHEDULED"; }; }>;
}
/** Lote de imóveis · Batch of properties
* `POST /v1/properties/batch` — permissão `properties:write` — aceita `dryRun` */
createPropertyBatch(body: { items: Array; }, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: BatchCreated; }> {
return this.call({"method":"POST","path":"/properties/batch","query":[],"dryRun":true,"idempotency":true}, { }, options, body) as Promise<{ data: BatchCreated; }>;
}
/** Acompanhar o lote · Track the batch
* `GET /v1/properties/batch/{batchId}` — permissão `properties:read` */
getPropertyBatch(batchId: string): Promise<{ data: Batch; }> {
return this.call({"method":"GET","path":"/properties/batch/{batchId}","query":[],"dryRun":false,"idempotency":false}, { batchId }, {}) as Promise<{ data: Batch; }>;
}
/** Lote de clientes · Batch of clients
* `POST /v1/leads/batch` — permissão `leads:write` — aceita `dryRun` */
createLeadBatch(body: { items: Array; }, options: { dryRun?: boolean; idempotencyKey?: string } = {}): Promise<{ data: BatchCreated; }> {
return this.call({"method":"POST","path":"/leads/batch","query":[],"dryRun":true,"idempotency":true}, { }, options, body) as Promise<{ data: BatchCreated; }>;
}
/** Acompanhar o lote · Track the batch
* `GET /v1/leads/batch/{batchId}` — permissão `leads:read` */
getLeadBatch(batchId: string): Promise<{ data: Batch; }> {
return this.call({"method":"GET","path":"/leads/batch/{batchId}","query":[],"dryRun":false,"idempotency":false}, { batchId }, {}) as Promise<{ data: Batch; }>;
}
/**
* Confere a assinatura de um webhook (Standard Webhooks). `rawBody`: o corpo EXATAMENTE como chegou,
* antes de qualquer JSON.parse. Aceita qualquer uma das assinaturas (na troca de segredo vêm duas) e
* recusa mensagem com mais de 5 minutos.
*/
static verifyWebhook(secret: string, msgId: string, timestamp: string, signatureHeader: string, rawBody: string): boolean {
const agora = Math.floor(Date.now() / 1000);
if (!/^\d+$/.test(timestamp) || Math.abs(agora - Number(timestamp)) > 5 * 60) return false;
const chave = Buffer.from(secret.slice('whsec_'.length), 'base64');
const esperado = createHmac('sha256', chave).update(`${msgId}.${timestamp}.${rawBody}`, 'utf8').digest();
return signatureHeader.split(' ').some((parte) => {
const [versao, assinatura] = parte.split(',');
if (versao !== 'v1' || !assinatura) return false;
const dada = Buffer.from(assinatura, 'base64');
return dada.length === esperado.length && timingSafeEqual(dada, esperado);
});
}
}