GetFacade エージェント API
MCP と HTTP による外装設計です。設計はどれも建物のある国に合わせて練られます。その国で使える材料、メーカーがそこで実際に販売している製品、そして表面の裏にある技術的な層構成です。レンダーはそれを住宅の写真の上に示し、見積書は明細ごとに金額を出し、PDF アルバムは施工する職方向けに内容を記録します。以下の各パスは既存の GetFacade エンドポイントであり、iOS・Android・Web の各アプリが呼ぶものと同じです。エージェントキーは呼び出せる相手を絞り、支出を計測し、上限で停止します。
- ベース 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
クイックスタート
キーを発行する
app.getfacade.aiアカウント設定APIキーを作成
値は一度だけ表示され、復元はできず、置き換えのみ可能です。支出上限は発行時に設定し、有料の呼び出しごとに適用されます。
エージェントキーを発行MCP サーバーを登録する
クライアント設定に 1 項目追加し、クライアントを再起動します。Claude Desktop は claude_desktop_config.json に保持します。他の MCP クライアントも同じ 3 つのフィールドを受け取ります。
{ "mcpServers": { "getfacade": { "command": "npx", "args": ["-y", "@getfacade/mcp"], "env": { "GETFACADE_API_KEY": "your-key" } } } }環境変数 変数 必須 既定値 GETFACADE_API_KEYはい —GETFACADE_API_BASE_URLいいえ https://api.getfacade.ai/api/v1または HTTP API を直接呼ぶ
同じキーがベアラートークンとして使えます。リクエストとレスポンスは JSON:API 文書で、id は最上位のフィールドであり、attributes の中には決して入りません。
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"}}}'
ツール
ツールは 21 個です。MCP サーバーは状態も独自の規則も持ちません。各ツールは横に示したエンドポイントへの 1 回以上の呼び出しであり、エージェントが伝えるメッセージはすべて API が書いています。
create_buildingcreate_building(name, goals?, construction_region?) -> { building_id, name }建物を作成します。名前はアカウント内で一意、最大 50 文字です。重複は 422 で拒否されます。
呼び出し先
POST /projectsupload_photoupload_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}/validationstart_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}/rendersrefine_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_jobget_job(job_id, kind: "render" | "album" | "estimate" = "render") -> { status, expected_seconds?, result_url?, error?, error_code? }1 件のレンダー、見積り、アルバムの状態を読みます。
呼び出し先
GET /renders/{render} · GET /estimates/{estimate}list_jobslist_jobs(kind?, limit? = 20) -> [{ job_id, kind, status, building_id, created_at }]アカウント全体の最近のジョブ。未完了のものが先頭です。
呼び出し先
GET /historylist_designslist_designs(building_id) -> [{ design_id, note, has_main_render, main_render_id, main_render_url, renders }]建物のデザインとそのレンダー。見積りやアルバムに渡すレンダー ID はここから得ます。
呼び出し先
GET /projects/{project}/conceptsorder_estimate非同期order_estimate(design_id, render_ids, currency?, measurement_system?, special_requirements?) -> { job_id, status }デザインの費用を明細ごとに、材料と工賃で算出します。金額は指定された材料が建物のある国で持つ価格に基づきます。通貨と単位系は既定でその国に従います。
呼び出し先
POST /projects/{project}/concepts/{concept}/estimatesorder_album非同期order_album(design_id, render_ids, language?, include_blueprints?, include_estimate?, requirements?) -> { job_id, status }施工する職方向けにデザインを記録します。材料、外装の層構成、安全上の注意、その根拠となる規格を収めます。完成した主レンダーが必要です。
呼び出し先
POST /concepts/{concept}/album/generateupscale_render非同期upscale_render(render_id) -> { job_id, status }完成したレンダーを拡大します。トークンを消費し、非同期で実行されます。
呼び出し先
POST /renders/{render}/upscaleget_estimateget_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_lineadd_estimate_line(estimate_id, section, name, quantity, unit_price, unit?, category?) -> { line_id }見積もりに 1 行追加します。単位は見積もり自身の単位系から取られます。
呼び出し先
POST /estimates/{estimate}/itemsupdate_estimate_lineupdate_estimate_line(estimate_id, line_id, name?, quantity?, unit_price?, unit?, category?, section?) -> { line_id }見積もりの 1 行を変更します。渡した項目だけが変わり、合計はサーバーが計算し直します。
呼び出し先
PATCH /estimates/{estimate}/items/{item}delete_estimate_linedelete_estimate_line(estimate_id, line_id) -> { deleted }見積もりから 1 行を削除します。
呼び出し先
DELETE /estimates/{estimate}/items/{item}delete_renderdelete_render(render_id) -> { deleted }レンダーを 1 つ削除します。メインレンダーを削除すると、そのデザインは下書きに戻ります。
呼び出し先
DELETE /renders/{render}delete_designdelete_design(building_id, design_id) -> { deleted }デザインを、その配下のレンダーごと削除します。
呼び出し先
DELETE /projects/{project}/concepts/{concept}delete_buildingdelete_building(building_id) -> { deleted }建物を中身ごと削除します。使用済みのトークンは返金されません。
呼び出し先
DELETE /projects/{project}list_token_packageslist_token_packages() -> [{ package, tokens, price, currency }]このアカウントが購入できるパックを、価格とトークン数つきで返します。
呼び出し先
GET /tokens/packagesbuy_tokens非同期buy_tokens(package) -> { status, transaction_id, tokens, checkout_url?, detail }このキーのウォレットにパックを 1 つ購入します。購入を許可して発行されたキーが必要で、そのキーがまだ使える範囲を超えることはありません。
呼び出し先
POST /tokens/purchaseget_balanceget_balance() -> { balance, scope: "api", spend_cap, spent, remaining, is_admissible }エージェントの残高、このキーの上限、そして次の有料呼び出しが受理されるかどうか。
呼び出し先
GET /tokens/balancereport_problemreport_problem(message, category?, context?: { tool, endpoint, status_code, job_id, expected, actual }) -> { reference, message }この API 自体の不具合を報告します。ここに書かれているのに届かないフィールド、次の一手が読み取れない拒否、依頼と合わない結果など。無料で、残高がなくても受け付けます。返るのは受付番号であり、返信ではありません。
呼び出し先
POST /feedback
認証とキー
- キーは
Authorizationヘッダーのベアラートークンとして送られます。MCP サーバーはGETFACADE_API_KEYから読み取り、それ以外は送りません。 - 値は発行時に一度だけ表示され、保存されるのはハッシュだけです。ローテーションとは新しいキーを発行し、古いキーを失効させることです。
- 各キーには支出上限があり、呼び出しがコントローラーに届く前にサーバー側で適用されます。上限に達して止まるのはそのキーであり、アカウントではありません。
- キーはキーを管理しません。これは人間の操作であり、該当エンドポイントはエージェントキーに 403 を返します。
- 失効は即時に効きます。失効したキーでの呼び出しは 401 を返します。
非同期処理とポーリング
start_design、order_estimate、order_albumはジョブ ID を返して終了します。レンダーには数分かかります。状態が終端になるまでGET /renders/{render}またはGET /estimates/{estimate}を問い合わせてください。- 写真検証の完了はエージェントが持たない WebSocket で通知されます。
GET /angles/{angle}/validationを問い合わせ、validation.is_in_progressを読んでください。状態文字列から終端かどうかを自分で判断しないでください。 - 完成したレンダーとアルバムは、恒久的な公開 URL に置かれます。署名も有効期限もありません。このリンクはそのまま人に渡せます。「結果を見せて」への答えがこれです。署名がないため誰の許可も求めず、受け取った人は誰でも開けますし、あとから取り消すこともできません。
GET /renders/{render}/downloadは別物です。数分で失効し、ファイル名を伴う署名付き URL で、共有用ではなくファイルを保存するためのものです。
キーごとのレート制限
エージェントキーには、同じアカウントの人間のセッションとは別の枠があります。ループに陥ったエージェントが、画面の前にいる人の枠を食い尽くさないためです。拒否は安価で、データベース処理の前にミドルウェアで決まります。
| 対象 | 毎分 | 毎時 |
|---|---|---|
| 読み取りと通常の書き込み | 120 | 2000 |
| 状態と検証のポーリング | 120 | 2000 |
| レンダー・見積り・アルバムの発注 | 10 | 200 |
冪等性
有料の呼び出しはジョブを作り、課金はそのジョブに従います。呼び出しに名前を付けることで、再送しても二つ目が作られず同じジョブが返ります。
- API キーで行う有料の呼び出しには
Idempotency-Keyが必須です。デザインの開始と修正、レンダーの拡大、見積もりやアルバムの注文、見積もりの再生成が対象です。ヘッダーがない場合は 422IDEMPOTENCY_KEY_REQUIREDを返し、キューには何も入りません。 - 値は 8〜191 文字であれば自由で、注文ごとに 1 つ。通常は UUID を使います。新しい注文には新しい値を使ってください。異なる 2 つの値による同一の呼び出しは、2 つのデザインです。
- 同じ値と同じボディで呼び出しを繰り返すと、元のステータスとボディがそのまま返り、応答に
Idempotent-Replay: trueが付きます。キューには何も入らず、二重に課金されることもありません。 - 同じ値で異なるボディの場合は 422
IDEMPOTENCY_KEY_REUSEDを返します。最初の呼び出しの実行中に届いた再送には 409IDEMPOTENCY_IN_PROGRESSを返すので、待ってから同じ呼び出しを再送してください。 - 4xx はいずれもその値を解放するため、原因を直せば同じ値で送り直せます。値はアカウントごとに 24 時間保持されます。
@getfacade/mcpは値の生成も再送も自分で行うため、ツール呼び出しで渡すものはありません。
エラー
失敗は JSON:API のエラー文書で返ります。Laravel のバリデーション応答は JSON:API 形式ではなく、本文を message に持ちます。
| ステータス | コード | 意味 | 再試行の可否 |
|---|---|---|---|
401 | — | キーがない、失効済み、または期限切れです。 | いいえ |
402 | AGENT_CREDITS_EXHAUSTED | アカウントに api スコープのクレジットが残っていません。 | いいえ |
402 | AGENT_KEY_CAP_REACHED | このキーは上限を使い切りました。別のキーを発行するか、上限を引き上げてください。 | いいえ |
403 | — | このエンドポイントは API キーでは利用できません。エージェント API が扱うのは、建物、写真、デザイン、レンダー、見積り、アルバム、API ウォレットです。アカウント、サインイン、支払いの設定は、アプリにサインインした本人が変更します。 | いいえ |
403 | AGENT_PURCHASE_NOT_ALLOWED | このキーは、トークンを購入する権限なしで発行されています。 | いいえ |
403 | AGENT_PURCHASE_EXCEEDS_CAP | この購入はキーの上限額を超えます。 | いいえ |
409 | IDEMPOTENCY_IN_PROGRESS | この Idempotency-Key の最初の呼び出しはまだ応答していません。待ってから同じ呼び出しを再送してください。 | はい |
422 | — | リクエストは理解されたうえで拒否されました。建物名の重複、写真の却下、メインレンダー完了前のアルバム発注などです。 | いいえ |
422 | IDEMPOTENCY_KEY_REQUIRED | API キーによる有料の呼び出しに Idempotency-Key ヘッダーがありません。キューには何も入っていないので、ヘッダーを付けて再送してください。 | いいえ |
422 | IDEMPOTENCY_KEY_REUSED | この Idempotency-Key は別のリクエストで使われています。新しい注文には新しい値を使ってください。 | いいえ |
429 | — | このキー自身の枠を使い切りました。間隔を空けてください。密なループでの再試行はしないでください。 | はい |
人が読む文面は API が呼び出し元の言語で書きます。errors[].detail をそのまま表示し、独自のメッセージを組み立てないでください。
課金と受理
- 有料の呼び出しは
apiスコープのクレジットから引かれ、受け付けはその残高だけを見ます。どのキーもクレジットで支払います。 - 有効な Pro Plan は請求期間ごとに一度、
apiウォレットを 1,000 クレジットまで補充します。それを超える分はクレジットを購入します。 - キーが自分のウォレットを補充できるのは、購入を許可して発行された場合だけで、しかもそのキーがまだ使える範囲までです。購入が上限額を引き上げることはありません。
apiスコープは独立した財布です。無料枠を含むアプリのクレジットがキーによって使われることはありません。- 支出はキー単位で集計されるため、アシスタントごとの消費が個別に見えます。
- 事前確認は
GET /tokens/balanceのフィールドdata.attributes.agent.is_admissibleです。このブロックはエージェントキーにのみ現れ、フラグは受理ミドルウェアをそのまま反映します。残高と上限を自分で比べず、このフラグを読んでください。 - 受理は処理をキューに入れる前に判断されるため、拒否された呼び出しは何も消費しません。
色とブランドのトークン
start_design は独立した 2 つのリストを受け取り、それぞれ最大 10 件です。並び順が 60/30/10 の役割を担い、最初の要素が壁の主色です。
colors
| トークン | 意味 |
|---|---|
palette:1 | GetFacade が用意した配色を ID で指定します。 |
#8A8F7D | 任意の色を 16 進 6 桁で指定します。 |
paint:412 | メーカーの色見本。互換性のために残された 2 セグメント形式です。 |
brand_selections
| トークン | 意味 |
|---|---|
siding:brand:12 | そのカテゴリーにおける、そのメーカーの任意の製品。 |
siding:line:40@double-4-dutchlap | 1 つのシリーズを、1 つの形状で。 |
siding:product:88@double-4-dutchlap | 完全に指定された 1 製品。 |
paint:brand:3 | その塗料ブランドの任意の色。 |
paint:product:412 | 塗料の色見本 1 点。 |
文法は category:level:id[@value][.value] です。@ 以降は形状の値スラッグで、カテゴリー内で一意のため、どの軸に属するかはトークンに書かず参照で解決します。未知のトークンは 422 で拒否され、黙って無視されることはありません。
一連のセッション
建物 1 件、写真 1 枚、デザイン 1 件、そして 2 つの文書。これを生む指示は次のとおりです。
Maple Street 14 という建物を作成し、./front.jpg をそのビューとしてアップロードし、暖かいグレーの壁と白い枠でデザインを開始してください。その結果について見積りとアルバムを発注してください。
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)