API agen GetFacade
Perancangan fasad melalui MCP dan HTTP. Setiap desain digarap untuk negara tempat bangunan berdiri: material yang dapat dipakai di sana, produk yang benar-benar dijual produsen di sana, dan susunan lapisan teknis di balik permukaan. Render menampilkannya pada foto rumah, estimasi biaya menghitungnya baris demi baris, dan album PDF mencatatnya untuk tim yang membangun. Setiap jalur di bawah adalah endpoint GetFacade yang sudah ada, sama dengan yang dipanggil aplikasi iOS, Android, dan web. Kunci agen hanya mempersempit siapa yang boleh memanggilnya, mengukur pengeluarannya, dan berhenti pada pagunya.
- URL dasar
- https://api.getfacade.ai/api/v1
- Autentikasi
- Bearer <agent key>
- Paket
- @getfacade/mcp
- Lingkungan eksekusi
- Node.js 20+
- Transport
- stdio (MCP), HTTPS (REST)
- Spesifikasi
- OpenAPI 3.1, v1.0.0
Mulai cepat
Terbitkan kunci
app.getfacade.aiAkunPengaturanAPIBuat kunci
Nilainya ditampilkan satu kali dan tidak dapat dipulihkan, hanya diganti. Batas pengeluaran ditetapkan saat penerbitan dan berlaku pada setiap panggilan berbayar.
Terbitkan kunci agenDaftarkan server MCP
Satu entri pada konfigurasi klien, lalu mulai ulang klien. Claude Desktop menyimpannya di claude_desktop_config.json; klien MCP lain menerima tiga bidang yang sama.
{ "mcpServers": { "getfacade": { "command": "npx", "args": ["-y", "@getfacade/mcp"], "env": { "GETFACADE_API_KEY": "your-key" } } } }Variabel lingkungan Variabel Wajib Nilai bawaan GETFACADE_API_KEYYa —GETFACADE_API_BASE_URLTidak https://api.getfacade.ai/api/v1Atau panggil API HTTP langsung
Kunci yang sama berfungsi sebagai token Bearer. Permintaan dan respons berupa dokumen JSON:API, dengan id sebagai bidang tingkat atas dan tidak pernah berada di dalam 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"}}}'
Alat
Dua puluh satu alat. Server MCP tidak menyimpan status maupun aturan sendiri: setiap alat adalah satu atau beberapa panggilan ke endpoint yang tercantum di sampingnya, dan setiap pesan yang diteruskan agen ditulis oleh API.
create_buildingcreate_building(name, goals?, construction_region?) -> { building_id, name }Membuat bangunan. Nama bersifat unik dalam akun dan maksimal 50 karakter; duplikat ditolak dengan 422.
Memanggil
POST /projectsupload_photoupload_photo(building_id, file_path, wait_for_validation? = true) -> { view_id, validation: { status, reason? } }Mendaftarkan tampak, mengunggah bita ke URL bertanda tangan, mengonfirmasinya, dan menanyakan status sampai foto diterima atau ditolak. Lebar, tinggi, dan md5 dihitung secara lokal; rasio aspek disimpulkan oleh server.
Memanggil
POST /projects/{project}/angles → PUT (presigned) → POST /angles/{angle}/confirm → GET /angles/{angle}/validationstart_designasinkronstart_design(building_id, view_id, prompt?, style_ids?, colors?, brand_selections?, render_effort?, seed?) -> { design_id, job_id, status, seed }Merancang fasad pada tampilan yang dipilih dan menampilkannya pada foto: material yang dapat dipakai di negara bangunan, produk yang benar-benar dijual di sana, dan susunan lapisan di balik permukaan. Membuat sebuah desain, mengantrekan pekerjaan, lalu mengembalikan id pekerjaan. Seed bersifat opsional: bila dihilangkan, server membuatnya sendiri dan mengembalikannya.
Memanggil
POST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/rendersrefine_designasinkronrefine_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 }Merevisi desain yang sudah jadi, dengan kata-kata. Instruksi diterapkan pada desain yang sudah jadi, sehingga apa pun yang tidak disebut tetap dipertahankan. Merevisi tampilan utama membuat desain baru, jadi yang sebelumnya tidak pernah tertimpa.
Memanggil
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? }Membaca keadaan satu render, estimasi, atau album.
Memanggil
GET /renders/{render} · GET /estimates/{estimate}list_jobslist_jobs(kind?, limit? = 20) -> [{ job_id, kind, status, building_id, created_at }]Tugas terbaru di seluruh akun, yang belum selesai lebih dulu.
Memanggil
GET /historylist_designslist_designs(building_id) -> [{ design_id, note, has_main_render, main_render_id, main_render_url, renders }]Desain sebuah bangunan beserta render-nya. Dari sinilah id render untuk estimasi dan album berasal.
Memanggil
GET /projects/{project}/conceptsorder_estimateasinkronorder_estimate(design_id, render_ids, currency?, measurement_system?, special_requirements?) -> { job_id, status }Menghitung biaya desain baris demi baris, dalam material dan tenaga kerja, pada harga material yang disebutkan di negara bangunan. Mata uang dan sistem satuan secara bawaan mengikuti negara itu.
Memanggil
POST /projects/{project}/concepts/{concept}/estimatesorder_albumasinkronorder_album(design_id, render_ids, language?, include_blueprints?, include_estimate?, requirements?) -> { job_id, status }Mencatat desain untuk tim yang membangun: material, susunan lapisan fasad, catatan keselamatan, dan norma yang mendasarinya. Membutuhkan render utama yang sudah selesai.
Memanggil
POST /concepts/{concept}/album/generateupscale_renderasinkronupscale_render(render_id) -> { job_id, status }Memperbesar render yang sudah selesai. Menghabiskan token dan berjalan asinkron.
Memanggil
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 }] }Estimasi itu sendiri: total, asumsi di baliknya, dan setiap baris dengan jumlah, satuan, dan harga. get_job melaporkan status estimasi, bukan isinya.
Memanggil
GET /estimates/{estimate}add_estimate_lineadd_estimate_line(estimate_id, section, name, quantity, unit_price, unit?, category?) -> { line_id }Menambahkan satu baris ke estimasi. Satuannya berasal dari sistem ukur estimasi itu sendiri.
Memanggil
POST /estimates/{estimate}/itemsupdate_estimate_lineupdate_estimate_line(estimate_id, line_id, name?, quantity?, unit_price?, unit?, category?, section?) -> { line_id }Mengubah satu baris estimasi. Hanya bidang yang dikirim yang berubah; total dihitung ulang oleh server.
Memanggil
PATCH /estimates/{estimate}/items/{item}delete_estimate_linedelete_estimate_line(estimate_id, line_id) -> { deleted }Menghapus satu baris dari estimasi.
Memanggil
DELETE /estimates/{estimate}/items/{item}delete_renderdelete_render(render_id) -> { deleted }Menghapus satu render. Menghapus render utama mengembalikan desainnya ke draf.
Memanggil
DELETE /renders/{render}delete_designdelete_design(building_id, design_id) -> { deleted }Menghapus satu desain beserta render di bawahnya.
Memanggil
DELETE /projects/{project}/concepts/{concept}delete_buildingdelete_building(building_id) -> { deleted }Menghapus bangunan beserta seluruh isinya. Token yang sudah terpakai tidak dikembalikan.
Memanggil
DELETE /projects/{project}list_token_packageslist_token_packages() -> [{ package, tokens, price, currency }]Paket yang bisa dibeli akun ini, lengkap dengan harga dan jumlah token.
Memanggil
GET /tokens/packagesbuy_tokensasinkronbuy_tokens(package) -> { status, transaction_id, tokens, checkout_url?, detail }Membeli satu paket untuk dompet kunci ini. Perlu kunci yang diterbitkan dengan pembelian diaktifkan, dan tidak pernah melampaui yang masih boleh dibelanjakan kunci.
Memanggil
POST /tokens/purchaseget_balanceget_balance() -> { balance, scope: "api", spend_cap, spent, remaining, is_admissible }Dompet agen, batas kunci ini, dan apakah panggilan berbayar berikutnya akan diterima.
Memanggil
GET /tokens/balancereport_problemreport_problem(message, category?, context?: { tool, endpoint, status_code, job_id, expected, actual }) -> { reference, message }Melaporkan cacat pada API ini: bidang yang dijelaskan di sini tetapi tidak pernah datang, penolakan yang kalimatnya tidak menunjukkan langkah berikutnya, hasil yang tidak sesuai permintaan. Gratis dan diterima meski dompet kosong; yang kembali adalah nomor rujukan, bukan balasan.
Memanggil
POST /feedback
Autentikasi dan kunci
- Kunci dikirim sebagai token Bearer pada header
Authorization. Server MCP membacanya dariGETFACADE_API_KEYdan tidak mengirim apa pun selain itu. - Nilainya ditampilkan sekali, saat penerbitan, dan hanya hash-nya yang disimpan. Rotasi berarti menerbitkan kunci baru dan mencabut yang lama.
- Setiap kunci membawa batas pengeluaran yang diberlakukan di server sebelum panggilan mencapai controller. Batas yang tercapai menghentikan kunci itu, bukan akunnya.
- Kunci tidak mengelola kunci: itu tindakan manusia, dan endpoint tersebut menjawab 403 untuk kunci agen.
- Pencabutan berlaku seketika. Panggilan dengan kunci yang dicabut menjawab 401.
Kerja asinkron dan penanyaan status
start_design,order_estimate, danorder_albummengembalikan id tugas lalu selesai. Render memakan waktu beberapa menit: tanyakanGET /renders/{render}atauGET /estimates/{estimate}sampai keadaannya final.- Selesainya validasi foto diumumkan lewat websocket yang tidak dimiliki agen. Tanyakan
GET /angles/{angle}/validationdan bacavalidation.is_in_progress; jangan menyimpulkan sendiri kefinalan dari teks status. - Render yang selesai dan album yang selesai berada di URL publik permanen: tanpa tanda tangan dan tanpa masa berlaku. Tautan itu bisa diberikan langsung kepada seseorang, dan itulah jawaban atas «tunjukkan hasilnya». Karena tidak ditandatangani, ia tidak meminta izin siapa pun: tetap bekerja bagi siapa saja yang menerimanya dan tidak dapat ditarik kembali.
GET /renders/{render}/downloadadalah hal lain: URL bertanda tangan yang kedaluwarsa dalam hitungan menit dan membawa nama berkas. Gunanya untuk menyimpan berkas, bukan untuk membagikannya.
Batas laju per kunci
Kunci agen memiliki kuota sendiri, terpisah dari sesi manusia pada akun yang sama, sehingga agen yang terjebak perulangan tidak menghabiskan jatah orang yang sedang di depan layar. Penolakan itu murah: diputuskan di middleware, sebelum ada kerja basis data.
| Cakupan | Per menit | Per jam |
|---|---|---|
| Pembacaan dan penulisan biasa | 120 | 2000 |
| Penanyaan status dan validasi | 120 | 2000 |
| Pemesanan render, estimasi, dan album | 10 | 200 |
Idempotensi
Panggilan berbayar membuat sebuah pekerjaan, dan biaya mengikuti pekerjaan itu. Memberi nama pada panggilan adalah yang membuat pengulangan mengembalikan pekerjaan yang sama, bukan membuat yang kedua.
Idempotency-Keywajib pada setiap panggilan berbayar dengan kunci API: memulai atau menyempurnakan desain, memperbesar render, memesan estimasi atau album, membuat ulang estimasi. Tanpa header itu panggilan menjawab 422IDEMPOTENCY_KEY_REQUIREDdan tidak ada yang masuk antrean.- Nilai apa pun sepanjang 8 sampai 191 karakter, satu per pesanan; biasanya UUID. Pesanan baru memakai nilai baru: dua panggilan identik dengan dua nilai adalah dua desain.
- Mengulang panggilan dengan nilai dan body yang sama mengembalikan status dan body aslinya, dengan
Idempotent-Replay: truepada respons. Tidak ada yang masuk antrean dan tidak ada yang ditagih dua kali. - Nilai yang sama dengan body berbeda menjawab 422
IDEMPOTENCY_KEY_REUSED. Pengulangan yang tiba saat panggilan pertama masih berjalan menjawab 409IDEMPOTENCY_IN_PROGRESS: tunggu, lalu kirim panggilan yang sama lagi. - Setiap 4xx melepaskan nilai itu, jadi nilai yang sama bisa dikirim lagi setelah penyebabnya diperbaiki. Nilai diingat selama 24 jam, per akun.
@getfacade/mcpmembuat nilai dan mengulang panggilan dengannya sendiri, jadi tidak ada yang perlu diteruskan dalam panggilan tool.
Kesalahan
Kegagalan datang sebagai dokumen kesalahan JSON:API. Respons validasi Laravel tidak berbentuk JSON:API dan membawa teksnya di message.
| Status | Kode | Arti | Dapat diulang |
|---|---|---|---|
401 | — | Kunci tidak ada, dicabut, atau kedaluwarsa. | Tidak |
402 | AGENT_CREDITS_EXHAUSTED | Akun tidak punya kredit lingkup api lagi. | Tidak |
402 | AGENT_KEY_CAP_REACHED | Kunci ini telah menghabiskan batasnya. Terbitkan kunci lain atau naikkan batasnya. | Tidak |
403 | — | Endpoint ini tidak tersedia untuk kunci API. API agen mencakup bangunan, foto, desain, render, estimasi biaya, album, dan dompet API. Pengaturan akun, masuk, dan pembayaran diubah oleh orang yang masuk di aplikasi. | Tidak |
403 | AGENT_PURCHASE_NOT_ALLOWED | Kunci ini diterbitkan tanpa izin membeli token. | Tidak |
403 | AGENT_PURCHASE_EXCEEDS_CAP | Pembelian akan membawa kunci melewati batas pengeluarannya. | Tidak |
409 | IDEMPOTENCY_IN_PROGRESS | Panggilan pertama dengan Idempotency-Key ini belum menjawab. Tunggu, lalu kirim panggilan yang sama lagi. | Ya |
422 | — | Permintaan dipahami dan ditolak: nama bangunan ganda, foto ditolak, album dipesan sebelum render utama selesai. | Tidak |
422 | IDEMPOTENCY_KEY_REQUIRED | Panggilan berbayar dengan kunci API tanpa header Idempotency-Key. Tidak ada yang masuk antrean; kirim ulang dengan header itu. | Tidak |
422 | IDEMPOTENCY_KEY_REUSED | Idempotency-Key ini dipakai untuk permintaan lain. Gunakan nilai baru untuk pesanan baru. | Tidak |
429 | — | Kuota milik kunci ini habis. Beri jeda, jangan mencoba ulang dalam perulangan rapat. | Ya |
Teks yang terbaca ditulis oleh API, dalam bahasa pemanggil. Tampilkan errors[].detail apa adanya alih-alih menyusun pesan sendiri.
Penagihan dan penerimaan
- Panggilan berbayar mengambil dari kredit lingkup
api, dan admisi hanya melihat saldo itu: setiap kunci membayar dengan kredit. - Pro Plan aktif mengisi dompet
apihingga 1.000 kredit sekali setiap periode penagihan. Di luar itu, kredit dibeli. - Kunci mengisi dompetnya sendiri hanya jika diterbitkan dengan pembelian diaktifkan, dan paling banyak sebesar yang masih boleh dibelanjakannya, sehingga pembelian tidak pernah menaikkan batas pengeluaran.
- Cakupan
apiadalah dompet tersendiri. Kredit aplikasi, termasuk tingkat gratis, tidak pernah dipakai oleh kunci. - Pengeluaran dihitung per kunci, sehingga konsumsi tiap asisten terlihat terpisah.
- Pemeriksaan awal adalah
GET /tokens/balance, bidangdata.attributes.agent.is_admissible. Blok itu hanya muncul untuk kunci agen, dan flag-nya mencerminkan middleware penerimaan secara persis. Bacalah flag itu, jangan membandingkan sendiri saldo dengan batas. - Penerimaan diputuskan sebelum pekerjaan masuk antrean, jadi panggilan yang ditolak tidak menghabiskan apa pun.
Token warna dan merek
start_design menerima dua daftar independen, masing-masing paling banyak sepuluh entri. Urutan membawa peran 60/30/10: entri pertama adalah warna dinding yang dominan.
colors
| Token | Arti |
|---|---|
palette:1 | Skema pilihan GetFacade, berdasarkan id. |
#8A8F7D | Warna bebas, enam digit heksadesimal. |
paint:412 | Contoh warna produsen, dalam bentuk dua segmen yang dipertahankan demi kompatibilitas. |
brand_selections
| Token | Arti |
|---|---|
siding:brand:12 | Produk apa pun dari produsen itu dalam kategori itu. |
siding:line:40@double-4-dutchlap | Satu lini, pada satu geometri. |
siding:product:88@double-4-dutchlap | Satu produk, ditentukan sepenuhnya. |
paint:brand:3 | Warna apa pun dari merek cat itu. |
paint:product:412 | Satu contoh warna cat. |
Tata bahasanya adalah category:level:id[@value][.value]. Bagian setelah @ membawa slug nilai geometri yang unik dalam kategorinya, sehingga sumbu pemiliknya dicari, bukan dituliskan pada token. Token tak dikenal ditolak dengan 422 dan tidak pernah diabaikan diam-diam.
Sesi menyeluruh
Satu bangunan, satu foto, satu desain, lalu dua dokumen. Perintah yang menghasilkannya:
Buat bangunan bernama Maple Street 14, unggah ./front.jpg sebagai tampaknya, dan mulai desain dengan dinding abu-abu hangat serta lis putih. Pesan estimasi dan album untuk hasilnya.
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)