API para agentes da GetFacade

Projeto de fachada sobre MCP e HTTP. Cada projeto é elaborado para o país onde o edifício se encontra: materiais aplicáveis ali, produtos que os fabricantes ali vendem realmente e a composição técnica por trás da superfície. Um render mostra-o na foto da casa, o orçamento valoriza-o linha a linha e o álbum PDF documenta-o para a equipa que o executa. Cada caminho abaixo é um endpoint GetFacade já existente, o mesmo que as apps iOS, Android e web chamam. Uma chave de agente apenas restringe quem pode chamá-lo, mede o que gasta e para no seu teto.

URL base
https://api.getfacade.ai/api/v1
Autenticação
Bearer <agent key>
Pacote
@getfacade/mcp
Ambiente de execução
Node.js 20+
Transporte
stdio (MCP), HTTPS (REST)
Especificação
OpenAPI 3.1, v1.0.0

Início rápido

  1. Emitir uma chave

    app.getfacade.aiContaConfiguraçõesAPICriar chave

    O valor é mostrado uma única vez e não pode ser recuperado, apenas substituído. O limite de gasto define-se na emissão e é aplicado em cada chamada paga.

    Emitir uma chave de agente
  2. Registar o servidor MCP

    Uma entrada na configuração do cliente e depois reiniciar o cliente. O Claude Desktop guarda-a em claude_desktop_config.json; qualquer outro cliente MCP aceita os mesmos três campos.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    Variáveis de ambiente
    VariávelObrigatóriaValor por omissão
    GETFACADE_API_KEYSim
    GETFACADE_API_BASE_URLNãohttps://api.getfacade.ai/api/v1
  3. Ou chamar a API HTTP diretamente

    A mesma chave funciona como token Bearer. Pedidos e respostas são documentos JSON:API, onde id é um campo de primeiro nível e nunca fica dentro de attributes.

    shell
    curl -X POST https://api.getfacade.ai/api/v1/projects \
      -H "Authorization: Bearer $GETFACADE_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{"data":{"type":"project","attributes":{"name":"Maple Street 14"}}}'

Ferramentas

Vinte e uma ferramentas. O servidor MCP não guarda estado nem regras próprias: cada ferramenta é uma ou mais chamadas aos endpoints indicados ao lado, e cada mensagem que o agente repete é escrita pela API.

  • create_building
    create_building(name, goals?, construction_region?)
      -> { building_id, name }

    Cria um edifício. O nome é único dentro da conta e tem no máximo 50 caracteres; um duplicado é recusado com 422.

    ChamaPOST /projects

  • upload_photo
    upload_photo(building_id, file_path, wait_for_validation? = true)
      -> { view_id, validation: { status, reason? } }

    Regista uma vista, carrega os bytes para um URL pré-assinado, confirma-os e consulta até a foto ser aceite ou recusada. Largura, altura e md5 são calculados localmente; a proporção é deduzida pelo servidor.

    ChamaPOST /projects/{project}/angles → PUT (presigned) → POST /angles/{angle}/confirm → GET /angles/{angle}/validation

  • start_designassíncrona
    start_design(building_id, view_id, prompt?, style_ids?, colors?,
                 brand_selections?, render_effort?, seed?)
      -> { design_id, job_id, status, seed }

    Projeta a fachada numa vista escolhida e mostra-a na foto: materiais aplicáveis no país do edifício, produtos ali realmente vendidos e a composição por trás da superfície. Cria um projeto, coloca o trabalho em fila e devolve o id do trabalho. A seed é opcional: se for omitida, o servidor gera-a e devolve-a.

    ChamaPOST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/renders

  • refine_designassíncrona
    refine_design(render_id | design_id + building_id, instruction,
                  style_ids?, colors?, brand_selections?, render_effort?, seed?)
      -> { design_id, job_id, status, parent_render_id, seed }

    Revê por palavras um projeto terminado. A instrução aplica-se ao projeto terminado, pelo que fica tudo o que ela não menciona. Rever uma vista principal cria um projeto novo, de modo que o anterior nunca é substituído.

    ChamaGET /renders/{render} → POST /concepts/{concept}/angles/{conceptAngle}/renders (mode: refine)

  • get_job
    get_job(job_id, kind: "render" | "album" | "estimate" = "render")
      -> { status, expected_seconds?, result_url?, error?, error_code? }

    Lê o estado de um render, de um orçamento ou de um álbum.

    ChamaGET /renders/{render} · GET /estimates/{estimate}

  • list_jobs
    list_jobs(kind?, limit? = 20)
      -> [{ job_id, kind, status, building_id, created_at }]

    Tarefas recentes da conta, as inacabadas primeiro.

    ChamaGET /history

  • list_designs
    list_designs(building_id)
      -> [{ design_id, note, has_main_render, main_render_id,
           main_render_url, renders }]

    Designs de um edifício com os seus renders. É daqui que vêm os identificadores de render para o orçamento e o álbum.

    ChamaGET /projects/{project}/concepts

  • order_estimateassíncrona
    order_estimate(design_id, render_ids, currency?,
                   measurement_system?, special_requirements?)
      -> { job_id, status }

    Valoriza o projeto linha a linha, em materiais e mão de obra, aos preços que esses materiais têm no país do edifício. A moeda e o sistema de medida seguem por omissão esse país.

    ChamaPOST /projects/{project}/concepts/{concept}/estimates

  • order_albumassíncrona
    order_album(design_id, render_ids, language?, include_blueprints?,
                include_estimate?, requirements?)
      -> { job_id, status }

    Documenta o projeto para a equipa que o executa: os materiais, a composição da fachada, as notas de segurança e as normas que as sustentam. Exige um render principal concluído.

    ChamaPOST /concepts/{concept}/album/generate

  • upscale_renderassíncrona
    upscale_render(render_id)
      -> { job_id, status }

    Amplia um render concluído. Custa créditos e é executado de forma assíncrona.

    ChamaPOST /renders/{render}/upscale

  • get_estimate
    get_estimate(estimate_id)
      -> { status, currency, facade_area, materials_total, labor_total,
           grand_total, notes, lines: [{ line_id, section, name, quantity,
           unit, unit_price, line_total }] }

    O orçamento em si: totais, os pressupostos por trás deles e cada linha com quantidade, unidade e preço. get_job informa o estado de um orçamento, nunca o seu conteúdo.

    ChamaGET /estimates/{estimate}

  • add_estimate_line
    add_estimate_line(estimate_id, section, name, quantity,
                      unit_price, unit?, category?)
      -> { line_id }

    Adiciona uma linha ao orçamento. As unidades vêm do seu próprio sistema de medida.

    ChamaPOST /estimates/{estimate}/items

  • update_estimate_line
    update_estimate_line(estimate_id, line_id, name?, quantity?,
                         unit_price?, unit?, category?, section?)
      -> { line_id }

    Altera uma linha do orçamento. Só os campos enviados mudam; o servidor recalcula os totais.

    ChamaPATCH /estimates/{estimate}/items/{item}

  • delete_estimate_line
    delete_estimate_line(estimate_id, line_id)
      -> { deleted }

    Remove uma linha do orçamento.

    ChamaDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    Apaga um render. Apagar o render principal devolve o design ao estado de rascunho.

    ChamaDELETE /renders/{render}

  • delete_design
    delete_design(building_id, design_id)
      -> { deleted }

    Apaga um design com os renders que contém.

    ChamaDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    Apaga um edifício com tudo o que contém. Os créditos já gastos não são devolvidos.

    ChamaDELETE /projects/{project}

  • list_token_packages
    list_token_packages()
      -> [{ package, tokens, price, currency }]

    Os pacotes que esta conta pode comprar, com preço e número de créditos.

    ChamaGET /tokens/packages

  • buy_tokensassíncrona
    buy_tokens(package)
      -> { status, transaction_id, tokens, checkout_url?, detail }

    Compra um pacote para a carteira desta chave. Exige uma chave emitida com a compra ativada e nunca ultrapassa o que a chave ainda pode gastar.

    ChamaPOST /tokens/purchase

  • get_balance
    get_balance()
      -> { balance, scope: "api", spend_cap, spent, remaining, is_admissible }

    Carteira do agente, limite desta chave e se a próxima chamada paga será admitida.

    ChamaGET /tokens/balance

  • report_problem
    report_problem(message, category?,
                   context?: { tool, endpoint, status_code, job_id,
                               expected, actual })
      -> { reference, message }

    Relata um defeito desta API: um campo descrito aqui que nunca chega, uma recusa cuja redação não indica o passo seguinte, um resultado que não corresponde ao pedido. Gratuito e aceite com saldo vazio; volta uma referência, não uma resposta.

    ChamaPOST /feedback

Autenticação e chaves

  • A chave viaja como token Bearer no cabeçalho Authorization. O servidor MCP lê-a de GETFACADE_API_KEY e não envia mais nada.
  • O valor é mostrado uma vez, na emissão, e apenas o seu hash é guardado. Rodar significa emitir uma chave nova e revogar a antiga.
  • Cada chave tem um limite de gasto, aplicado no servidor antes de a chamada chegar a um controlador. Atingir o limite para essa chave, não a conta.
  • As chaves não gerem chaves: isso é uma ação humana, e esses endpoints respondem 403 a uma chave de agente.
  • A revogação tem efeito imediato. Chamadas com uma chave revogada respondem 401.

Trabalho assíncrono e consulta de estado

  • start_design, order_estimate e order_album devolvem um identificador de tarefa e terminam. Um render demora minutos: consulte GET /renders/{render} ou GET /estimates/{estimate} até o estado ser terminal.
  • O fim da validação da foto é anunciado por um websocket que o agente não tem. Consulte GET /angles/{angle}/validation e leia validation.is_in_progress; não deduza a terminalidade a partir da cadeia de estado.
  • Um render concluído e um álbum concluído ficam em URL públicos permanentes: sem assinatura e sem prazo. A ligação pode ser entregue diretamente a uma pessoa, como resposta a «mostra-me o resultado». Por não estar assinada, não pede autorização a ninguém: continua a funcionar para quem quer que a receba e não pode ser revogada.
  • GET /renders/{render}/download é outra coisa: um URL assinado que expira em minutos e traz um nome de ficheiro. Serve para guardar o ficheiro, não para o partilhar.

Limites de frequência por chave

Uma chave de agente tem contadores próprios, separados das sessões humanas da mesma conta, para que um agente em ciclo não consuma a quota de quem está ao ecrã. A recusa é barata: é decidida no middleware, antes de qualquer trabalho na base de dados.

ÂmbitoPor minutoPor hora
Leituras e escritas comuns1202000
Consulta de estados e validação1202000
Encomendas de render, orçamento e álbum10200

Idempotência

Uma chamada paga cria uma tarefa, e a cobrança segue a tarefa. Dar nome à chamada é o que permite que um reenvio devolva a mesma tarefa em vez de criar uma segunda.

  • Idempotency-Key é obrigatório em qualquer chamada paga feita com uma chave de API: iniciar ou aperfeiçoar um design, ampliar um render, encomendar um orçamento ou um álbum, regenerar um orçamento. Sem ele a chamada responde 422 IDEMPOTENCY_KEY_REQUIRED e nada entra na fila.
  • Qualquer valor de 8 a 191 caracteres, um por encomenda; o habitual é um UUID. Uma encomenda nova leva um valor novo: duas chamadas iguais com dois valores são dois designs.
  • Repetir uma chamada com o mesmo valor e o mesmo corpo devolve o estado e o corpo originais, com Idempotent-Replay: true na resposta. Nada entra na fila e nada é cobrado duas vezes.
  • O mesmo valor com um corpo diferente responde 422 IDEMPOTENCY_KEY_REUSED. Um reenvio que chega enquanto a primeira chamada ainda decorre responde 409 IDEMPOTENCY_IN_PROGRESS: espere e envie a mesma chamada de novo.
  • Qualquer 4xx liberta o valor, portanto pode ser enviado de novo assim que a causa for corrigida. Os valores ficam em memória 24 horas, por conta.
  • @getfacade/mcp gera o valor e repete a chamada com ele sozinho, por isso não há nada a passar na chamada da ferramenta.

Erros

As falhas chegam como documentos de erro JSON:API. As respostas de validação do Laravel não têm forma JSON:API e trazem o texto em message.

EstadoCódigoSignificadoRepetível
401A chave falta, foi revogada ou expirou.Não
402AGENT_CREDITS_EXHAUSTEDA conta não tem mais créditos de âmbito api.Não
402AGENT_KEY_CAP_REACHEDEsta chave esgotou o seu limite. Emita outra chave ou aumente o limite.Não
403Este endpoint não está disponível para chaves de API. A API para agentes abrange edifícios, fotos, designs, renderizações, orçamentos, álbuns e a carteira de API. As definições de conta, de início de sessão e de pagamento são alteradas por uma pessoa com sessão iniciada na aplicação.Não
403AGENT_PURCHASE_NOT_ALLOWEDEsta chave foi emitida sem permissão para comprar créditos.Não
403AGENT_PURCHASE_EXCEEDS_CAPA compra levaria a chave além do seu teto de gasto.Não
409IDEMPOTENCY_IN_PROGRESSA primeira chamada com este Idempotency-Key ainda não respondeu. Espere e envie a mesma chamada de novo.Sim
422O pedido foi compreendido e recusado: nome de edifício duplicado, foto rejeitada, álbum encomendado antes de o render principal terminar.Não
422IDEMPOTENCY_KEY_REQUIREDUma chamada paga com chave de API e sem cabeçalho Idempotency-Key. Nada entrou na fila; envie-a de novo com o cabeçalho.Não
422IDEMPOTENCY_KEY_REUSEDEste Idempotency-Key foi usado noutro pedido. Use um valor novo para uma encomenda nova.Não
429O contador próprio desta chave está esgotado. Abrande, não repita em ciclo apertado.Sim

O texto legível é escrito pela API, na língua de quem chama. Mostre errors[].detail tal como está, em vez de compor a sua própria mensagem.

Faturação e admissão

  • As chamadas pagas consomem créditos do escopo api, e a admissão olha apenas para esse saldo: cada chave paga em créditos.
  • Um Pro Plan ativo completa a carteira api até 1000 créditos uma vez por período de faturação. Além disso, os créditos são comprados.
  • Uma chave recarrega a própria carteira apenas se foi emitida com a compra ativada, e só até o que ainda pode gastar, por isso uma compra nunca levanta o teto de gasto.
  • O âmbito api é uma carteira à parte. Os créditos da aplicação, incluindo o nível gratuito, nunca são gastos por uma chave.
  • O gasto é contado por chave, pelo que o consumo de cada assistente é visível em separado.
  • A verificação prévia é GET /tokens/balance, campo data.attributes.agent.is_admissible. O bloco só aparece em chaves de agente e o indicador espelha exatamente o middleware de admissão. Leia-o em vez de comparar o saldo com o limite.
  • A admissão é decidida antes de qualquer trabalho entrar em fila, por isso uma chamada recusada não gasta nada.

Tokens de cor e de marca

start_design aceita duas listas independentes com dez entradas no máximo. A ordem carrega o papel 60/30/10: a primeira entrada é a cor dominante das paredes.

colors

TokenSignificado
palette:1Um esquema selecionado da GetFacade, por identificador.
#8A8F7DUma cor livre, seis dígitos hexadecimais.
paint:412Uma amostra de fabricante, na forma de dois segmentos mantida por compatibilidade.

brand_selections

TokenSignificado
siding:brand:12Qualquer produto desse fabricante nessa categoria.
siding:line:40@double-4-dutchlapUma linha, numa geometria.
siding:product:88@double-4-dutchlapUm produto, totalmente especificado.
paint:brand:3Qualquer cor dessa marca de tintas.
paint:product:412Uma amostra de tinta.

A gramática é category:level:id[@value][.value]. A parte depois de @ leva slugs de valores de geometria, únicos dentro da sua categoria, pelo que o eixo a que pertencem é procurado em vez de escrito no token. Um token desconhecido é recusado com 422 e nunca ignorado em silêncio.

Sessão de ponta a ponta

Um edifício, uma foto, um design e depois os dois documentos. A instrução que o produz:

Cria um edifício chamado Maple Street 14, carrega ./front.jpg como a sua vista e inicia um design com paredes cinzento quente e molduras brancas. Encomenda o orçamento e o álbum para o resultado.
Sessão MCP
create_building(name: "Maple Street 14")
  -> { building_id: "0f8c…" }

upload_photo(building_id: "0f8c…", file_path: "./front.jpg")
  -> { view_id: "41ab…", validation: { status: "approved" } }

start_design(building_id: "0f8c…", view_id: "41ab…",
             colors: ["#8A8F7D", "#F2F0EB"],
             brand_selections: ["siding:line:40@double-4-dutchlap"])
  -> { design_id: "7d21…", job_id: "b933…", status: "queued" }

get_job(job_id: "b933…")
  -> { status: "completed", result_url: "https://…" }

refine_design(render_id: "b933…",
              instruction: "put a canopy over the front door")
  -> { design_id: "9e44…", job_id: "c07f…", status: "queued" }

order_estimate(design_id: "9e44…", render_ids: ["c07f…"])
order_album(design_id: "9e44…", render_ids: ["c07f…"], include_estimate: true)

Recursos