Pular para o conteúdo
v1

Documentação da API ObraAberta

API REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.

Início rápido

Base: https://obraaberta.com.br/api/v1. O caminho alternativo /api/public/v1 expõe exatamente os mesmos endpoints e é sempre público — use-o em integrações servidor-a-servidor.

# 1. checar disponibilidade
curl "https://obraaberta.com.br/api/v1/health"

# 2. listar 5 obras em construção em SP
curl "https://obraaberta.com.br/api/v1/projects?state=SP&status=em_construcao&limit=5"

# 3. mesma chamada com chave de API (limite ampliado)
curl "https://obraaberta.com.br/api/v1/projects?state=SP" -H "X-API-Key: $OBRAABERTA_KEY"

JavaScript (fetch)

const r = await fetch(
  "https://obraaberta.com.br/api/v1/projects/search?q=vila+mariana&limit=10",
  { headers: { "X-API-Key": process.env.OBRAABERTA_KEY } }
);
const { data, pagination } = await r.json();
console.log(pagination.total, data[0].name);

Python (requests)

import os, requests

r = requests.get(
    "https://obraaberta.com.br/api/v1/projects",
    params={"state": "SP", "status": "em_construcao", "limit": 100},
    headers={"X-API-Key": os.environ["OBRAABERTA_KEY"]},
    timeout=30,
)
r.raise_for_status()
print(r.json()["pagination"]["total"])

Autenticação e limites de uso

Os endpoints GET são abertos. A autenticação serve para elevar o limite de requisições, liberar uso automatizado e acessar o enriquecimento. Chaves são emitidas por administradores da ObraAberta e guardadas apenas como hash — copie no momento da criação.

PerfilLimiteComo enviar
Anônimo100 req/h por IPSem cabeçalho de autenticação.
Usuário logado1.000 req/h por usuárioAuthorization: Bearer <JWT da sessão>.
Chave de API10.000 req/h por chaveX-API-Key: <chave emitida pelo admin>.

Toda resposta traz X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset (janela deslizante de 1 hora). Ao estourar, a API devolve 429 rate_limited. Respostas de leitura têm Cache-Control: public, max-age=60.

Convenções

Paginação

{
  "data": [ /* itens */ ],
  "pagination": { "page": 1, "limit": 50, "total": 18093, "pages": 362 }
}

limit máximo de 500. Para varreduras completas, pagine com sort=created_at&order=asc para manter a ordem estável.

Erros

{ "error": { "code": "not_found", "message": "Obra não encontrada ou não publicada.", "status": 404 } }
  • 400 bad_request Parâmetro ausente, mal formatado ou filtro rejeitado pelo banco.
  • 401 unauthorized Endpoint exige JWT (Authorization: Bearer) ou chave (X-API-Key).
  • 403 forbidden Agente automatizado sem chave — o anti-bot bloqueia raspagem anônima.
  • 404 not_found Recurso inexistente, não publicado ou fora do seu escopo de acesso.
  • 405 method_not_allowed Só GET é aceito, exceto POST /projects/enrich.
  • 429 rate_limited Limite por hora excedido; consulte X-RateLimit-Reset.
  • 500 internal_error Falha inesperada no servidor — tente novamente.
  • 502 enrichment_failed Fonte externa indisponível durante o enriquecimento.

Status das obras

Valor na APIEstado internoSignificado
lancamentoplanejamentoProjeto anunciado, obra ainda não iniciada.
em_construcaoem_andamentoCanteiro ativo.
paralisadaparalisadaObra interrompida.
pronto / entregueconcluidaObra concluída ou entregue aos moradores.

Objeto Obra

Estrutura devolvida em todas as listagens e no detalhe. Campos sem informação vêm como null (nunca são omitidos). data_quality_score vai de 0 a 1 e indica a completude dos dados; data_sources lista as fontes que alimentaram o registro.

{
  "id": "0f0a1c7e-4a2b-4e0f-9c3a-2f5d8b1c9e11",
  "slug": "evolve-vila-mariana",
  "name": "Evolve Vila Mariana",
  "description": "Empreendimento residencial com 2 torres...",
  "address": "Rua Domingos de Morais, 1200 - Vila Mariana - São Paulo",
  "neighborhood": "Vila Mariana",
  "city": "São Paulo",
  "state": "SP",
  "cep": "04010-100",
  "phone": "+55 11 4000-0000",
  "geolocation": { "latitude": -23.5896, "longitude": -46.6383 },
  "status": "em_construcao",
  "completion_percentage": 42,
  "total_units": 180,
  "available_units": 37,
  "price_from": 620000,
  "price_to": 1180000,
  "price_per_m2": 12400,
  "total_area": 8600,
  "bedrooms": 2,
  "bathrooms": 2,
  "parking_spaces": 1,
  "amenities": ["piscina", "academia", "coworking"],
  "cover_url": "https://.../capa.jpg",
  "floor_plans": [],
  "constructor": { "id": "…", "name": "Construtora Exemplo" },
  "launch_date": "2024-03-01",
  "completion_date": "2026-12-31",
  "data_sources": ["mcmv", "osm", "brasilapi"],
  "data_quality_score": 0.82,
  "last_enriched_at": "2026-08-01T12:00:00Z",
  "last_updated_at": "2026-08-05T09:31:00Z",
  "created_at": "2025-11-02T18:22:00Z",
  "url": "https://obraaberta.com.br/obras/sp/sao-paulo/vila-mariana/evolve-vila-mariana"
}

Referência de endpoints

Obras (Projects)

Consulta às obras publicadas na ObraAberta: listagem, busca, geolocalização, linha do tempo, avaliações e serviços do entorno.

GET
/projects
público
Lista obras publicadas

Retorna obras com o envelope padrão de paginação. Somente obras com publicada = true aparecem. Todos os filtros podem ser combinados.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
pagequeryinteger1Página desejada (começa em 1).
limitqueryinteger50Itens por página. Máximo 500.
cityquerystringNome exato da cidade (sem diferenciar maiúsculas).
statequerystringSigla da UF, ex.: SP.
statusqueryenumlancamento | em_construcao | paralisada | pronto | entregue.
min_pricequerynumberPreço mínimo (R$) a partir do menor valor da obra.
max_pricequerynumberPreço máximo (R$) sobre o menor valor da obra.
bedroomsqueryintegerNúmero exato de dormitórios.
amenitiesquerystringLista separada por vírgula; retorna obras que tenham todas.
sortqueryenumcreated_atcreated_at | name | price | completion_percentage | updated_at.
orderqueryenumdescasc ou desc.

Requisição

curl "https://obraaberta.com.br/api/v1/projects?state=SP&status=em_construcao&limit=20"

Resposta

{
  "data": [ /* array de Obra */ ],
  "pagination": { "page": 1, "limit": 50, "total": 18093, "pages": 362 }
}
GET
/projects/by-city/{city}
público
Obras de uma cidade

Atalho para /projects com o filtro city preenchido pelo caminho.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
city*pathstringNome da cidade (URL-encoded).
pagequeryinteger1Página desejada (começa em 1).
limitqueryinteger50Itens por página. Máximo 500.
cityquerystringNome exato da cidade (sem diferenciar maiúsculas).
statequerystringSigla da UF, ex.: SP.
statusqueryenumlancamento | em_construcao | paralisada | pronto | entregue.
min_pricequerynumberPreço mínimo (R$) a partir do menor valor da obra.
max_pricequerynumberPreço máximo (R$) sobre o menor valor da obra.
bedroomsqueryintegerNúmero exato de dormitórios.
amenitiesquerystringLista separada por vírgula; retorna obras que tenham todas.
sortqueryenumcreated_atcreated_at | name | price | completion_percentage | updated_at.
orderqueryenumdescasc ou desc.

Requisição

curl "https://obraaberta.com.br/api/v1/projects/by-city/S%C3%A3o%20Paulo"

Resposta

{
  "data": [ /* array de Obra */ ],
  "pagination": { "page": 1, "limit": 50, "total": 18093, "pages": 362 }
}
GET
/projects/by-state/{state}
público
Obras de um estado

Atalho para /projects com o filtro state preenchido pelo caminho.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
state*pathstringSigla da UF.
pagequeryinteger1Página desejada (começa em 1).
limitqueryinteger50Itens por página. Máximo 500.
cityquerystringNome exato da cidade (sem diferenciar maiúsculas).
statequerystringSigla da UF, ex.: SP.
statusqueryenumlancamento | em_construcao | paralisada | pronto | entregue.
min_pricequerynumberPreço mínimo (R$) a partir do menor valor da obra.
max_pricequerynumberPreço máximo (R$) sobre o menor valor da obra.
bedroomsqueryintegerNúmero exato de dormitórios.
amenitiesquerystringLista separada por vírgula; retorna obras que tenham todas.
sortqueryenumcreated_atcreated_at | name | price | completion_percentage | updated_at.
orderqueryenumdescasc ou desc.

Requisição

curl "https://obraaberta.com.br/api/v1/projects/by-state/MG"

Resposta

{
  "data": [ /* array de Obra */ ],
  "pagination": { "page": 1, "limit": 50, "total": 18093, "pages": 362 }
}
GET
/projects/by-region
público
Obras dentro de um raio

Busca geográfica: filtra por caixa delimitadora, calcula a distância exata (Haversine) e ordena da mais próxima para a mais distante. Cada item ganha o campo distance_km e a resposta traz o objeto center.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
latitude*querynumberLatitude do centro.
longitude*querynumberLongitude do centro.
radius_kmquerynumber5Raio de busca em km.
pagequeryinteger1Página desejada (começa em 1).
limitqueryinteger50Itens por página. Máximo 500.
cityquerystringNome exato da cidade (sem diferenciar maiúsculas).
statequerystringSigla da UF, ex.: SP.
statusqueryenumlancamento | em_construcao | paralisada | pronto | entregue.
min_pricequerynumberPreço mínimo (R$) a partir do menor valor da obra.
max_pricequerynumberPreço máximo (R$) sobre o menor valor da obra.
bedroomsqueryintegerNúmero exato de dormitórios.
amenitiesquerystringLista separada por vírgula; retorna obras que tenham todas.
sortqueryenumcreated_atcreated_at | name | price | completion_percentage | updated_at.
orderqueryenumdescasc ou desc.

Requisição

curl "https://obraaberta.com.br/api/v1/projects/by-region?latitude=-23.5896&longitude=-46.6383&radius_km=3"

Resposta

{
  "data": [ { /* Obra */ "distance_km": 0.84 } ],
  "pagination": { "page": 1, "limit": 50, "total": 12, "pages": 1 },
  "center": { "latitude": -23.5896, "longitude": -46.6383, "radius_km": 3 }
}
  • 400 bad_request — latitude/longitude ausentes ou inválidas.
GET
/projects/{id}
público
Detalhe da obra

Objeto Obra completo acrescido de timeline (etapas com fotos), ratings (resumo de avaliações), recent_reviews (5 mais recentes) e nearby_services_url.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
id*pathstringUUID da obra ou o slug público (ex.: evolve-vila-mariana).

Requisição

curl "https://obraaberta.com.br/api/v1/projects/evolve-vila-mariana"

Resposta

{
  "id": "0f0a1c7e-4a2b-4e0f-9c3a-2f5d8b1c9e11",
  "slug": "evolve-vila-mariana",
  "name": "Evolve Vila Mariana",
  "description": "Empreendimento residencial com 2 torres...",
  "address": "Rua Domingos de Morais, 1200 - Vila Mariana - São Paulo",
  "neighborhood": "Vila Mariana",
  "city": "São Paulo",
  "state": "SP",
  "cep": "04010-100",
  "phone": "+55 11 4000-0000",
  "geolocation": { "latitude": -23.5896, "longitude": -46.6383 },
  "status": "em_construcao",
  "completion_percentage": 42,
  "total_units": 180,
  "available_units": 37,
  "price_from": 620000,
  "price_to": 1180000,
  "price_per_m2": 12400,
  "total_area": 8600,
  "bedrooms": 2,
  "bathrooms": 2,
  "parking_spaces": 1,
  "amenities": ["piscina", "academia", "coworking"],
  "cover_url": "https://.../capa.jpg",
  "floor_plans": [],
  "constructor": { "id": "…", "name": "Construtora Exemplo" },
  "launch_date": "2024-03-01",
  "completion_date": "2026-12-31",
  "data_sources": ["mcmv", "osm", "brasilapi"],
  "data_quality_score": 0.82,
  "last_enriched_at": "2026-08-01T12:00:00Z",
  "last_updated_at": "2026-08-05T09:31:00Z",
  "created_at": "2025-11-02T18:22:00Z",
  "url": "https://obraaberta.com.br/obras/sp/sao-paulo/vila-mariana/evolve-vila-mariana"
}
  • 404 not_found — obra inexistente ou não publicada.
GET
/projects/{id}/timeline
público
Linha do tempo da obra

Etapas registradas com percentual, data de referência e fotos associadas.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
id*pathstringUUID da obra ou o slug público (ex.: evolve-vila-mariana).
orderqueryenumdescasc | desc por data de referência.

Requisição

curl "https://obraaberta.com.br/api/v1/projects/evolve-vila-mariana/timeline?order=asc"

Resposta

{
  "project_id": "…",
  "timeline": [
    {
      "id": "…",
      "title": "Fundação concluída",
      "description": "…",
      "date": "2025-06-14",
      "completion_percentage": 25,
      "photos": [{ "url": "https://…", "caption": "Vista aérea" }]
    }
  ]
}
GET
/projects/{id}/ratings
público
Avaliações da obra

Avaliações públicas moderadas, com resumo (média e contagem) e lista paginada.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
id*pathstringUUID da obra ou o slug público (ex.: evolve-vila-mariana).
pagequeryinteger1Página desejada (começa em 1).
limitqueryinteger50Itens por página. Máximo 500.

Requisição

curl "https://obraaberta.com.br/api/v1/projects/evolve-vila-mariana/ratings"

Resposta

{
  "summary": { "average": 4.3, "count": 27 },
  "ratings": [ { "rating": 5, "comment": "…", "created_at": "…" } ],
  "pagination": { "page": 1, "limit": 50, "total": 27, "pages": 1 }
}
GET
/projects/{id}/nearby-services
público
Serviços do entorno (OpenStreetMap)

Escolas, hospitais, transporte e comércio num raio configurável, via Overpass API com cache de 7 dias por obra+raio. Dados sob licença ODbL — mantenha a atribuição ao OpenStreetMap.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
id*pathstringUUID da obra ou o slug público (ex.: evolve-vila-mariana).
radius_kmquerynumber2Raio em km. Máximo 10.
typesquerystringLista separada por vírgula: schools, hospitals, transport, commerce.

Requisição

curl "https://obraaberta.com.br/api/v1/projects/evolve-vila-mariana/nearby-services?radius_km=2&types=schools,transport"

Resposta

{
  "schools": [
    { "id": "osm-123", "name": "EMEF …", "distance_km": 0.42, "type": "school", "source": "openstreetmap" }
  ],
  "transport": [],
  "cached": false,
  "attribution": "© OpenStreetMap contributors (ODbL)"
}
POST
/projects/enrich
autenticado
Enriquece uma obra com fontes públicas

Cria um job de enriquecimento e executa as fontes solicitadas de forma síncrona (resposta 202 com o resultado). Fontes não suportadas ou que exigem contrato voltam em skipped_sources. Exige JWT ou chave de API.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
project_id*bodyuuidIdentificador da obra.
sourcesbodystring[]brasilapi | osm | mcmv. Vazio = todas.
force_refreshbodybooleanIgnora o cache das fontes.

Requisição

curl -X POST "https://obraaberta.com.br/api/v1/projects/enrich" \
  -H "X-API-Key: $OBRAABERTA_KEY" \
  -H "Content-Type: application/json" \
  -d '{"project_id":"0f0a1c7e-…","sources":["brasilapi","osm"]}'

Resposta

{
  "job_id": "…",
  "status": "done",
  "updated_fields": ["cep", "bairro", "latitude"],
  "skipped_sources": [{ "source": "orulo", "reason": "Requer contrato." }]
}
  • 401 unauthorized — sem JWT nem chave de API.
  • 404 not_found — obra inexistente.
  • 502 enrichment_failed — a fonte externa falhou.
GET
/jobs/{id}
autenticado
Situação de um job de enriquecimento

Visível apenas para quem criou o job (usuário ou dono da chave) e para administradores; para os demais retorna 404 por privacidade.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
id*pathuuidjob_id devolvido pelo enrich.

Requisição

curl "https://obraaberta.com.br/api/v1/jobs/6b1f…" -H "X-API-Key: $OBRAABERTA_KEY"

Resposta

{
  "job_id": "…",
  "project_id": "…",
  "sources": ["brasilapi"],
  "status": "done",
  "result": { },
  "error": null,
  "created_at": "…",
  "finished_at": "…"
}

Construtoras (Builders)

Cadastro das construtoras, suas obras e o Índice de Sinais de Estresse (ISE), calculado por fórmula pública.

GET
/builders
público
Lista construtoras

Cadastro básico ordenado por nome, com o ISE quando já calculado.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
pagequeryinteger1Página desejada (começa em 1).
limitqueryinteger50Itens por página. Máximo 500.

Requisição

curl "https://obraaberta.com.br/api/v1/builders?limit=100"

Resposta

{
  "data": [
    { "id": "…", "name": "Construtora Exemplo", "slug": "construtora-exemplo",
      "cnpj": "00.000.000/0001-00", "website": "https://…", "headquarters": "São Paulo/SP", "ise_score": 87 }
  ],
  "pagination": { "page": 1, "limit": 100, "total": 340, "pages": 4 }
}
GET
/builders/{id}
público
Dados e reputação da construtora

Cadastro, média de avaliações das obras, indicadores de reputação e ticker na B3 quando houver.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
id*pathstringUUID da construtora ou o slug (ex.: mrv).

Requisição

curl "https://obraaberta.com.br/api/v1/builders/mrv"

Resposta

{
  "id": "…", "slug": "mrv", "name": "MRV", "cnpj": null, "website": "https://…",
  "rating": { "average": 4.1, "count": 88 },
  "reputation": { "ise_score": 74, "completed_projects": 120, "active_projects": 44,
                  "stalled_projects": 2, "delayed_projects": 9, "total_projects": 166, "legal_issues": null },
  "stock_info": { "ticker": "MRVE3" },
  "projects_count": 166
}
  • 404 not_found — construtora sem cadastro e sem obras.
GET
/builders/{id}/projects
público
Obras da construtora

Lista paginada das obras publicadas vinculadas à construtora, com filtro opcional por status.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
id*pathstringUUID da construtora ou o slug (ex.: mrv).
statusqueryenumMesmos valores de /projects.
pagequeryinteger1Página desejada (começa em 1).
limitqueryinteger50Itens por página. Máximo 500.

Requisição

curl "https://obraaberta.com.br/api/v1/builders/mrv/projects?status=em_construcao"

Resposta

{
  "data": [ /* array de Obra */ ],
  "pagination": { "page": 1, "limit": 50, "total": 18093, "pages": 362 }
}
GET
/builders/{id}/reputation
público
Indicadores de reputação (ISE)

Retorna os indicadores e a metodologia: o ISE parte de 100 e desconta proporcionalmente obras atrasadas (peso 60) e paralisadas (peso 40) sobre o total de obras publicadas.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
id*pathstringUUID da construtora ou o slug (ex.: mrv).

Requisição

curl "https://obraaberta.com.br/api/v1/builders/mrv/reputation"

Resposta

{
  "reputation": { "ise_score": 74, "delayed_projects": 9, "stalled_projects": 2, "total_projects": 166 },
  "methodology": "O ISE parte de 100 e desconta…"
}

Dados abertos

Bases públicas incorporadas à plataforma e a relação de fontes utilizadas.

GET
/data/mcmv
público
Empreendimentos do Minha Casa Minha Vida

Base importada dos dados abertos do programa, com unidades, situação, regime e geolocalização quando disponível.

ParâmetroLocalTipoPadrãoAPI REST de leitura com dados públicos de obras residenciais: empreendimentos, construtoras, linha do tempo, avaliações, serviços do entorno e bases abertas. Respostas em JSON, CORS liberado e paginação padronizada.
pagequeryinteger1Página desejada (começa em 1).
limitqueryinteger50Itens por página. Máximo 500.
cityquerystringCidade do empreendimento.
statequerystringSigla da UF.

Requisição

curl "https://obraaberta.com.br/api/v1/data/mcmv?state=BA&limit=100"

Resposta

{
  "mcmv_projects": [
    { "id": "…", "external_code": "…", "name": "Residencial …", "city": "Salvador", "state": "BA",
      "total_units": 240, "units_delivered": 240, "status": "Concluído", "regime": "FAR",
      "geolocation": { "latitude": -12.97, "longitude": -38.5 }, "source": "mcmv" }
  ],
  "pagination": { "page": 1, "limit": 100, "total": 18093, "pages": 181 }
}
GET
/data/public-sources
público
Fontes de dados da plataforma

Relação das fontes públicas usadas, quais estão habilitadas para enriquecimento e quais dependem de contrato/autorização do detentor dos dados.

Requisição

curl "https://obraaberta.com.br/api/v1/data/public-sources"

Resposta

{
  "sources": { "mcmv": { "license": "Dados abertos", "notes": "…" } },
  "enabled_for_enrichment": ["brasilapi", "osm", "mcmv"],
  "notes": "Fontes marcadas como 'requer_contrato' só são ativadas mediante API oficial…"
}

Sistema

Descoberta, disponibilidade e especificação legível por máquina.

GET
/
público
Descoberta da API

Nome, versão e links para documentação e especificação OpenAPI.

Requisição

curl "https://obraaberta.com.br/api/v1"

Resposta

{ "name": "ObraAberta API", "version": "1.0.0",
  "documentation": "https://obraaberta.com.br/api/v1/docs",
  "openapi": "https://obraaberta.com.br/api/v1/openapi.json" }
GET
/health
público
Verificação de disponibilidade

Responde sem consultar o banco; use para monitoramento (uptime checks). Nunca é cacheado.

Requisição

curl "https://obraaberta.com.br/api/v1/health"

Resposta

{ "status": "ok", "version": "1.0.0", "time": "2026-08-11T16:00:00.000Z" }
GET
/openapi.json
público
Especificação OpenAPI 3.0

Contrato completo para gerar SDKs (openapi-generator), importar no Postman/Insomnia ou validar.

Requisição

curl "https://obraaberta.com.br/api/v1/openapi.json"

Resposta

{ "openapi": "3.0.3", "info": { "title": "ObraAberta API", … } }
GET
/docs
público
Swagger UI interativo

Interface para testar os endpoints direto no navegador.

Requisição

open https://obraaberta.com.br/api/v1/docs

Resposta

HTML (Swagger UI)

GraphQL

POST https://obraaberta.com.br/api/v1/graphql

Um único endpoint devolve imóvel, construtora, reputação, entorno e ofertas na mesma consulta. Usa a mesma autenticação do REST. O schema é público e o playground está disponível no mesmo caminho. A profundidade máxima é de 10 níveis; a introspecção via POST exige cliente identificado. /graphql/schema.graphql

Consulta completa

curl -X POST "https://obraaberta.com.br/api/v1/graphql" \
  -H "Content-Type: application/json" \
  -H "X-API-Key: $OBRAABERTA_KEY" \
  -d '{"query":"{
    building(slug: \"evolve-vila-mariana\") {
      name city status completionPercentage delayMonths
      priceFrom priceTo totalUnits availableUnits
      geolocation { latitude longitude }
      builder { name transparencyIndex reputation { score methodologyUrl } }
      reputation { score reviewsCount }
      timeline { title status date }
      nearbyServices(radiusKm: 2, page: 1, limit: 50) {
        nodes { category name distanceKm }
        pageInfo { page limit total pages }
      }
      offers(page: 1, limit: 5) { nodes { title partner price sponsored } pageInfo { total } }
    }
  }"}'

Busca paginada e meus direitos

{
  # Convenção única (igual ao REST v1): filter + sort + order + page + limit
  buildings(
    filter: { state: "SP", status: "em_construcao" }
    sort: created_at
    order: desc
    page: 1
    limit: 50
  ) {
    pageInfo { page limit total pages hasNextPage hasPreviousPage }
    nodes { id slug name neighborhood delayMonths priceFrom }
  }
  buildingsNearby(latitude: -23.58, longitude: -46.63, radiusKm: 3, page: 1, limit: 50) {
    nodes { name city }
    pageInfo { total pages }
    center
  }
  myEntitlements {
    plan planName maxObjectsPerQuery maxExportPerMonth
    labels { label level }
    quotas { hour { used limit } day { used limit } month { used limit } }
  }
}

Mutations (moderadas)

mutation {
  trackOfferClick(offerId: "…") { ok status }
  submitReview(input: {
    buildingId: "…", rating: 5, comment: "Obra evoluiu bem",
    termsVersion: "2026-01", privacyVersion: "2026-01"
  }) { ok status message }
  submitContribution(input: { buildingId: "…", type: "informacao", field: "endereco", value: "…" }) { ok status }
  requestPartnerLead(input: { name: "…", email: "…", message: "…", consent: true }) { ok status }
}

Avaliações e contribuições exigem usuário autenticado e entram na fila de moderação; leads exigem consentimento LGPD explícito. Ofertas patrocinadas são sempre marcadas como sponsored e nunca alteram a ordenação orgânica.

Liberação de campos por plano (entitlements)

Cada campo sensível tem uma etiqueta. Sem direito, o campo volta null — nunca erro — e a resposta explica o porquê em extensions.obraaberta.campos_restritos. Preços podem vir em faixa quando o plano só permite o nível resumo.

EtiquetaCampos cobertos
basicoidentificação, endereço, status, progresso, datas, atraso
geogeolocation, buildingsNearby
precospriceFrom, priceTo, pricePerM2 (faixa no nível resumo)
unidadestotalUnits, availableUnits, tipologias e plantas
contatostelefone e canais de contato
reputacao_detalhadacomponentes da reputação e do Índice de Transparência
fontes_brutasdataSources, dataQualityScore, divergências
entornonearbyServices (POIs OpenStreetMap)
marketplaceoffers, promoções e parceiros
historicotimeline, histórico de status e dados de condomínio
exportacaovolumes altos e exportação em lote
"extensions": {
  "obraaberta": {
    "plano": "anonimo",
    "campos_restritos": [
      { "campo": "totalUnits", "etiqueta": "unidades", "nivelAtual": "bloqueado",
        "nivelExigido": "resumo",
        "mensagem": "O campo \"totalUnits\" exige a etiqueta \"unidades\"." }
    ],
    "limites_atingidos": [
      { "tipo": "objetos_consulta", "detalhe": "Pedido 200 objetos; o plano Anônimo permite 20.",
        "pedido": 200, "aplicado": 20 }
    ],
    "cotas": { "hora": { "uso": 4, "limite": 100 } },
    "upgrade_sugerido": { "id": "pro", "nome": "Pro" },
    "upgrade_url": "https://obraaberta.com.br/planos"
  }
}

A cota do plano foi excedida: a resposta vem com HTTP 429 e code: QUOTA_EXCEEDED.

upgrade_sugerido indica o plano ativo mais barato que libera todas as etiquetas que faltaram naquela requisição. Vem null quando nada foi bloqueado; nas respostas REST v1 os mesmos dados aparecem em entitlements.

Toda requisição que teve campo bloqueado ou limite atingido é registrada na trilha de auditoria de entitlements por 90 dias e fica visível apenas para a equipe ObraAberta. Nenhum conteúdo da consulta ou das variáveis é armazenado.

SDK de exemplo (TypeScript, sem dependências)

// obraaberta.ts
const ENDPOINT = "https://obraaberta.com.br/api/v1/graphql";

export type Resultado<T> = {
  data?: T;
  errors?: { message: string; extensions?: Record<string, unknown> }[];
  extensions?: {
    obraaberta?: {
      plano: string;
      campos_restritos: { campo: string; etiqueta: string; mensagem: string }[];
      cotas: Record<string, { uso: number; limite: number }> | null;
      upgrade_url: string;
    };
  };
};

export function criarCliente(apiKey?: string) {
  return async function consultar<T>(
    query: string,
    variables: Record<string, unknown> = {},
  ): Promise<Resultado<T>> {
    const r = await fetch(ENDPOINT, {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        ...(apiKey ? { "X-API-Key": apiKey } : {}),
      },
      body: JSON.stringify({ query, variables }),
    });
    if (r.status === 429) throw new Error("Cota do plano excedida (429).");
    const json = (await r.json()) as Resultado<T>;
    const bloqueados = json.extensions?.obraaberta?.campos_restritos ?? [];
    if (bloqueados.length) {
      console.warn("Campos bloqueados pelo plano:", bloqueados.map((c) => c.campo).join(", "));
    }
    return json;
  };
}

// uso
const consultar = criarCliente(process.env.OBRAABERTA_KEY);
const { data } = await consultar<{ building: { name: string; delayMonths: number | null } }>(
  `query Obra($slug: String!) {
      building(slug: $slug) { name delayMonths builder { name transparencyIndex } }
    }`,
  { slug: "evolve-vila-mariana" },
);
console.log(data?.building);

O mesmo padrão funciona em Python com requests.post ou em qualquer cliente GraphQL, como Apollo, urql ou graphql-request, apontando para o endpoint acima.

Persisted queries (APQ) e limites

O endpoint aceita Automatic Persisted Queries: envie apenas o hash SHA-256 da consulta. Se o servidor ainda não a conhecer, ele responde PERSISTED_QUERY_NOT_FOUND e basta reenviar o texto da consulta com o hash; a partir daí só o hash é necessário. Consultas têm profundidade máxima de 10 e custo máximo de 1500.

# hash = SHA-256 do texto exato da consulta
# node: crypto.createHash('sha256').update(query).digest('hex')

# 1) tentativa só com o hash
curl -s https://obraaberta.com.br/api/v1/graphql \
  -H 'Content-Type: application/json' -H "X-API-Key: $OBRAABERTA_KEY" \
  -d '{"extensions":{"persistedQuery":{"version":1,"sha256Hash":"<hash>"}}}'
# -> {"errors":[{"message":"PersistedQueryNotFound", ...}]}

# 2) registra a consulta (uma única vez)
curl -s https://obraaberta.com.br/api/v1/graphql \
  -H 'Content-Type: application/json' -H "X-API-Key: $OBRAABERTA_KEY" \
  -d '{"query":"query { buildings(limit: 5) { name } }","extensions":{"persistedQuery":{"version":1,"sha256Hash":"<hash>"}}}'

Planos corporativos podem operar em modo estrito: nele só rodam consultas previamente aprovadas, consultas com texto solto são recusadas e a introspecção fica desativada. O schema continua público; para homologar novas consultas nesse modo, envie o texto para o suporte.

CódigoSignificado
PERSISTED_QUERY_NOT_FOUNDHash desconhecido — reenvie com o texto (modo livre) ou solicite aprovação (modo estrito).
PERSISTED_QUERY_HASH_MISMATCHO hash enviado não corresponde ao texto da consulta.
PERSISTED_QUERY_REQUIREDModo estrito: é obrigatório usar extensions.persistedQuery.
PERSISTED_QUERY_BLOCKEDConsulta bloqueada pela administração.
INTROSPECTION_DISABLEDIntrospecção indisponível para este cliente.

Comparativo com a API da Órulo

RecursoÓruloObraAberta GraphQL
Empreendimento, tipologias, fotossimsim
Consulta única aninhada (GraphQL)nãosim
Atraso de entrega em mesesnãosim
Reputação de construtora, obra e condomínionãosim (fórmula pública)
Obras públicas / Minha Casa Minha Vidanãosim
POIs do entorno (OpenStreetMap)nãosim
Fontes de dados e score de qualidadenãosim
Marketplace e ofertas rotuladasnãosim
Liberação de campos por assinaturanãosim (etiquetas + ACL)

Uso responsável e licenças

  • A API é somente leitura: nenhum endpoint cria ou altera obras. O envio de dados por construtoras passa por cadastro e moderação.
  • Dados sensíveis, como fornecedores, canais privados, financeiro e propostas de leilão, nunca são expostos pela API.
  • Serviços do entorno vêm do OpenStreetMap sob ODbL — mantenha a atribuição © OpenStreetMap contributors.
  • Dados do Minha Casa Minha Vida vêm de bases abertas do governo federal; cite a origem ao republicar.
  • Ao exibir obras, credite a ObraAberta e prefira apontar para a URL canônica do campo url.
  • Use If-None-Match e cache local, respeite os cabeçalhos de rate limit e saiba que chaves com abuso são revogadas.