API GetFacade dla agentów
Projektowanie elewacji przez MCP i HTTP. Każdy projekt jest opracowywany pod kraj, w którym stoi budynek: materiały tam stosowalne, produkty, które producenci faktycznie tam sprzedają, i techniczny układ warstw pod powierzchnią. Render pokazuje to na zdjęciu domu, kosztorys wycenia pozycja po pozycji, a album PDF dokumentuje to dla ekipy, która będzie budować. Każda ścieżka poniżej to istniejący endpoint GetFacade, ten sam, który wywołują aplikacje iOS, Android i web. Klucz agenta jedynie zawęża krąg wywołujących, mierzy wydatki i zatrzymuje się na swoim limicie.
- Adres bazowy
- https://api.getfacade.ai/api/v1
- Uwierzytelnianie
- Bearer <agent key>
- Pakiet
- @getfacade/mcp
- Środowisko uruchomieniowe
- Node.js 20+
- Transport
- stdio (MCP), HTTPS (REST)
- Specyfikacja
- OpenAPI 3.1, v1.0.0
Szybki start
Wydaj klucz
app.getfacade.aiKontoUstawieniaAPIUtwórz klucz
Wartość pokazuje się raz i nie da się jej odzyskać, tylko zastąpić. Limit wydatków ustawia się przy wydaniu i obowiązuje przy każdym płatnym wywołaniu.
Wydaj klucz agentaZarejestruj serwer MCP
Jeden wpis w konfiguracji klienta, potem restart klienta. Claude Desktop trzyma go w claude_desktop_config.json; każdy inny klient MCP przyjmuje te same trzy pola.
{ "mcpServers": { "getfacade": { "command": "npx", "args": ["-y", "@getfacade/mcp"], "env": { "GETFACADE_API_KEY": "your-key" } } } }Zmienne środowiskowe Zmienna Wymagana Wartość domyślna GETFACADE_API_KEYTak —GETFACADE_API_BASE_URLNie https://api.getfacade.ai/api/v1Albo wywołuj API HTTP bezpośrednio
Ten sam klucz działa jako token Bearer. Żądania i odpowiedzi to dokumenty JSON:API, w których id jest polem najwyższego poziomu i nigdy nie leży w 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"}}}'
Narzędzia
Dwadzieścia jeden narzędzi. Serwer MCP nie przechowuje stanu ani własnych reguł: każde narzędzie to jedno lub kilka wywołań wymienionych obok endpointów, a każdy komunikat powtarzany przez agenta pisze API.
create_buildingcreate_building(name, goals?, construction_region?) -> { building_id, name }Tworzy budynek. Nazwa jest unikalna w obrębie konta i ma najwyżej 50 znaków; duplikat zostaje odrzucony kodem 422.
Wywołuje
POST /projectsupload_photoupload_photo(building_id, file_path, wait_for_validation? = true) -> { view_id, validation: { status, reason? } }Rejestruje widok, wysyła bajty pod podpisany URL, potwierdza je i odpytuje, aż zdjęcie zostanie przyjęte lub odrzucone. Szerokość, wysokość i md5 liczone są lokalnie; proporcje wyprowadza serwer.
Wywołuje
POST /projects/{project}/angles → PUT (presigned) → POST /angles/{angle}/confirm → GET /angles/{angle}/validationstart_designasynchronicznestart_design(building_id, view_id, prompt?, style_ids?, colors?, brand_selections?, render_effort?, seed?) -> { design_id, job_id, status, seed }Projektuje elewację na wybranym ujęciu i pokazuje ją na zdjęciu: materiały stosowalne w kraju budynku, produkty tam faktycznie sprzedawane i układ warstw pod powierzchnią. Tworzy projekt, kolejkuje pracę i zwraca identyfikator zadania. Seed jest opcjonalny: jeśli go pominiesz, serwer sam go wygeneruje i zwróci.
Wywołuje
POST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/rendersrefine_designasynchronicznerefine_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 }Poprawia słowami gotowy projekt. Instrukcja jest stosowana do gotowego projektu, więc wszystko, o czym nie wspomina, zostaje zachowane. Poprawka głównego ujęcia tworzy nowy projekt, poprzedni nigdy nie jest nadpisywany.
Wywołuje
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? }Odczytuje stan jednego renderu, kosztorysu albo albumu.
Wywołuje
GET /renders/{render} · GET /estimates/{estimate}list_jobslist_jobs(kind?, limit? = 20) -> [{ job_id, kind, status, building_id, created_at }]Ostatnie zadania na koncie, niedokończone na górze.
Wywołuje
GET /historylist_designslist_designs(building_id) -> [{ design_id, note, has_main_render, main_render_id, main_render_url, renders }]Projekty budynku wraz z ich renderami. Stąd pochodzą identyfikatory renderów do kosztorysu i albumu.
Wywołuje
GET /projects/{project}/conceptsorder_estimateasynchroniczneorder_estimate(design_id, render_ids, currency?, measurement_system?, special_requirements?) -> { job_id, status }Wycenia projekt pozycja po pozycji, w materiałach i robociźnie, po cenach wskazanych materiałów w kraju budynku. Waluta i system miar domyślnie wynikają z tego kraju.
Wywołuje
POST /projects/{project}/concepts/{concept}/estimatesorder_albumasynchroniczneorder_album(design_id, render_ids, language?, include_blueprints?, include_estimate?, requirements?) -> { job_id, status }Dokumentuje projekt dla ekipy, która będzie budować: materiały, układ warstw elewacji, uwagi o bezpieczeństwie i normy, na których się opierają. Wymaga ukończonego renderu głównego.
Wywołuje
POST /concepts/{concept}/album/generateupscale_renderasynchroniczneupscale_render(render_id) -> { job_id, status }Powiększa ukończony render. Kosztuje tokeny i działa asynchronicznie.
Wywołuje
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 }] }Sam kosztorys: sumy, założenia, które za nimi stoją, i każda pozycja z ilością, jednostką i ceną. get_job podaje status kosztorysu, nigdy jego treść.
Wywołuje
GET /estimates/{estimate}add_estimate_lineadd_estimate_line(estimate_id, section, name, quantity, unit_price, unit?, category?) -> { line_id }Dodaje pozycję do kosztorysu. Jednostki pochodzą z jego własnego układu miar.
Wywołuje
POST /estimates/{estimate}/itemsupdate_estimate_lineupdate_estimate_line(estimate_id, line_id, name?, quantity?, unit_price?, unit?, category?, section?) -> { line_id }Zmienia pozycję kosztorysu. Zmieniają się tylko przekazane pola; sumy przelicza serwer.
Wywołuje
PATCH /estimates/{estimate}/items/{item}delete_estimate_linedelete_estimate_line(estimate_id, line_id) -> { deleted }Usuwa pozycję z kosztorysu.
Wywołuje
DELETE /estimates/{estimate}/items/{item}delete_renderdelete_render(render_id) -> { deleted }Usuwa render. Usunięcie głównego renderu cofa jego projekt do wersji roboczej.
Wywołuje
DELETE /renders/{render}delete_designdelete_design(building_id, design_id) -> { deleted }Usuwa projekt razem z jego renderami.
Wywołuje
DELETE /projects/{project}/concepts/{concept}delete_buildingdelete_building(building_id) -> { deleted }Usuwa obiekt z całą zawartością. Wydane tokeny nie wracają.
Wywołuje
DELETE /projects/{project}list_token_packageslist_token_packages() -> [{ package, tokens, price, currency }]Pakiety dostępne dla tego konta, z ceną i liczbą tokenów.
Wywołuje
GET /tokens/packagesbuy_tokensasynchronicznebuy_tokens(package) -> { status, transaction_id, tokens, checkout_url?, detail }Kupuje pakiet do portfela tego klucza. Wymaga klucza wydanego z prawem zakupu i nigdy nie wykracza poza to, co klucz może jeszcze wydać.
Wywołuje
POST /tokens/purchaseget_balanceget_balance() -> { balance, scope: "api", spend_cap, spent, remaining, is_admissible }Portfel agenta, limit tego klucza i informacja, czy kolejne płatne wywołanie zostanie dopuszczone.
Wywołuje
GET /tokens/balancereport_problemreport_problem(message, category?, context?: { tool, endpoint, status_code, job_id, expected, actual }) -> { reference, message }Zgłasza usterkę tego API: pole opisane tutaj, które nigdy nie przychodzi, odmowę, z której treści nie wynika następny krok, wynik niezgodny z zamówieniem. Bezpłatne i przyjmowane przy pustym portfelu; wraca numer zgłoszenia, nie odpowiedź.
Wywołuje
POST /feedback
Uwierzytelnianie i klucze
- Klucz podróżuje jako token Bearer w nagłówku
Authorization. Serwer MCP czyta go ze zmiennejGETFACADE_API_KEYi nie wysyła nic poza tym. - Wartość pokazuje się raz, przy wydaniu, a przechowywany jest tylko jej skrót. Rotacja to wydanie nowego klucza i unieważnienie starego.
- Każdy klucz ma limit wydatków, egzekwowany po stronie serwera, zanim wywołanie dotrze do kontrolera. Osiągnięty limit zatrzymuje ten klucz, a nie konto.
- Klucze nie zarządzają kluczami: to czynność człowieka, a odpowiednie endpointy odpowiadają kluczowi agenta kodem 403.
- Unieważnienie działa natychmiast. Wywołania unieważnionym kluczem otrzymują 401.
Praca asynchroniczna i odpytywanie
start_design,order_estimateiorder_albumzwracają identyfikator zadania i na tym kończą. Render trwa minuty: odpytujGET /renders/{render}alboGET /estimates/{estimate}, aż stan będzie końcowy.- O zakończeniu walidacji zdjęcia informuje websocket, którego agent nie ma. Odpytuj
GET /angles/{angle}/validationi czytajvalidation.is_in_progress; nie wyliczaj końcowości samodzielnie z tekstu statusu. - Ukończony render i ukończony album leżą pod trwałymi publicznymi adresami: bez podpisu i bez terminu ważności. Taki link można dać człowiekowi wprost, i to jest odpowiedź na „pokaż wynik”. Ponieważ nie jest podpisany, nikogo o nic nie pyta: działa u każdego, kto go otrzyma, i nie da się go cofnąć.
GET /renders/{render}/downloadto co innego: podpisany URL, który wygasa w ciągu minut i niesie nazwę pliku. Służy do zapisania pliku, a nie do dzielenia się nim.
Limity częstotliwości na klucz
Klucz agenta ma własne koszyki limitów, oddzielone od sesji ludzkich tego samego konta, żeby zapętlony agent nie zjadł przydziału osoby siedzącej przy ekranie. Odmowa jest tania: zapada w middleware, przed jakąkolwiek pracą na bazie.
| Zakres | Na minutę | Na godzinę |
|---|---|---|
| Odczyty i zwykłe zapisy | 120 | 2000 |
| Odpytywanie statusów i walidacji | 120 | 2000 |
| Zamówienia renderu, kosztorysu i albumu | 10 | 200 |
Idempotencja
Płatne wywołanie tworzy zadanie, a opłata idzie za zadaniem. To nazwanie wywołania sprawia, że powtórka zwraca to samo zadanie, zamiast tworzyć drugie.
Idempotency-Keyjest wymagany przy każdym płatnym wywołaniu kluczem API: rozpoczęcie lub poprawka projektu, powiększenie renderu, zamówienie kosztorysu albo albumu, ponowne wygenerowanie kosztorysu. Bez niego wywołanie odpowiada 422IDEMPOTENCY_KEY_REQUIREDi nic nie trafia do kolejki.- Dowolna wartość od 8 do 191 znaków, po jednej na zamówienie; zwykle jest to UUID. Nowe zamówienie bierze nową wartość: dwa identyczne wywołania pod dwiema wartościami to dwa projekty.
- Powtórzenie wywołania z tą samą wartością i tym samym ciałem zwraca pierwotny status i pierwotne ciało, z nagłówkiem
Idempotent-Replay: true. Nic nie trafia do kolejki i nic nie jest liczone dwa razy. - Ta sama wartość z innym ciałem odpowiada 422
IDEMPOTENCY_KEY_REUSED. Powtórka, która przyjdzie, gdy pierwsze wywołanie jeszcze trwa, odpowiada 409IDEMPOTENCY_IN_PROGRESS: poczekaj i wyślij to samo wywołanie ponownie. - Każda odpowiedź 4xx zwalnia wartość, więc można wysłać tę samą, gdy przyczyna zostanie usunięta. Wartości są pamiętane przez 24 godziny, w obrębie konta.
@getfacade/mcpsam tworzy wartość i sam ponawia pod nią wywołanie, więc w wywołaniu narzędzia nie trzeba nic przekazywać.
Błędy
Niepowodzenia przychodzą jako dokumenty błędów JSON:API. Odpowiedzi walidacyjne Laravela nie mają formy JSON:API i niosą tekst w polu message.
| Status | Kod | Znaczenie | Ponawialny |
|---|---|---|---|
401 | — | Klucza brak, został unieważniony albo wygasł. | Nie |
402 | AGENT_CREDITS_EXHAUSTED | Na koncie nie ma już kredytów zakresu api. | Nie |
402 | AGENT_KEY_CAP_REACHED | Ten klucz wyczerpał swój limit. Wydaj inny klucz albo podnieś limit. | Nie |
403 | — | Ten endpoint nie jest dostępny dla kluczy API. API dla agentów obejmuje budynki, zdjęcia, projekty, rendery, kosztorysy, albumy i portfel API. Ustawienia konta, logowania i płatności zmienia osoba zalogowana w aplikacji. | Nie |
403 | AGENT_PURCHASE_NOT_ALLOWED | Ten klucz wydano bez prawa do kupowania tokenów. | Nie |
403 | AGENT_PURCHASE_EXCEEDS_CAP | Zakup przekroczyłby limit wydatków klucza. | Nie |
409 | IDEMPOTENCY_IN_PROGRESS | Pierwsze wywołanie z tym kluczem Idempotency-Key jeszcze nie odpowiedziało. Poczekaj i wyślij to samo wywołanie ponownie. | Tak |
422 | — | Żądanie zostało zrozumiane i odrzucone: powtórzona nazwa budynku, odrzucone zdjęcie, album zamówiony przed ukończeniem renderu głównego. | Nie |
422 | IDEMPOTENCY_KEY_REQUIRED | Płatne wywołanie kluczem API bez nagłówka Idempotency-Key. Nic nie trafiło do kolejki; wyślij je ponownie z nagłówkiem. | Nie |
422 | IDEMPOTENCY_KEY_REUSED | Ten Idempotency-Key został użyty do innego żądania. Do nowego zamówienia użyj nowej wartości. | Nie |
429 | — | Własny koszyk limitów tego klucza jest wyczerpany. Odczekaj, nie ponawiaj w ciasnej pętli. | Tak |
Tekst czytelny dla człowieka pisze API, w języku wywołującego. Wyświetlaj errors[].detail bez zmian, zamiast układać własny komunikat.
Rozliczenia i dopuszczenie
- Płatne wywołania czerpią z kredytów zakresu
api, a dopuszczenie patrzy wyłącznie na to saldo: każdy klucz płaci kredytami. - Aktywny Pro Plan raz na okres rozliczeniowy uzupełnia portfel
apido 1000 kredytów. Powyżej tego kredyty się kupuje. - Klucz doładowuje własny portfel tylko wtedy, gdy wydano go z prawem zakupu, i najwyżej o tyle, ile jeszcze może wydać, więc zakup nigdy nie podnosi limitu wydatków.
- Zakres
apito osobny portfel. Kredytów aplikacji, łącznie z darmowym progiem, klucz nie wydaje nigdy. - Wydatek liczony jest na klucz, więc zużycie każdego asystenta widać osobno.
- Kontrola przed wywołaniem to
GET /tokens/balance, poledata.attributes.agent.is_admissible. Blok pojawia się wyłącznie przy kluczach agenta, a flaga dokładnie odzwierciedla middleware dopuszczenia. Czytaj ją zamiast samodzielnie porównywać saldo z limitem. - Dopuszczenie rozstrzyga się przed skolejkowaniem pracy, więc odrzucone wywołanie nic nie kosztuje.
Tokeny koloru i marki
start_design przyjmuje dwie niezależne listy, po najwyżej dziesięć pozycji. Kolejność niesie rolę 60/30/10: pierwsza pozycja to dominujący kolor ścian.
colors
| Token | Znaczenie |
|---|---|
palette:1 | Gotowy schemat GetFacade, po identyfikatorze. |
#8A8F7D | Dowolny kolor, sześć znaków szesnastkowych. |
paint:412 | Próbka producenta w dwuczłonowej formie zachowanej dla zgodności. |
brand_selections
| Token | Znaczenie |
|---|---|
siding:brand:12 | Dowolny produkt tego producenta w tej kategorii. |
siding:line:40@double-4-dutchlap | Jedna linia, na jednej geometrii. |
siding:product:88@double-4-dutchlap | Jeden produkt, w pełni określony. |
paint:brand:3 | Dowolny kolor tej marki farb. |
paint:product:412 | Jedna próbka farby. |
Gramatyka to category:level:id[@value][.value]. Część po @ niesie slugi wartości geometrii, unikalne w obrębie kategorii, więc oś, do której należą, jest wyszukiwana, a nie zapisywana w tokenie. Nieznany token zostaje odrzucony kodem 422 i nigdy nie jest cicho pomijany.
Pełna sesja
Jeden budynek, jedno zdjęcie, jeden projekt, a potem dwa dokumenty. Polecenie, które to daje:
Utwórz budynek o nazwie Maple Street 14, wgraj ./front.jpg jako jego widok i uruchom projekt z ciepłoszarymi ścianami i białymi obramowaniami. Zamów kosztorys i album dla wyniku.
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)