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
빠른 시작
키 발급
app.getfacade.ai계정설정API키 만들기
값은 한 번만 표시되며 복구할 수 없고 교체만 가능합니다. 지출 한도는 발급 시 정하며 유료 호출마다 적용됩니다.
에이전트 키 발급MCP 서버 등록
클라이언트 설정에 항목 하나를 추가한 뒤 클라이언트를 다시 시작합니다. Claude Desktop은 claude_desktop_config.json에 보관하며, 다른 MCP 클라이언트도 같은 세 필드를 받습니다.
{ "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 직접 호출
같은 키를 Bearer 토큰으로 사용합니다. 요청과 응답은 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"}}}'
도구
도구는 스물한 개입니다. MCP 서버는 상태도, 자체 규칙도 두지 않습니다. 각 도구는 옆에 적힌 엔드포인트로의 한 번 또는 여러 번의 호출이며, 에이전트가 전하는 모든 메시지는 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? }렌더, 견적, 앨범 하나의 상태를 읽습니다.
호출
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 }견적에 한 줄을 추가합니다. 단위는 견적 자체의 도량형에서 가져옵니다.
호출
POST /estimates/{estimate}/itemsupdate_estimate_lineupdate_estimate_line(estimate_id, line_id, name?, quantity?, unit_price?, unit?, category?, section?) -> { line_id }견적의 한 줄을 수정합니다. 보낸 필드만 바뀌고 합계는 서버가 다시 계산합니다.
호출
PATCH /estimates/{estimate}/items/{item}delete_estimate_linedelete_estimate_line(estimate_id, line_id) -> { deleted }견적에서 한 줄을 삭제합니다.
호출
DELETE /estimates/{estimate}/items/{item}delete_renderdelete_render(render_id) -> { deleted }렌더 하나를 삭제합니다. 메인 렌더를 삭제하면 해당 디자인은 초안으로 돌아갑니다.
호출
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 }이 키의 지갑으로 패키지 하나를 구매합니다. 구매가 허용된 키가 필요하며, 키가 아직 쓸 수 있는 범위를 넘지 않습니다.
호출
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헤더의 Bearer 토큰으로 전달됩니다. MCP 서버는GETFACADE_API_KEY에서 읽으며 그 밖의 것은 보내지 않습니다. - 값은 발급 시 한 번만 표시되고 해시만 저장됩니다. 교체란 새 키를 발급하고 이전 키를 폐기하는 것입니다.
- 모든 키에는 지출 한도가 있으며, 호출이 컨트롤러에 닿기 전에 서버에서 적용됩니다. 한도에 도달하면 그 키가 멈추며 계정은 멈추지 않습니다.
- 키는 키를 관리하지 않습니다. 이는 사람의 작업이며 해당 엔드포인트는 에이전트 키에 403을 반환합니다.
- 폐기는 즉시 적용됩니다. 폐기된 키의 호출은 401을 받습니다.
비동기 작업과 상태 조회
start_design,order_estimate,order_album은 작업 ID를 반환하고 종료됩니다. 렌더는 몇 분이 걸립니다. 상태가 최종이 될 때까지GET /renders/{render}또는GET /estimates/{estimate}를 조회하세요.- 사진 검증 완료는 에이전트에게 없는 웹소켓으로 알립니다.
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자 사이의 값이면 무엇이든 되고, 주문마다 하나씩 씁니다. 보통 UUID를 사용합니다. 새 주문에는 새 값을 쓰세요. 서로 다른 두 값으로 보낸 동일한 호출은 두 개의 디자인입니다.
- 같은 값과 같은 본문으로 호출을 반복하면 원래의 상태 코드와 본문이 그대로 돌아오고, 응답에
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은 각각 최대 열 개 항목의 독립된 두 목록을 받습니다. 순서가 60/30/10 역할을 담으며, 첫 항목이 벽의 주된 색입니다.
colors
| 토큰 | 의미 |
|---|---|
palette:1 | GetFacade가 준비한 배색을 ID로 지정합니다. |
#8A8F7D | 자유로운 색상, 16진수 여섯 자리. |
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]입니다. @ 뒤 부분은 형상 값 슬러그이며 카테고리 안에서 고유하므로, 어느 축에 속하는지는 토큰에 적지 않고 조회로 정합니다. 알 수 없는 토큰은 422로 거절되며 조용히 무시되지 않습니다.
전 과정 세션
건물 하나, 사진 한 장, 디자인 하나, 그리고 두 개의 문서. 이를 만드는 지시는 다음과 같습니다.
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)