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

  1. 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 agenta
  2. Zarejestruj 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.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    Zmienne środowiskowe
    ZmiennaWymaganaWartość domyślna
    GETFACADE_API_KEYTak
    GETFACADE_API_BASE_URLNiehttps://api.getfacade.ai/api/v1
  3. Albo 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.

    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"}}}'

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_building
    create_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łujePOST /projects

  • upload_photo
    upload_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łujePOST /projects/{project}/angles → PUT (presigned) → POST /angles/{angle}/confirm → GET /angles/{angle}/validation

  • start_designasynchroniczne
    start_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łujePOST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/renders

  • refine_designasynchroniczne
    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 }

    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łujeGET /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? }

    Odczytuje stan jednego renderu, kosztorysu albo albumu.

    WywołujeGET /renders/{render} · GET /estimates/{estimate}

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

    Ostatnie zadania na koncie, niedokończone na górze.

    WywołujeGET /history

  • list_designs
    list_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łujeGET /projects/{project}/concepts

  • order_estimateasynchroniczne
    order_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łujePOST /projects/{project}/concepts/{concept}/estimates

  • order_albumasynchroniczne
    order_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łujePOST /concepts/{concept}/album/generate

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

    Powiększa ukończony render. Kosztuje tokeny i działa asynchronicznie.

    WywołujePOST /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 }] }

    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łujeGET /estimates/{estimate}

  • add_estimate_line
    add_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łujePOST /estimates/{estimate}/items

  • update_estimate_line
    update_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łujePATCH /estimates/{estimate}/items/{item}

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

    Usuwa pozycję z kosztorysu.

    WywołujeDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    Usuwa render. Usunięcie głównego renderu cofa jego projekt do wersji roboczej.

    WywołujeDELETE /renders/{render}

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

    Usuwa projekt razem z jego renderami.

    WywołujeDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    Usuwa obiekt z całą zawartością. Wydane tokeny nie wracają.

    WywołujeDELETE /projects/{project}

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

    Pakiety dostępne dla tego konta, z ceną i liczbą tokenów.

    WywołujeGET /tokens/packages

  • buy_tokensasynchroniczne
    buy_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łujePOST /tokens/purchase

  • get_balance
    get_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łujeGET /tokens/balance

  • report_problem
    report_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łujePOST /feedback

Uwierzytelnianie i klucze

  • Klucz podróżuje jako token Bearer w nagłówku Authorization. Serwer MCP czyta go ze zmiennej GETFACADE_API_KEY i 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_estimate i order_album zwracają identyfikator zadania i na tym kończą. Render trwa minuty: odpytuj GET /renders/{render} albo GET /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}/validation i czytaj validation.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}/download to 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.

ZakresNa minutęNa godzinę
Odczyty i zwykłe zapisy1202000
Odpytywanie statusów i walidacji1202000
Zamówienia renderu, kosztorysu i albumu10200

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-Key jest 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 422 IDEMPOTENCY_KEY_REQUIRED i 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 409 IDEMPOTENCY_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/mcp sam 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.

StatusKodZnaczeniePonawialny
401Klucza brak, został unieważniony albo wygasł.Nie
402AGENT_CREDITS_EXHAUSTEDNa koncie nie ma już kredytów zakresu api.Nie
402AGENT_KEY_CAP_REACHEDTen klucz wyczerpał swój limit. Wydaj inny klucz albo podnieś limit.Nie
403Ten 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
403AGENT_PURCHASE_NOT_ALLOWEDTen klucz wydano bez prawa do kupowania tokenów.Nie
403AGENT_PURCHASE_EXCEEDS_CAPZakup przekroczyłby limit wydatków klucza.Nie
409IDEMPOTENCY_IN_PROGRESSPierwsze 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
422IDEMPOTENCY_KEY_REQUIREDPłatne wywołanie kluczem API bez nagłówka Idempotency-Key. Nic nie trafiło do kolejki; wyślij je ponownie z nagłówkiem.Nie
422IDEMPOTENCY_KEY_REUSEDTen Idempotency-Key został użyty do innego żądania. Do nowego zamówienia użyj nowej wartości.Nie
429Wł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 api do 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 api to 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, pole data.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

TokenZnaczenie
palette:1Gotowy schemat GetFacade, po identyfikatorze.
#8A8F7DDowolny kolor, sześć znaków szesnastkowych.
paint:412Próbka producenta w dwuczłonowej formie zachowanej dla zgodności.

brand_selections

TokenZnaczenie
siding:brand:12Dowolny produkt tego producenta w tej kategorii.
siding:line:40@double-4-dutchlapJedna linia, na jednej geometrii.
siding:product:88@double-4-dutchlapJeden produkt, w pełni określony.
paint:brand:3Dowolny kolor tej marki farb.
paint:product:412Jedna 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.
Sesja 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)

Materiały