para imobiliárias

API · integração com CRM

O seu CRM publica. A Tudonuma mantém no ar.

Ligue o CRM que a imobiliária já usa e a carteira entra no site sozinha: preço novo, foto nova, imóvel reservado, vendido. Ninguém redigita nada — e os contatos dos anúncios vão direto para você.

  • Grátissem plano pago nem comissão
  • 600chamadas/min por chave
  • 200anúncios por lote
  • OpenAPIe Markdown para agentes
sincronizar REF-1042
PUT /api/v1/listings/REF-1042
Authorization: Bearer mk_9f3c…

{
  "title": "Apartamento 2 quartos na Velha",
  "operation": "aluguel",
  "type": "apartamento",
  "city": "Blumenau",
  "uf": "SC",
  "price": 2100
}
201 Created
{
  "external_id": "REF-1042",
  "url": "https://tudonuma.com/imovel/…-aa8fde4f9382",
  "status": "active",
  "created": true
}
Para a imobiliária

Menos digitação, mais contato direto.

  • Sem redigitar nada

    O CRM é a fonte da verdade. Mudou o preço, entrou foto, o imóvel foi reservado ou vendido: a Tudonuma recebe a mudança do próprio CRM, sem ninguém abrir o painel.

  • Grátis, de verdade

    Sem plano pago, sem destaque pago, sem comissão. Hoje a Tudonuma não cobra nada para anunciar — pela API ou pelo painel.

  • O contato vem para você

    Anúncio publicado pela imobiliária mostra os botões dela: mensagem no site, WhatsApp e telefone. As cópias reunidas de portais só levam ao anúncio de origem.

  • Uma vitrine só sua

    Uma página pública da imobiliária, com logo, capa, descrição, contatos e todos os anúncios ativos — atualizada junto com o CRM.

  • Números de cada imóvel

    No painel, por anúncio e nos últimos 30 dias: quantas vezes apareceu, quantos abriram, salvaram nos favoritos e pediram contato.

  • A moderação avisa o CRM

    Aprovou ou recusou, o seu sistema recebe um webhook assinado, com o motivo. Dá para abrir a tarefa para o corretor na hora.

Como funciona

Três passos, uma vez só.

  1. Crie a conta e a chave

    Cadastro de imobiliária com CNPJ, grátis. No painel, Integrações → Chaves de API: a chave aparece uma única vez — guarde no cofre do CRM.

  2. Ligue o CRM

    O fornecedor do CRM, um programador ou um agente de IA envia os imóveis com PUT, usando o código do CRM como external_id. A primeira chamada cria; as seguintes atualizam.

  3. Receba os avisos

    Cadastre uma URL https:// e receba listing.approved e listing.rejected, assinados com HMAC.

Quem vai ligar

Não precisa ser você quem programa.

Não temos plugin pronto para nenhum CRM — é uma API REST comum, e qualquer sistema integra. Escolha quem faz:

  • O fornecedor do CRM

    Vista, Jetimob, Kenlo, Superlógica, Imoview, Tecimob… Mande ao suporte do seu CRM uma mensagem pronta, com a documentação e o que você quer ligar.

  • Um programador ou um agente de IA

    Claude Code, Cursor, Codex, ChatGPT: o prompt desta página já aponta para a documentação em Markdown e para o OpenAPI, e diz o que fazer, na ordem certa.

  • Ninguém, por enquanto

    Com poucos imóveis, publique pelo painel: o assistente guia campo por campo. Quer ajuda para ligar o CRM? A equipe conversa com você.

Pronto para agentes de IA

O pedido, já escrito.

Três escolhas e sai o texto para colar no Claude Code, no Cursor, no Codex ou no ChatGPT — ou a mensagem para o suporte do seu CRM. Os dois levam os links certos e o que costuma dar errado.

Qual é o CRM?
Em que linguagem?
O que ligar

Para máquinas

Você vai integrar o Vista da nossa imobiliária à Tudonuma (https://tudonuma.com), um portal de imóveis, pela API de integração dela. É grátis e não tem plugin pronto: são chamadas REST comuns.

Leia a documentação antes de escrever código:
- https://tudonuma.com/api/v1/docs.md — a documentação completa, em Markdown
- https://tudonuma.com/api/v1/openapi.json — a especificação OpenAPI 3.0
- https://tudonuma.com/integracao — a mesma documentação para pessoas, com um validador de payload

O essencial:
- Base URL: https://tudonuma.com/api/v1 — JSON UTF-8, campos em snake_case, Content-Type: application/json.
- Autenticação: cabeçalho Authorization: Bearer <chave>. A chave (começa com mk_) vem da variável de ambiente TUDONUMA_API_KEY — nunca no código, no repositório nem em log.
- Cada imóvel é identificado pelo código dele no Vista: é o external_id (1 a 100 caracteres: letras sem acento, dígitos e - _ . :). PUT /listings/{external_id} cria na primeira vez e atualiza nas seguintes, então repetir a carga não duplica.
- Limite: 600 chamadas por minuto por chave.
- Use a linguagem e o estilo do projeto em que você estiver; se não houver projeto, proponha um antes de começar.

Faça, nesta ordem:
1. Um teste de conexão com GET /me, que responde com a imobiliária dona da chave e os escopos dela.
2. O mapeamento dos campos do Vista para os da Tudonuma. Obrigatórios na criação: title, operation ("aluguel" ou "venda"), type, address, city, uf e price (em reais) ou price_cents. Mande também lat/lng e ao menos uma foto (URLs públicas e estáveis): sem coordenadas o anúncio não aparece no mapa, e sem foto não entra na busca.
3. Publicar e atualizar: a cada alteração no Vista, um PUT /listings/{external_id} com o registro COMPLETO — alguns campos omitidos voltam ao padrão. Imóvel vendido ou alugado: DELETE /listings/{external_id}. Reservado por um tempo: POST /listings/{external_id}/status com {"status": "paused"} (e "active" para voltar).
4. Conciliação noturna: a carteira inteira em lotes de até 200 por POST /listings/batch (~50 por lote quando houver muitas fotos novas, que são baixadas durante a chamada); depois GET /listings?status=all (100 por página) e DELETE do que não existe mais no Vista.
5. Webhooks: um endpoint HTTPS que confere o cabeçalho X-Tudonuma-Signature (sha256=HMAC-SHA256 do corpo BRUTO, antes de qualquer parse de JSON, com o secret whsec_… do webhook; compare em tempo constante), responde 2xx em até 10 segundos (processe depois, numa fila), ignora X-Tudonuma-Delivery repetido e, em listing.rejected, cria uma tarefa para o corretor com o moderation_note. Registre a URL no painel ou por POST /webhooks.
6. Erros: teste o campo error das respostas 4xx (413, 415 e 422 vêm em texto simples); em 429 e 5xx, tente de novo com espera crescente. Registre em log os warnings que o PUT devolve (uma foto pulada, por exemplo).

Antes de pôr no ar, valide um corpo de exemplo em https://tudonuma.com/integracao#validador e rode tudo contra um ou dois imóveis de teste. Quando terminar, me diga o que falta configurar do meu lado (a chave, a URL do webhook, o agendamento da carga noturna).
Abrir no Claude ↗Abrir no ChatGPT ↗

A chave não vai no texto: o prompt pede que ela fique na variável TUDONUMA_API_KEY. Nunca cole a chave num chat.

Perguntas

Antes de ligar.

O que as imobiliárias perguntam primeiro. O resto está na documentação logo abaixo — ou com a equipe.

Quanto custa?

Nada. Anunciar na Tudonuma é grátis para imobiliárias, pela API ou pelo painel: não há plano pago, destaque pago nem comissão.

O meu CRM já tem integração pronta?

Ainda não temos plugin pronto com nenhum CRM específico. A API é REST e genérica: o fornecedor do CRM, um programador ou um agente de IA liga qualquer sistema. A mensagem pronta ajuda a pedir ao seu fornecedor.

Vocês aceitam feed XML (VRSync, ZAP, Viva Real) ou planilha?

Hoje não. A forma automática de levar a carteira é esta API, em JSON. Com poucos imóveis, o painel resolve; se precisa de outro formato, fale com a equipe.

Preciso de um programador?

Alguém precisa escrever as chamadas uma vez — o fornecedor do CRM, um programador ou um agente de IA com o prompt desta página. Depois disso a sincronização roda sozinha.

Os meus imóveis já aparecem na Tudonuma, vindos de portais. O que muda?

A Tudonuma reúne anúncios públicos de portais. Essas cópias não se juntam sozinhas aos anúncios da sua conta: depois de confirmar a imobiliária, a equipe cuida delas. O que a imobiliária publica direto sai com os contatos dela.

Já cadastrei imóveis no painel. Posso ligar a API?

Pode, mas escolha um caminho por imóvel: um anúncio do painel enviado de novo pela API vira um segundo anúncio, porque o do painel não tem external_id. Exclua o do painel, ou deixe esse imóvel fora da carga.

E se a moderação recusar um anúncio?

O status vira rejected, o motivo vem em moderation_note e o seu sistema recebe o webhook listing.rejected. Corrija e envie o PUT de novo: o anúncio volta para análise.

A chave de API é segura?

Guardamos só o hash SHA-256 dela; a chave completa aparece uma vez, ao criar. Se vazar, revogue no painel: ela para de funcionar na hora. Só o responsável pela conta da imobiliária gerencia as chaves.

Para quem vai programar

A documentação.

Base https://tudonuma.com/api/v1 · JSON UTF-8 · campos em snake_case · exemplos em cURL, Node.js, PHP e Python.

OpenAPI ↗Markdown ↗
Fundamentos

Autenticação

Toda chamada leva a chave no cabeçalho Authorization. X-Api-Key: mk_… também é aceito, para CRMs que não deixam mexer no Authorization.

Guardamos apenas o hash SHA-256 da chave: se ela se perder, revogue no painel e crie outra. Uma chave revogada — ou de uma conta desativada — para de funcionar na hora, com 401.

Escopos

EscopoLibera
listings:readGET /listings e GET /listings/{external_id}
listings:writePUT, /batch, /status e DELETE
webhooks:manage/webhooks por API

Uma chave nova recebe os três escopos. GET /me funciona com qualquer um — é o jeito mais simples de testar se a chave está certa.

curl -X GET 'https://tudonuma.com/api/v1/me' \
  -H "Authorization: Bearer mk_SUA_CHAVE"

Erros e limites

Os erros de negócio vêm sempre com o mesmo corpo: um error estável, que o seu código pode testar, e um message para quem estiver lendo o log.

Limite: 600 chamadas por minuto por chave. Para enviar a carteira inteira, use /listings/batch — são 200 anúncios por chamada.

429

Além do limite por chave existe um limite por IP na borda (cerca de 60 req/s, com rajada de 30), e esse 429 vem sem corpo JSON. Nos dois casos, espere alguns segundos e tente de novo com espera crescente.

400 Bad Request
{
  "error": "invalid_price",
  "message": "price (reais) or price_cents must be positive"
}
StatusQuando aconteceO que fazer
400Dados inválidos. O error diz qual campo: invalid_price, invalid_type…Corrija o registro no CRM; tentar de novo não resolve.
401Chave ausente, desconhecida, revogada, ou conta desativada.Confira a chave no painel.
403scope_missing: a chave não tem o escopo da rota.Crie uma chave com o escopo.
404not_found: nenhum anúncio com esse external_id nesta conta.Crie com PUT.
409not_applicable: por exemplo, reativar um anúncio retido pela moderação.Leia moderation_note, corrija e envie o PUT.
413Corpo acima de 2 MB.Divida o lote.
415Faltou Content-Type: application/json.Envie o cabeçalho.
422Tipo errado num campo: "bedrooms": "2" em texto, area_m2 com decimal.Envie números como números.
429rate_limited: mais de 600 chamadas no último minuto.Espere e use o lote.
500internal_error: falha do nosso lado.Tente de novo com espera.

413, 415 e 422 vêm em texto simples, sem o corpo {error, message}.

O external_id é o seu código

Todo anúncio é identificado pelo código que o CRM já usa — REF-1042, AP0231, o que for. PUT /listings/{external_id} cria na primeira chamada e atualiza nas seguintes. Rodar a sincronização inteira toda noite não gera duplicatas.

O código vale por conta: o mesmo external_id em duas contas são dois anúncios.

Formato: de 1 a 100 caracteres — letras sem acento, dígitos e - _ . :. Espaços e barras não entram; troque por - antes de enviar.

válido
Serve como está: PUT /listings/REF-1042

Status e moderação

Cada anúncio tem dois campos que andam juntos e dizem coisas diferentes: status é o ciclo de vida, que você controla; moderation é o parecer da equipe, que você só lê.

status

Se o anúncio aparece no site.

  • activePublicado e visível.
  • pausedOculto, guardado. Volta com available: true.
  • pending_reviewRetido até a equipe aprovar (modo pre).
  • rejectedRecusado. O motivo está em moderation_note.
  • deletedRemovido com DELETE. Sai das listagens.

moderation

O parecer da equipe sobre o conteúdo.

  • pendingAinda não revisado.
  • approvedAprovado. Dispara listing.approved.
  • rejectedRecusado. Dispara listing.rejected.

O modo da plataforma está em GET /me: post publica na hora e revisa depois; pre segura em pending_review até aprovar.

  1. PUT de um código novo→active+pendingmodo post
  2. available: false ou /status paused→paused
  3. A equipe recusa→rejected+ webhook listing.rejected
  4. Você corrige e envia o PUT de novo→volta para análise: active+pending
  5. DELETE→deleted+ webhook listing.deleted
Referência

Anúncios

GET/me

Quem sou eu

A imobiliária dona da chave, os escopos dela e o modo de moderação da plataforma. Use no botão “testar conexão” do seu CRM.

curl -X GET 'https://tudonuma.com/api/v1/me' \
  -H "Authorization: Bearer mk_SUA_CHAVE"
200 OK
{
  "agency": {
    "id": 42,
    "name": "Imobiliária Exemplo",
    "slug": "imobiliaria-exemplo"
  },
  "key": {
    "id": 7,
    "scopes": [
      "listings:read",
      "listings:write",
      "webhooks:manage"
    ]
  },
  "user": {
    "id": 1180,
    "email": "integracao@exemplo.com.br"
  },
  "moderation": "post"
}
Cole a sua chave no índice para executar.
GET/listingslistings:read

Listar os anúncios desta conta

100 por página, do mais novo para o mais antigo. Serve para conciliar: compare com a carteira do CRM e remova o que não existe mais.

ParâmetroDescrição
pageinteger · padrão 1Página, a partir de 1.
statusstring · padrão allactive, paused, rejected, pending_review ou all (tudo menos os excluídos).
curl -X GET 'https://tudonuma.com/api/v1/listings?page=1&status=all' \
  -H "Authorization: Bearer mk_SUA_CHAVE"
200 OK
{
  "data": [
    {
      "id": 18231,
      "external_id": "REF-1042",
      "url": "https://tudonuma.com/imovel/apartamento-aluguel-velha-blumenau-aa8fde4f9382",
      "status": "active",
      "moderation": "approved",
      "title": "Apartamento 2 quartos com sacada na Velha",
      "price_cents": 210000,
      "updated_at": "2026-09-21T03:10:05Z"
    }
  ],
  "total": 312,
  "page": 1,
  "page_size": 100
}
Cole a sua chave no índice para executar.
GET/listings/{external_id}listings:read

Um anúncio

O anúncio como está agora: status, moderation, a URL pública e as fotos já servidas por nós. 404 se não existir nesta conta.

curl -X GET 'https://tudonuma.com/api/v1/listings/REF-1042' \
  -H "Authorization: Bearer mk_SUA_CHAVE"
200 OK
{
  "id": 18231,
  "public_id": "aa8fde4f9382",
  "external_id": "REF-1042",
  "url": "https://tudonuma.com/imovel/apartamento-aluguel-velha-blumenau-aa8fde4f9382",
  "status": "active",
  "moderation": "approved",
  "moderation_note": "",
  "title": "Apartamento 2 quartos com sacada na Velha",
  "operation": "aluguel",
  "type": "apartamento",
  "address": "Rua João Pessoa, 1250, ap. 302",
  "neighborhood": "Velha",
  "city": "Blumenau",
  "uf": "SC",
  "lat": -26.9245,
  "lng": -49.0912,
  "area_m2": 72,
  "bedrooms": 2,
  "bathrooms": 1,
  "parking": 1,
  "price_cents": 210000,
  "condo_cents": 38000,
  "iptu_cents": 6000,
  "description": "Apartamento arejado, sol da manhã, a duas quadras da Rua São Paulo.",
  "photos": [
    "https://tudonuma.com/uploads/2026/09/7c1e…a4.webp",
    "https://tudonuma.com/uploads/2026/09/03b9…1f.webp"
  ],
  "matricula": "45.123",
  "inscricao": "01.02.003.0456.001",
  "created_at": "2026-09-07T14:02:48Z",
  "updated_at": "2026-09-21T03:10:05Z"
}
Cole a sua chave no índice para executar.
PUT/listings/{external_id}listings:write

Criar ou atualizar

O coração da integração. Responde 201 Created quando cria e 200 OK quando atualiza, sempre com o anúncio como ficou, mais created e warnings.

Obrigatórios na criação: title, operation, type, address, city, uf e price (ou price_cents). Todos os campos estão na referência.

Numa atualização, envie o registro completo

Parte dos campos mantém o valor anterior quando omitida; outra parte volta ao padrão — a referência marca cada um. photos e tags, quando enviados, substituem a lista inteira.

Fotos

URLs públicas http(s)://, JPG, PNG ou WebP, até 10 MB e 12000×12000 px. Baixamos e servimos as fotos nós mesmos. Cada URL é baixada uma vez e lembrada — se a imagem mudar, publique numa URL nova. Redirecionamentos não são seguidos. Uma foto que falhar é pulada e aparece em warnings; o anúncio é salvo mesmo assim.

Um anúncio sem nenhuma foto é salvo, mas não entra no catálogo público.

Dica

Monte o corpo no validador antes de programar: ele aponta o mesmo erro que a API devolveria.

curl -X PUT 'https://tudonuma.com/api/v1/listings/REF-1042' \
  -H "Authorization: Bearer mk_SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Apartamento 2 quartos com sacada na Velha",
  "operation": "aluguel",
  "type": "apartamento",
  "address": "Rua João Pessoa, 1250, ap. 302",
  "neighborhood": "Velha",
  "city": "Blumenau",
  "uf": "SC",
  "lat": -26.9245,
  "lng": -49.0912,
  "area_m2": 72,
  "bedrooms": 2,
  "bathrooms": 1,
  "parking": 1,
  "floor": 3,
  "building_floors": 8,
  "price": 2100,
  "condo": 380,
  "iptu": 60,
  "description": "Apartamento arejado, sol da manhã, a duas quadras da Rua São Paulo.",
  "photos": [
    "https://cdn.suaimobiliaria.com.br/imoveis/1042/01.jpg",
    "https://cdn.suaimobiliaria.com.br/imoveis/1042/02.jpg"
  ],
  "furnished": "partial",
  "pet_friendly": true,
  "amenities": [
    "piscina",
    "academia",
    "portaria-24h"
  ],
  "tags": [
    "sacada",
    "churrasqueira"
  ],
  "contact_phone": "47999990000",
  "matricula": "45.123",
  "inscricao": "01.02.003.0456.001",
  "available": true
}'
201 Created
{
  "id": 18231,
  "public_id": "aa8fde4f9382",
  "external_id": "REF-1042",
  "url": "https://tudonuma.com/imovel/apartamento-aluguel-velha-blumenau-aa8fde4f9382",
  "status": "active",
  "moderation": "pending",
  "moderation_note": "",
  "…": "o anúncio completo, como em GET",
  "created": true,
  "warnings": []
}
POST/listings/batchlistings:write

Até 200 anúncios numa chamada

Cada item leva o seu external_id junto dos campos e é julgado sozinho: um registro ruim não derruba o lote. A resposta lista cada item com ok, e o erro dos que falharam.

Um JSON com tipo errado em qualquer item recusa a chamada inteira (422). O corpo vai até 2 MB.

Tempo

As fotos novas são baixadas durante a chamada. Com muitas fotos novas, prefira lotes de ~50 para não passar de 60 s. Um lote de atualizações sem fotos novas pode ir cheio.

curl -X POST 'https://tudonuma.com/api/v1/listings/batch' \
  -H "Authorization: Bearer mk_SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "listings": [
    {
      "external_id": "REF-1042",
      "title": "Apartamento 2 quartos na Velha",
      "operation": "aluguel",
      "type": "apartamento",
      "address": "Rua João Pessoa, 1250",
      "city": "Blumenau",
      "uf": "SC",
      "price": 2100
    },
    {
      "external_id": "REF-1043",
      "title": "Casa 3 quartos no Garcia",
      "operation": "venda",
      "type": "casa",
      "address": "Rua Amazonas, 310",
      "city": "Blumenau",
      "uf": "SC",
      "price": 650000
    }
  ]
}'
200 OK
{
  "ok": 1,
  "failed": 1,
  "results": [
    {
      "external_id": "REF-1042",
      "ok": true,
      "id": 18231,
      "public_id": "aa8fde4f9382",
      "created": false,
      "warnings": []
    },
    {
      "external_id": "REF-1043",
      "ok": false,
      "error": "invalid_price",
      "message": "price (reais) or price_cents must be positive"
    }
  ]
}
POST/listings/{external_id}/statuslistings:write

Pausar ou reativar

{"status": "paused"} ou {"status": "active"} — mais leve que um PUT quando o imóvel só saiu do ar por um tempo: reservado, em negociação.

Não reativa um anúncio retido pela moderação (409) e não dispara webhook.

curl -X POST 'https://tudonuma.com/api/v1/listings/REF-1042/status' \
  -H "Authorization: Bearer mk_SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "paused"
}'
200 OK
{
  "id": 18231,
  "external_id": "REF-1042",
  "status": "paused"
}
DELETE/listings/{external_id}listings:write

Remover

Para imóvel vendido ou alugado. É uma exclusão lógica: o anúncio sai do site e das listagens, o histórico fica. Dispara listing.deleted.

curl -X DELETE 'https://tudonuma.com/api/v1/listings/REF-1042' \
  -H "Authorization: Bearer mk_SUA_CHAVE"
200 OK
{
  "id": 18231,
  "external_id": "REF-1042",
  "status": "deleted"
}
Referência

Campos do anúncio

Tudo o que o PUT e o lote aceitam. Campos desconhecidos são ignorados — o CRM pode mandar o registro inteiro como está. A coluna Na atualização diz o que acontece com um campo que não vem num PUT de um anúncio que já existe.

34 de 34
CampoTipoDescriçãoNa atualização
titleobrig.stringTítulo do anúncio, de 3 a 200 caracteres.mantém
operationobrig.aluguel | vendaA operação. Maiúsculas são aceitas.mantém
typeobrig.stringO tipo do imóvel; os valores estão logo abaixo da tabela.mantém
addressobrig.stringRua, número e complemento.mantém
cityobrig.stringCidade. Uma cidade que ainda não está no cadastro é criada.mantém
ufobrig.stringEstado, duas letras.mantém
priceobrig.numberPreço em reais — aluguel mensal ou valor de venda. Ou envie price_cents.mantém
price_centsintegerPreço em centavos. Vale este se vierem os dois.mantém
neighborhoodstringBairro pelo nome; é casado com o cadastro da cidade, sem ligar para acentos.mantém
latnumberLatitude. Sem coordenadas o anúncio não aparece no mapa.mantém
lngnumberLongitude.mantém
area_m2integerÁrea útil em m², número inteiro.mantém
bedroomsintegerQuartos, até 99.mantém
bathroomsintegerBanheiros, até 99.mantém
parkingintegerVagas de garagem, até 99.mantém
condonumberCondomínio mensal em reais. Ou condo_cents.mantém
iptunumberIPTU mensal em reais. Ou iptu_cents.mantém
descriptionstringTexto livre, até 8.000 caracteres.mantém
photosstring[]URLs públicas http(s), até 16; JPG, PNG ou WebP de até 10 MB. Enviada, substitui a lista. Sem nenhuma foto, o anúncio não entra no catálogo.mantém
tagsstring[]Características livres (sacada, vista-rio…). Até 40, de até 40 caracteres. Enviada, substitui a lista.mantém
floorintegerAndar. 0 = térreo.volta ao padrão
building_floorsintegerAndares do prédio.volta ao padrão
furnishedbool | no | partial | fullMobília. true equivale a full.volta ao padrão
pet_friendlyboolAceita animais.volta ao padrão
internetboolInternet incluída.volta ao padrão
amenitiesstring[]Áreas comuns do condomínio. As da lista abaixo viram filtro no site; as outras são guardadas sem filtro.volta ao padrão
contact_phonestringTelefone com DDD. Guardamos só os dígitos.volta ao padrão
show_whatsappboolMostra o botão de WhatsApp. Padrão true.volta ao padrão
show_phoneboolMostra o telefone. Padrão true.volta ao padrão
show_chatboolAceita mensagens pelo chat do site. Padrão true.volta ao padrão
matriculastringMatrícula do cartório, até 64 caracteres. Com ela o anúncio entra no filtro “com matrícula”.volta ao padrão
inscricaostringInscrição imobiliária (IPTU), até 64 caracteres.volta ao padrão
owner_typeowner | agencyQuem detém o imóvel. Padrão agency.volta ao padrão
availableboolfalse pausa (oculto, não excluído); true publica. Omitido, o status não muda.—

Valores de type

apartamentostudiocasaloftcolivingcoberturaconsultoriogalpaocomercialterrenoterreno_comerciallojasalaprediorural

Áreas comuns que viram filtro no site

piscinaacademiachurrasqueirasalao-festasespaco-kidspet-areacoworkingportaria-24hsaunamercadinho

Outros valores de amenities são guardados, mas não viram filtro.

Ferramenta

Validador de payload

Cole o JSON que o seu CRM gera. O validador aplica as mesmas regras da API, na mesma ordem, e mostra a resposta que ela daria — sem enviar nada. Quando passa, sai o comando pronto para enviar de verdade.

Corpo do PUT
PUT /listings/
Resposta prevista
201

Seria criado, sem avisos.

Operação
aluguel
Tipo
apartamento
Preço
R$ 2.100,00
Local
Blumenau/SC
Fotos
2
  • notaGuardadas sem filtro no site: elevador.
  • notatype é gravado em minúsculas: apartamento.
curl -X PUT 'https://tudonuma.com/api/v1/listings/REF-1042' \
  -H "Authorization: Bearer mk_SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "title": "Apartamento 2 quartos com sacada na Velha",
  "operation": "aluguel",
  "type": "Apartamento",
  "address": "Rua João Pessoa, 1250, ap. 302",
  "neighborhood": "Velha",
  "city": "Blumenau",
  "uf": "SC",
  "lat": -26.9245,
  "lng": -49.0912,
  "area_m2": 72,
  "bedrooms": 2,
  "bathrooms": 1,
  "parking": 1,
  "floor": 3,
  "building_floors": 8,
  "price": 2100,
  "condo": 380,
  "iptu": 60,
  "description": "Apartamento arejado, sol da manhã, a duas quadras da Rua São Paulo.",
  "photos": [
    "https://cdn.suaimobiliaria.com.br/imoveis/1042/01.jpg",
    "https://cdn.suaimobiliaria.com.br/imoveis/1042/02.jpg"
  ],
  "furnished": "partial",
  "pet_friendly": true,
  "amenities": [
    "piscina",
    "academia",
    "elevador"
  ],
  "tags": [
    "sacada",
    "churrasqueira"
  ],
  "contact_phone": "47999990000",
  "matricula": "45.123",
  "inscricao": "01.02.003.0456.001",
  "available": true
}'
Webhooks

O que muda, avisamos

Cadastre uma URL https:// em Painel → Integrações → Webhooks, ou por API. A cada evento enviamos um POST JSON com o anúncio como ficou.

EventoQuando
listing.createdUm PUT criou o anúncio (só via API).
listing.updatedUm PUT atualizou o anúncio (só via API).
listing.deletedUm DELETE removeu o anúncio (só via API).
listing.approvedA moderação aprovou um anúncio da imobiliária — venha ele da API ou do painel.
listing.rejectedA moderação recusou. O motivo vem em moderation_note.
pingO teste disparado pelo botão do painel.

Cabeçalhos

X-Tudonuma-EventO nome do evento.
X-Tudonuma-DeliveryId único da entrega. Guarde e ignore repetições.
X-Tudonuma-Signaturesha256=<hex>, HMAC-SHA256 do corpo bruto com o secret do webhook.
User-AgentTudonuma-Webhooks/1.0
POST → a sua URL
{
  "event": "listing.rejected",
  "created_at": "2026-09-07T14:03:11Z",
  "data": {
    "listing": {
      "id": 18231,
      "public_id": "aa8fde4f9382",
      "external_id": "REF-1042",
      "url": "https://tudonuma.com/imovel/apartamento-aluguel-velha-blumenau-aa8fde4f9382",
      "status": "rejected",
      "moderation": "rejected",
      "moderation_note": "Fotos pertencem a outro imóvel.",
      "…": "o anúncio completo"
    }
  }
}

Confira a assinatura

Antes de confiar no payload, recalcule o HMAC do corpo exatamente como chegou — antes de qualquer JSON.parse — e compare em tempo constante.

O secret (whsec_…) aparece uma única vez, ao criar o webhook.

import { createHmac, timingSafeEqual } from "node:crypto";
import express from "express";

const SECRET = process.env.TUDONUMA_WEBHOOK_SECRET;
const app = express();

// O corpo BRUTO: express.raw, e não express.json.
app.post("/webhooks/tudonuma", express.raw({ type: "application/json" }), (req, res) => {
  const expected = "sha256=" + createHmac("sha256", SECRET).update(req.body).digest("hex");
  const got = req.get("X-Tudonuma-Signature") ?? "";
  if (got.length !== expected.length || !timingSafeEqual(Buffer.from(got), Buffer.from(expected))) {
    return res.sendStatus(401);
  }
  res.sendStatus(204); // responda já; processe depois
  const { event, data } = JSON.parse(req.body);
  fila.push({ entrega: req.get("X-Tudonuma-Delivery"), event, anuncio: data.listing });
});
Teste com uma entrega
Resultado
Calculando no navegador…

Mude uma vírgula no corpo para ver a assinatura deixar de conferir. Nada sai desta página: o cálculo é feito no navegador.

Novas tentativas

Responda 2xx em até 10 segundos — de preferência antes de processar, pondo o evento numa fila. Qualquer outra resposta, um timeout ou um redirecionamento (3xx não é seguido) conta como falha, e a entrega é tentada de novo com espera crescente.

1agora
2+1 min
3+6 min
4+36 min
5+2 h 36 min
6+14 h 36 min
6 tentativas no totala última cerca de 14 h 36 min depois da primeiradepois disso, a entrega é abandonada

O painel mostra as entregas e o último status de cada webhook. Até 10 webhooks ativos por imobiliária; URL https:// pública de até 500 caracteres. As entregas saem uma por vez, a cada 15 s, e a ordem de chegada não é garantida — use o created_at do evento.

Gerenciar webhooks por API

Para CRMs que se configuram sozinhos na instalação. Exige o escopo webhooks:manage.

RotaFaz
GET /webhooksLista os webhooks e os eventos disponíveis.
POST /webhooks{url, events}; events vazio = todos. Responde 201 com o secret, uma única vez.
DELETE /webhooks/{id}Remove.
curl -X POST 'https://tudonuma.com/api/v1/webhooks' \
  -H "Authorization: Bearer mk_SUA_CHAVE" \
  -H "Content-Type: application/json" \
  -d '{
  "url": "https://crm.suaimobiliaria.com.br/webhooks/tudonuma",
  "events": [
    "listing.approved",
    "listing.rejected"
  ]
}'
201 Created
{
  "id": 3,
  "url": "https://crm.suaimobiliaria.com.br/webhooks/tudonuma",
  "events": [
    "listing.approved",
    "listing.rejected"
  ],
  "active": true,
  "created_at": "2026-09-07T13:58:20Z",
  "last_status": null,
  "last_delivered_at": null,
  "failures": 0,
  "secret": "whsec_4Tn2…"
}
Guia

Receitas de sincronização

O desenho que funciona para a maioria dos CRMs: um fluxo contínuo para o que muda no dia, uma conciliação noturna para o que escapou, e os webhooks fechando o ciclo.

A cada alteração

Incremental

Ao salvar um imóvel no CRM, envie um PUT só dele. Vendido ou alugado: DELETE. Reservado por uns dias: /status paused.

Uma vez por noite

Conciliação

Envie a carteira inteira em lotes de 200 pelo /batch. Depois leia GET /listings?status=all e apague o que não existe mais no CRM.

Quando chega um webhook

Fechar o ciclo

Em listing.rejected, crie uma tarefa para o corretor com o moderation_note. Recusa pede ação humana; reenviar igual não adianta.

Boas práticas

  • Envie ao menos uma foto: anúncio sem foto não entra no catálogo público — fica salvo, mas ninguém o encontra na busca.
  • Use URLs de foto estáveis: a mesma URL não é baixada duas vezes, e uma URL nova é tratada como foto nova.
  • Envie lat/lng sempre que tiver — sem coordenadas o anúncio não aparece no mapa.
  • Mande dinheiro em centavos (price_cents) se o CRM já guarda assim; evita arredondamento.
  • Preencha matricula e inscricao quando existirem: o anúncio entra no filtro “com matrícula”.
  • Guarde o X-Tudonuma-Delivery dos webhooks processados e ignore repetições.

Recursos

/api/v1/openapi.jsonEspecificação OpenAPI 3.0 — importe no Postman, no Insomnia ou no gerador de cliente.Abrir
/api/v1/docs.mdEsta documentação em Markdown, para versionar junto do código da integração — ou para dar a um agente de IA.Abrir
/llms.txtO índice para agentes de IA (padrão llms.txt): o que ler e onde. /llms-full.txt traz a documentação inteira num arquivo só.Abrir
Painel → IntegraçõesChaves, webhooks, histórico de entregas e o botão de teste (ping).

Vai programar com um agente de IA? O prompt pronto já leva estes links. Dúvidas de integração: Falar com o suporte, no rodapé.

é grátis

Ligue o CRM uma vez. A carteira se cuida sozinha.

Crie a conta da imobiliária, gere a chave e mande o pedido pronto para quem vai ligar.