DEVELOPING

Pagar por posição

GET /property-v1/properties/{paId}/publication/{portal}/positioning
PUT /property-v1/properties/{paId}/publication/{portal}/positioning

Alguns portais permitem pagar para que um anúncio apareça mais acima na listagem. O GET te dá tudo o que é necessário para decidir quanto; o PUT executa.

É um passo separado da publicação. Um anúncio publica do mesmo jeito sem isso; o que muda é onde ele aparece.

Cada portal cobra de um jeito diferente

O campo mechanism diz o que esperar, então um mesmo código serve para todos:

PortalO que se pagamechanismspend é
Argenproppontos de uma assinatura mensal, que a imobiliária distribui entre seus anúnciospointsum número
Zonapropo plano do anúnciotiero nome de um nível
MercadoLibreo tipo de publicaçãotiero nome de um nível
Cabaprop— não cobra por posição——

Hoje somente o Argenprop está habilitado. Os outros recebem 501, e a mensagem distingue os dois casos: "o portal não tem posicionamento pago" não é o mesmo que "ainda não habilitamos isso por aqui".


O GET: o contexto para decidir

GET …/positioning?simulate=5,100&visits=1-10
ParâmetroO que fazDefault
simulatelista de valores a simular: "em que posição eu ficaria se gastasse isso?"vazio
visitsfaixa de posições para trazer quantas visitas cada uma recebevazio

simulate custa uma chamada da cota do seu cliente POR CADA VALOR, e visits custa duas. Por isso não vêm por default: você os pede quando precisa. Até 10 valores em simulate e 25 posições em visits.

O que ele responde

{ "portal": "argenpropapi",
  "mechanism": "points",
  "paId": "01M5375T7YS6PC223DWC0YQPGS",
  "current": { "position": 794, "byBedrooms": 310, "indexed": true },
  "bounds":  { "min": 0, "max": 94518 },
  "balance": { "available": 10, "total": 10, "hasSubscription": true,
               "asOf": "2026-10-16T21:10:00Z" },
  "segment": { "propertyType": 1, "operation": 1, "locality": 2102,
               "neighborhood": 20, "bedrooms": 2 },
  "simulation": [ { "spend": 5, "position": 332 }, { "spend": 100, "position": 185 } ],
  "visitsByPosition": [ { "position": 1, "visits": 7991 }, { "position": 2, "visits": 3673 } ],
  "thresholds": [ { "position": 1, "points": 90018 }, { "position": 2, "points": 90017 } ],
  "calls": 9 }
CampoO que é
currentOnde o anúncio está hoje. indexed: false significa que o portal ainda não o indexou
boundsO piso e o teto do que você pode gastar neste anúncio
balanceO que resta ao seu cliente, com a data em que lemos
segmentContra qual conjunto de anúncios está sendo comparado
simulationUma entrada por cada valor que você pediu
visitsByPositionQuantas visitas cada posição recebe
thresholdsQuantos pontos tem quem está em cada posição
callsQuantas chamadas da cota do seu cliente esta consulta custou

🔴 O dado que torna tudo o resto útil

visitsByPosition cruzado com simulation diz quantas visitas cada ponto compra:

posição 1 → 7991 visitas           com   5 pontos → posição 332
posição 2 → 3673 visitas           com 100 pontos → posição 185

A posição 2 recebe menos da metade do que a 1. E a curva não é linear: os primeiros 5 pontos moveram 462 posições, os 5 seguintes moveram 22.


🔴 O que não conseguimos descobrir, nós dizemos

Um bloco que não pôde ser lido não vem como null: não vem, e o seu motivo está em unavailable.

{ "current": { "position": 794, "indexed": true },
  "balance": { "available": 10, "asOf": "…" },
  "unavailable": [
    { "block": "simulation", "reason": "no_indexado" },
    { "block": "visitsByPosition", "reason": "no_indexado" } ] }

A diferença importa: um campo que existe e diz null significaria "o portal diz que não há nada". Um campo ausente com o seu motivo significa "não conseguimos descobrir", que é o que aconteceu.

reasonO que aconteceuO que fazer
no_indexadoo anúncio foi publicado há muito pouco tempo e o portal ainda não o indexouesperar e pedir de novo. Não é um erro
segmento_sin_datos_suficienteso mercado dessa propriedade é muito pequeno para o portal ter estatísticasnada: não há números honestos a dar
segmento_incompletofalta a localização da propriedadecompletar a zona e publicar de novo
um código do portalo portal rejeitou essa leituraleia-o: é o mesmo tipo de código da publicação

current e o PUT continuam funcionando mesmo que falte todo o resto. As estatísticas e a simulação vêm de uma parte do portal que pode não estar disponível; publicar, consultar a sua posição e atribuir não dependem dela.

Se o segmento foi ampliado, nós dizemos

Quando o segmento da sua propriedade tem poucos anúncios, o portal compara contra um mais amplo. Se isso acontecer, nós declaramos:

{ "segment": { "propertyType": 1, "operation": 1, "locality": 2102,
               "neighborhood": 20, "bedrooms": null },
  "segmentWidened": ["bedrooms"] }

Rotule o dado com o segmento que voltou, não com o que você pediu. Uma curva de "Palermo, qualquer quantidade de dormitórios" não é a mesma que uma de "Palermo, 2 dormitórios".


O PUT: atribuir

{ "spend": 50 }
{ "portal": "argenpropapi", "mechanism": "points",
  "paId": "01M5375T7YS6PC223DWC0YQPGS",
  "spend": 50, "position": 185, "calls": 3 }

position é a posição REAL que lemos, não a que a simulação prometia: nós a consultamos depois de atribuir.

Mas o portal demora para recalculá-la. Medido: atribuindo 5 pontos, a simulação dava a posição 463 e a leitura imediata continuava devolvendo a anterior. Não é um erro e não significa que não foi aplicado — os pontos já foram descontados do saldo. Se você quiser mostrar o efeito, peça o GET de novo mais tarde; se quiser mostrar na hora, use o número da simulação e diga que é uma estimativa.

spend: 0 é válido — significa "pare de pagar". Por isso não há um DELETE aqui: dar baixa na publicação é outra coisa.

Se o portal ainda não reindexou, position não vem e nós dizemos:

{ "spend": 50, "positionUnavailable": "el portal todavía no reindexó el aviso" }

Não validamos o seu spend contra o max que lemos. Esse número vem de uma leitura que pode estar velha, e rejeitar você por isso seria a nossa cópia decidindo em lugar do portal. O portal é a autoridade sobre o que aceita: se ele rejeitar, devolvemos o motivo dele.

Erros

CódigoO que aconteceu
400Um parâmetro mal formado. É validado antes de chamar o portal, então não gasta cota
409 portal_not_connectedEssa conta não está conectada ao portal
409 no_publicadoA propriedade não está publicada ali: não há posição a consultar
404Essa propriedade não está no seu inventário
501Esse portal não tem posicionamento pago habilitado aqui
502 portal_rechazoO portal rejeitou a atribuição. reason traz o código dele

Relacionado