GetFacade 智能体 API

通过 MCP 与 HTTP 进行外立面设计。每一份设计都按建筑所在的国家推敲:那里可用的材料、厂商在当地确实销售的产品,以及表面之后的技术构造层次。渲染把它呈现在房屋照片上,预算逐项算出金额,PDF 图册则为施工班组记录下来。下面每一条路径都是已有的 GetFacade 接口,与 iOS、Android 和网页应用调用的完全相同。智能体密钥只是收窄了谁可以调用,计量支出,并在上限处停止。

基础 URL
https://api.getfacade.ai/api/v1
认证方式
Bearer <agent key>
软件包
@getfacade/mcp
运行环境
Node.js 20+
传输方式
stdio (MCP), HTTPS (REST)
规范
OpenAPI 3.1, v1.0.0

快速开始

  1. 签发密钥

    app.getfacade.ai账户设置API创建密钥

    密钥值仅显示一次,无法找回,只能替换。支出上限在签发时设定,并在每次付费调用时生效。

    签发智能体密钥
  2. 注册 MCP 服务器

    在客户端配置中加入一条记录,然后重启客户端。Claude Desktop 将其保存在 claude_desktop_config.json 中;其他 MCP 客户端接受同样的三个字段。

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    环境变量
    变量必填默认值
    GETFACADE_API_KEY
    GETFACADE_API_BASE_URLhttps://api.getfacade.ai/api/v1
  3. 或直接调用 HTTP API

    同一把密钥可作为 Bearer 令牌使用。请求与响应均为 JSON:API 文档,其中 id 是顶层字段,绝不放在 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"}}}'

工具

共二十一个工具。MCP 服务器不保存状态,也没有自己的规则:每个工具都是对旁边所列端点的一次或多次调用,智能体转述的每条消息都由 API 撰写。

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

    创建建筑。名称在账户内唯一,最长 50 个字符;重名会以 422 拒绝。

    调用POST /projects

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

    登记视角,将字节上传至预签名 URL,确认后轮询,直到照片被接受或拒绝。宽、高与 md5 在本地计算,宽高比由服务器推导。

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

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

    在选定的视角上设计外立面,并呈现在照片上:建筑所在国家可用的材料、当地确实有售的产品,以及表面之后的构造层次。创建一个设计,把工作排入队列,并返回任务 id。seed 是可选的:省略时由服务端生成并返回。

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

  • refine_design异步
    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 }

    用文字修改已完成的设计。指令作用于已完成的设计,因此未提到的部分都会保留。修改主视角会生成一个新的设计,因此先前那个永远不会被覆盖。

    调用GET /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? }

    读取单个渲染、估算或图册的状态。

    调用GET /renders/{render} · GET /estimates/{estimate}

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

    账户内的近期任务,未完成的排在前面。

    调用GET /history

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

    某建筑的设计及其渲染。估算和图册所需的渲染 ID 由此获得。

    调用GET /projects/{project}/concepts

  • order_estimate异步
    order_estimate(design_id, render_ids, currency?,
                   measurement_system?, special_requirements?)
      -> { job_id, status }

    为设计逐项算出材料与人工的金额,价格取自所选材料在建筑所在国家的行情。货币与计量单位默认取自该国家。

    调用POST /projects/{project}/concepts/{concept}/estimates

  • order_album异步
    order_album(design_id, render_ids, language?, include_blueprints?,
                include_estimate?, requirements?)
      -> { job_id, status }

    为施工班组记录设计:材料、外立面的构造层次、安全提示,以及支撑它们的规范。需要已完成的主渲染。

    调用POST /concepts/{concept}/album/generate

  • upscale_render异步
    upscale_render(render_id)
      -> { job_id, status }

    放大一张已完成的效果图。消耗额度,异步执行。

    调用POST /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 }] }

    报价本身:合计、背后的假设,以及带有数量、单位和单价的每一行。get_job 只报告报价的状态,从不给出内容。

    调用GET /estimates/{estimate}

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

    为预算添加一行。单位取自该预算自身的度量制。

    调用POST /estimates/{estimate}/items

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

    修改预算中的一行。只改动传入的字段,合计由服务端重新计算。

    调用PATCH /estimates/{estimate}/items/{item}

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

    从预算中删除一行。

    调用DELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    删除一张效果图。删除主效果图会让其设计退回草稿。

    调用DELETE /renders/{render}

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

    删除一个设计及其下属的效果图。

    调用DELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    删除一栋建筑及其全部内容。已花费的额度不予退还。

    调用DELETE /projects/{project}

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

    该账户可购买的额度包,含价格与额度数量。

    调用GET /tokens/packages

  • buy_tokens异步
    buy_tokens(package)
      -> { status, transaction_id, tokens, checkout_url?, detail }

    为此密钥的钱包购买一个额度包。需要创建时开启了购买权限的密钥,且绝不超过该密钥还可以支出的额度。

    调用POST /tokens/purchase

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

    智能体钱包、该密钥的上限,以及下一次付费调用是否会被放行。

    调用GET /tokens/balance

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

    报告这个 API 自身的缺陷:此处写明却从未返回的字段、看不出下一步该怎么走的拒绝、与所求不符的结果。免费,余额为空时同样受理;返回的是受理编号,而不是回复。

    调用POST /feedback

认证与密钥

  • 密钥以 Bearer 令牌的形式放在 Authorization 头中。MCP 服务器从 GETFACADE_API_KEY 读取,不额外发送任何内容。
  • 密钥值在签发时仅显示一次,服务器只保存其哈希。轮换即签发新密钥并吊销旧密钥。
  • 每把密钥都带有支出上限,在调用抵达控制器之前由服务器执行。达到上限只会停用这把密钥,不会停用账户。
  • 密钥不能管理密钥:这是人工操作,相关端点对智能体密钥返回 403。
  • 吊销立即生效。使用已吊销密钥的调用返回 401。

异步任务与轮询

  • start_designorder_estimateorder_album 返回任务 ID 后即结束。渲染需要数分钟:轮询 GET /renders/{render}GET /estimates/{estimate},直到状态为终态。
  • 照片校验完成通过智能体所没有的 WebSocket 通知。请轮询 GET /angles/{angle}/validation 并读取 validation.is_in_progress;不要自行从状态字符串判断是否为终态。
  • 完成的渲染和图册位于永久的公开地址:没有签名,也没有有效期。这个链接可以直接交给他人,正是对「把结果给我看」的回答。因为没有签名,它不会向任何人索取许可:拿到的人都能打开,事后也无法收回。
  • GET /renders/{render}/download 是另一回事:一个几分钟内过期、带文件名的签名 URL,用于保存文件,而不是用于分享。

按密钥计的频率限制

智能体密钥拥有独立配额,与同一账户的人工会话分开,这样陷入循环的智能体不会吃掉屏幕前那个人的额度。拒绝的代价很低:它在中间件中判定,先于任何数据库操作。

范围每分钟每小时
读取与常规写入1202000
状态与校验轮询1202000
渲染、估算与图册的下单10200

幂等性

付费调用会创建一个任务,费用跟着任务走。给调用起个名字,重发时才会返回同一个任务,而不是再建一个。

  • 用 API 键发出的每一次付费调用都必须带 Idempotency-Key:开始或修改设计、放大渲染图、订购预算或相册、重新生成预算。缺少该头时,调用返回 422 IDEMPOTENCY_KEY_REQUIRED,不会有任何任务入队。
  • 值为 8 到 191 个字符,每笔订单一个,通常用 UUID。新的订单换用新的值:两个值下的两次相同调用就是两个设计。
  • 用相同的值和相同的请求体重复调用,会原样返回最初的状态码和响应体,并在响应中带上 Idempotent-Replay: true。不会入队,也不会重复计费。
  • 相同的值配上不同的请求体,返回 422 IDEMPOTENCY_KEY_REUSED。在第一次调用尚未完成时到达的重发,返回 409 IDEMPOTENCY_IN_PROGRESS:稍候,再发送同一次调用。
  • 任何 4xx 都会释放该值,原因修复后可以用同一个值重发。值按账户保存 24 小时。
  • @getfacade/mcp 会自行生成该值并用它重发,因此工具调用中无需传任何东西。

错误

失败以 JSON:API 错误文档返回。Laravel 的校验响应不是 JSON:API 结构,其文本位于 message 字段。

状态码代码含义可否重试
401密钥缺失、已吊销或已过期。
402AGENT_CREDITS_EXHAUSTED账户已没有 api 范围的额度。
402AGENT_KEY_CAP_REACHED该密钥已用尽上限。请签发新密钥或提高上限。
403此端点不对 API 密钥开放。代理 API 涵盖建筑、照片、设计、渲染图、报价、图册和 API 钱包。账户、登录和付款设置由已登录应用的本人更改。
403AGENT_PURCHASE_NOT_ALLOWED此密钥在创建时未开启购买额度的权限。
403AGENT_PURCHASE_EXCEEDS_CAP这笔购买会让密钥超出其支出上限。
409IDEMPOTENCY_IN_PROGRESS使用该 Idempotency-Key 的第一次调用尚未返回。请稍候,再发送同一次调用。
422请求被理解并拒绝:建筑名称重复、照片被拒、在主渲染完成前订购图册。
422IDEMPOTENCY_KEY_REQUIRED用 API 键发出的付费调用缺少 Idempotency-Key 头。没有任何任务入队,请带上该头重新发送。
422IDEMPOTENCY_KEY_REUSEDIdempotency-Key 已用于另一个请求。新的订单请使用新的值。
429该密钥自身的配额已用尽。请退避等待,不要在紧密循环中重试。

面向人的文本由 API 以调用方的语言撰写。请原样展示 errors[].detail,不要自行拼装消息。

计费与准入

  • 付费调用从 api 作用域的额度中扣除,准入只看这个余额:每个密钥都用额度付费。
  • 有效的 Pro Plan 每个计费周期一次,将 api 钱包补足到 1,000 额度。超出部分需要购买额度。
  • 只有在创建时开启了购买权限,密钥才能补充自己的钱包,且最多只能补到它还可以支出的额度,因此购买绝不会抬高支出上限。
  • api 范围是独立钱包。应用内的额度,包括免费层,永远不会被密钥消耗。
  • 支出按密钥计量,因此每个助手的消耗都能单独看到。
  • 预检为 GET /tokens/balancedata.attributes.agent.is_admissible 字段。该区块仅在智能体密钥下出现,标志位与准入中间件完全一致。请读取该标志,而不要自行比较余额与上限。
  • 准入在任务入队之前判定,因此被拒绝的调用不消耗任何额度。

颜色与品牌令牌

start_design 接受两个相互独立的列表,每个最多十项。顺序承担 60/30/10 的角色:第一项是墙面的主色。

colors

令牌含义
palette:1按 ID 指定 GetFacade 预设配色。
#8A8F7D自由颜色,六位十六进制。
paint:412厂商色卡,采用为兼容而保留的两段式写法。

brand_selections

令牌含义
siding:brand:12该厂商在该品类下的任意产品。
siding:line:40@double-4-dutchlap一个系列,配一种造型。
siding:product:88@double-4-dutchlap完全指定的一款产品。
paint:brand:3该涂料品牌的任意颜色。
paint:product:412一款涂料色卡。

语法为 category:level:id[@value][.value]。@ 之后是造型取值的 slug,在其品类内唯一,因此所属的轴通过查询确定,而不写进令牌。未知令牌以 422 拒绝,绝不会被悄悄忽略。

端到端会话

一栋建筑、一张照片、一个设计,然后是两份文档。产生它的指令如下:

创建一栋名为 Maple Street 14 的建筑,把 ./front.jpg 作为它的视角上传,并以暖灰色墙面和白色线脚开始一个设计。为结果订购估算和图册。
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)

资料