GetFacade Agenten-API

Fassadenentwurf über MCP und HTTP. Jeder Entwurf wird für das Land ausgearbeitet, in dem das Gebäude steht: Materialien, die dort anwendbar sind, Herstellerprodukte, die dort tatsächlich verkauft werden, und der technische Aufbau hinter der Oberfläche. Ein Render zeigt ihn auf dem Foto des Hauses, die Kostenschätzung beziffert ihn Position für Position, und das PDF-Album dokumentiert ihn für den Betrieb, der ihn ausführt. Jeder Pfad unten ist ein bestehender GetFacade-Endpunkt, derselbe, den die iOS-, Android- und Web-App aufrufen. Ein Agentenschlüssel schränkt nur ein, wer ihn aufrufen darf, misst die Ausgaben und stoppt beim Limit.

Basis-URL
https://api.getfacade.ai/api/v1
Authentifizierung
Bearer <agent key>
Paket
@getfacade/mcp
Laufzeitumgebung
Node.js 20+
Transport
stdio (MCP), HTTPS (REST)
Spezifikation
OpenAPI 3.1, v1.0.0

Schnellstart

  1. Schlüssel erstellen

    app.getfacade.aiKontoEinstellungenAPISchlüssel erstellen

    Der Wert wird einmal angezeigt und lässt sich nicht wiederherstellen, nur ersetzen. Das Ausgabenlimit wird bei der Erstellung gesetzt und bei jedem kostenpflichtigen Aufruf geprüft.

    Agentenschlüssel erstellen
  2. MCP-Server eintragen

    Ein Eintrag in der Client-Konfiguration, dann den Client neu starten. Claude Desktop hält ihn in claude_desktop_config.json; jeder andere MCP-Client nimmt dieselben drei Felder.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    Umgebungsvariablen
    VariableErforderlichStandardwert
    GETFACADE_API_KEYJa
    GETFACADE_API_BASE_URLNeinhttps://api.getfacade.ai/api/v1
  3. Oder die HTTP-API direkt aufrufen

    Derselbe Schlüssel dient als Bearer-Token. Anfragen und Antworten sind JSON:API-Dokumente, in denen id ein Feld der obersten Ebene ist und nie in attributes steht.

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

Werkzeuge

Einundzwanzig Werkzeuge. Der MCP-Server hält keinen Zustand und keine eigenen Regeln: Jedes Werkzeug ist ein Aufruf oder eine Folge von Aufrufen der daneben genannten Endpunkte, und jede Meldung, die der Agent weitergibt, stammt von der API.

  • create_building
    create_building(name, goals?, construction_region?)
      -> { building_id, name }

    Legt ein Gebäude an. Der Name ist innerhalb des Kontos eindeutig und höchstens 50 Zeichen lang; ein Duplikat wird mit 422 abgelehnt.

    Ruft aufPOST /projects

  • upload_photo
    upload_photo(building_id, file_path, wait_for_validation? = true)
      -> { view_id, validation: { status, reason? } }

    Registriert eine Ansicht, lädt die Bytes an eine vorsignierte URL, bestätigt sie und fragt ab, bis das Foto angenommen oder abgelehnt ist. Breite, Höhe und md5 werden lokal berechnet; das Seitenverhältnis leitet der Server ab.

    Ruft aufPOST /projects/{project}/angles → PUT (presigned) → POST /angles/{angle}/confirm → GET /angles/{angle}/validation

  • start_designasynchron
    start_design(building_id, view_id, prompt?, style_ids?, colors?,
                 brand_selections?, render_effort?, seed?)
      -> { design_id, job_id, status, seed }

    Entwirft die Fassade auf einer gewählten Ansicht und zeigt sie auf dem Foto: Materialien, die im Land des Gebäudes anwendbar sind, Produkte, die dort tatsächlich verkauft werden, und der Aufbau hinter der Oberfläche. Legt einen Entwurf an, stellt die Arbeit in die Warteschlange und liefert die Auftrags-ID. Der Seed ist optional: Fehlt er, erzeugt ihn der Server und gibt ihn zurück.

    Ruft aufPOST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/renders

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

    Überarbeitet einen fertigen Entwurf in Worten. Die Anweisung wird auf den fertigen Entwurf angewendet, alles Nichtgenannte bleibt erhalten. Die Überarbeitung einer Hauptansicht erzeugt einen neuen Entwurf, der frühere wird also nie überschrieben.

    Ruft aufGET /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? }

    Liest den Stand eines Renderings, einer Kostenschätzung oder eines Albums.

    Ruft aufGET /renders/{render} · GET /estimates/{estimate}

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

    Aktuelle Aufträge des Kontos, unfertige zuerst.

    Ruft aufGET /history

  • list_designs
    list_designs(building_id)
      -> [{ design_id, note, has_main_render, main_render_id,
           main_render_url, renders }]

    Entwürfe eines Gebäudes samt ihren Renderings. Von hier stammen die Rendering-Kennungen für Kostenschätzung und Album.

    Ruft aufGET /projects/{project}/concepts

  • order_estimateasynchron
    order_estimate(design_id, render_ids, currency?,
                   measurement_system?, special_requirements?)
      -> { job_id, status }

    Beziffert den Entwurf Position für Position, in Material und Arbeitszeit, zu den Preisen der angegebenen Materialien im Land des Gebäudes. Währung und Maßsystem richten sich standardmäßig nach diesem Land.

    Ruft aufPOST /projects/{project}/concepts/{concept}/estimates

  • order_albumasynchron
    order_album(design_id, render_ids, language?, include_blueprints?,
                include_estimate?, requirements?)
      -> { job_id, status }

    Dokumentiert den Entwurf für den ausführenden Betrieb: die Materialien, den Aufbau der Fassade, Sicherheitshinweise und die zugrunde liegenden Normen. Setzt einen fertigen Hauptrender voraus.

    Ruft aufPOST /concepts/{concept}/album/generate

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

    Vergrößert ein fertiges Rendering. Kostet Token und läuft asynchron.

    Ruft aufPOST /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 }] }

    Die Kalkulation selbst: Summen, die Annahmen dahinter und jede Position mit Menge, Einheit und Preis. get_job meldet den Status einer Kalkulation, nie ihren Inhalt.

    Ruft aufGET /estimates/{estimate}

  • add_estimate_line
    add_estimate_line(estimate_id, section, name, quantity,
                      unit_price, unit?, category?)
      -> { line_id }

    Fügt der Kalkulation eine Position hinzu. Die Einheiten stammen aus deren eigenem Maßsystem.

    Ruft aufPOST /estimates/{estimate}/items

  • update_estimate_line
    update_estimate_line(estimate_id, line_id, name?, quantity?,
                         unit_price?, unit?, category?, section?)
      -> { line_id }

    Ändert eine Position der Kalkulation. Nur übergebene Felder werden berührt, die Summen rechnet der Server neu.

    Ruft aufPATCH /estimates/{estimate}/items/{item}

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

    Entfernt eine Position aus der Kalkulation.

    Ruft aufDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    Löscht ein Rendering. Wird das Haupt-Rendering gelöscht, kehrt sein Entwurf in den Entwurfsstatus zurück.

    Ruft aufDELETE /renders/{render}

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

    Löscht einen Entwurf samt seiner Renderings.

    Ruft aufDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    Löscht ein Gebäude mit allem darin. Bereits verbrauchte Token werden nicht erstattet.

    Ruft aufDELETE /projects/{project}

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

    Die für dieses Konto kaufbaren Pakete, mit Preis und Tokenzahl.

    Ruft aufGET /tokens/packages

  • buy_tokensasynchron
    buy_tokens(package)
      -> { status, transaction_id, tokens, checkout_url?, detail }

    Kauft ein Paket für das Guthaben dieses Schlüssels. Setzt einen Schlüssel mit Kaufberechtigung voraus und geht nie über das hinaus, was er noch ausgeben darf.

    Ruft aufPOST /tokens/purchase

  • get_balance
    get_balance()
      -> { balance, scope: "api", spend_cap, spent, remaining, is_admissible }

    Agenten-Guthaben, das Limit dieses Schlüssels und ob der nächste kostenpflichtige Aufruf zugelassen wird.

    Ruft aufGET /tokens/balance

  • report_problem
    report_problem(message, category?,
                   context?: { tool, endpoint, status_code, job_id,
                               expected, actual })
      -> { reference, message }

    Meldet einen Fehler dieser API: ein hier beschriebenes Feld, das nie ankommt, eine Ablehnung, aus deren Wortlaut kein nächster Schritt folgt, ein Ergebnis, das nicht zum Auftrag passt. Kostenlos und auch bei leerem Guthaben angenommen; zurück kommt eine Referenz, keine Antwort.

    Ruft aufPOST /feedback

Authentifizierung und Schlüssel

  • Der Schlüssel reist als Bearer-Token im Authorization-Header. Der MCP-Server liest ihn aus GETFACADE_API_KEY und sendet sonst nichts.
  • Der Wert wird einmal bei der Erstellung angezeigt, gespeichert wird nur sein Hash. Rotation heißt: neuen Schlüssel erstellen, alten widerrufen.
  • Jeder Schlüssel trägt ein Ausgabenlimit, das serverseitig geprüft wird, bevor ein Aufruf einen Controller erreicht. Ein erreichtes Limit stoppt diesen Schlüssel, nicht das Konto.
  • Schlüssel verwalten keine Schlüssel: Das ist eine menschliche Handlung, und die Endpunkte antworten einem Agentenschlüssel mit 403.
  • Ein Widerruf wirkt sofort. Aufrufe mit einem widerrufenen Schlüssel antworten mit 401.

Asynchrone Arbeit und Statusabfrage

  • start_design, order_estimate und order_album liefern eine Auftragskennung und sind damit fertig. Renderings dauern Minuten: GET /renders/{render} oder GET /estimates/{estimate} abfragen, bis der Zustand endgültig ist.
  • Das Ende der Fotoprüfung meldet ein Websocket, den ein Agent nicht hat. GET /angles/{angle}/validation abfragen und validation.is_in_progress lesen; leiten Sie die Endgültigkeit nicht selbst aus dem Statustext ab.
  • Ein fertiger Render und ein fertiges Album liegen unter dauerhaften öffentlichen URLs: ohne Signatur, ohne Ablauf. Der Link lässt sich einer Person direkt geben, als Antwort auf „zeig mir das Ergebnis“. Da er nicht signiert ist, fragt er niemanden um Erlaubnis: Er funktioniert für jeden, der ihn erhält, und lässt sich nicht zurückziehen.
  • GET /renders/{render}/download ist etwas anderes: eine signierte URL, die nach Minuten abläuft und einen Dateinamen trägt. Sie dient zum Speichern der Datei, nicht zum Teilen.

Ratenlimits je Schlüssel

Ein Agentenschlüssel hat eigene Kontingente, getrennt von den menschlichen Sitzungen desselben Kontos, damit ein Agent in einer Schleife nicht das Kontingent der Person am Bildschirm aufbraucht. Die Ablehnung ist billig: Sie fällt in der Middleware, vor jeder Datenbankarbeit.

BereichPro MinutePro Stunde
Lesen und gewöhnliches Schreiben1202000
Status- und Prüfungsabfragen1202000
Bestellung von Rendering, Kostenschätzung und Album10200

Idempotenz

Ein kostenpflichtiger Aufruf erzeugt einen Auftrag, und die Abrechnung folgt dem Auftrag. Erst der Name des Aufrufs macht es möglich, dass eine Wiederholung denselben Auftrag zurückgibt, statt einen zweiten zu erzeugen.

  • Idempotency-Key ist bei jedem kostenpflichtigen Aufruf mit einem API-Schlüssel erforderlich: Design starten oder überarbeiten, Render vergrößern, Kostenschätzung oder Album bestellen, Kostenschätzung neu erzeugen. Ohne ihn antwortet der Aufruf mit 422 IDEMPOTENCY_KEY_REQUIRED, und nichts wird eingereiht.
  • Beliebiger Wert mit 8 bis 191 Zeichen, einer pro Auftrag; üblich ist eine UUID. Ein neuer Auftrag bekommt einen neuen Wert: zwei identische Aufrufe unter zwei Werten sind zwei Designs.
  • Ein wiederholter Aufruf mit demselben Wert und demselben Body liefert Status und Body des Originals zurück, mit Idempotent-Replay: true in der Antwort. Nichts wird eingereiht und nichts doppelt berechnet.
  • Derselbe Wert mit einem anderen Body antwortet mit 422 IDEMPOTENCY_KEY_REUSED. Eine Wiederholung, die eintrifft, während der erste Aufruf noch läuft, antwortet mit 409 IDEMPOTENCY_IN_PROGRESS: warten und denselben Aufruf erneut senden.
  • Jede 4xx-Antwort gibt den Wert frei, er kann also erneut gesendet werden, sobald die Ursache behoben ist. Werte werden 24 Stunden lang je Konto gemerkt.
  • @getfacade/mcp erzeugt den Wert selbst und wiederholt den Aufruf darunter, im Tool-Aufruf ist also nichts zu übergeben.

Fehler

Fehlschläge kommen als JSON:API-Fehlerdokumente. Laravel-Validierungsantworten haben nicht die JSON:API-Form und tragen ihren Text in message.

StatusCodeBedeutungWiederholbar
401Der Schlüssel fehlt, ist widerrufen oder abgelaufen.Nein
402AGENT_CREDITS_EXHAUSTEDDas Konto hat kein Guthaben im api-Scope mehr.Nein
402AGENT_KEY_CAP_REACHEDDieser Schlüssel hat sein Limit ausgeschöpft. Neuen Schlüssel erstellen oder Limit anheben.Nein
403Dieser Endpunkt steht API-Schlüsseln nicht zur Verfügung. Die Agenten-API umfasst Gebäude, Fotos, Entwürfe, Renderings, Kostenschätzungen, Alben und die API-Guthabenkasse. Konto-, Anmelde- und Zahlungseinstellungen ändert eine Person, die in der App angemeldet ist.Nein
403AGENT_PURCHASE_NOT_ALLOWEDDieser Schlüssel wurde ohne Kaufberechtigung ausgestellt.Nein
403AGENT_PURCHASE_EXCEEDS_CAPDer Kauf würde den Schlüssel über sein Ausgabenlimit bringen.Nein
409IDEMPOTENCY_IN_PROGRESSDer erste Aufruf mit diesem Idempotency-Key hat noch nicht geantwortet. Warten Sie und senden Sie denselben Aufruf erneut.Ja
422Die Anfrage wurde verstanden und abgelehnt: doppelter Gebäudename, abgelehntes Foto, Album vor dem Ende des Hauptrenderings bestellt.Nein
422IDEMPOTENCY_KEY_REQUIREDEin kostenpflichtiger Aufruf mit API-Schlüssel ohne Idempotency-Key-Header. Nichts wurde eingereiht; senden Sie ihn erneut, diesmal mit Header.Nein
422IDEMPOTENCY_KEY_REUSEDDieser Idempotency-Key wurde für eine andere Anfrage verwendet. Nehmen Sie für einen neuen Auftrag einen neuen Wert.Nein
429Das eigene Kontingent dieses Schlüssels ist erschöpft. Warten Sie, wiederholen Sie nicht in enger Schleife.Ja

Den lesbaren Text schreibt die API, in der Sprache des Aufrufers. Zeigen Sie errors[].detail unverändert an, statt eine eigene Meldung zu formulieren.

Abrechnung und Zulassung

  • Bezahlte Aufrufe zehren am Guthaben des api-Scopes, und die Zulassung sieht allein auf diesen Stand: jeder Schlüssel zahlt in Guthaben.
  • Ein aktiver Pro Plan füllt das api-Guthaben einmal pro Abrechnungszeitraum auf 1.000 Credits auf. Darüber hinaus wird Guthaben gekauft.
  • Ein Schlüssel füllt sein Guthaben nur auf, wenn er mit Kaufberechtigung ausgestellt wurde, und höchstens um das, was er noch ausgeben darf. Ein Kauf hebt das Ausgabenlimit also nie an.
  • Der api-Scope ist eine eigene Geldbörse. Die Credits der App, das Gratiskontingent eingeschlossen, gibt ein Schlüssel nie aus.
  • Die Ausgaben werden je Schlüssel gezählt, der Verbrauch jedes Assistenten ist also einzeln sichtbar.
  • Die Vorabprüfung ist GET /tokens/balance, Feld data.attributes.agent.is_admissible. Der Block erscheint nur bei Agentenschlüsseln, und das Flag spiegelt die Zulassungs-Middleware exakt. Lesen Sie es, statt Guthaben und Limit selbst zu vergleichen.
  • Die Zulassung wird entschieden, bevor Arbeit in die Warteschlange geht; ein abgelehnter Aufruf kostet daher nichts.

Farb- und Markentoken

start_design nimmt zwei unabhängige Listen mit höchstens zehn Einträgen. Die Reihenfolge trägt die 60/30/10-Rolle: Der erste Eintrag ist die dominierende Wandfarbe.

colors

TokenBedeutung
palette:1Ein kuratiertes GetFacade-Schema, per Kennung.
#8A8F7DEine freie Farbe, sechs Hexadezimalstellen.
paint:412Ein Herstellerfarbton in der zweiteiligen Form, die aus Kompatibilitätsgründen bleibt.

brand_selections

TokenBedeutung
siding:brand:12Jedes Produkt dieses Herstellers in dieser Kategorie.
siding:line:40@double-4-dutchlapEine Linie, auf einer Geometrie.
siding:product:88@double-4-dutchlapEin Produkt, vollständig bestimmt.
paint:brand:3Jede Farbe dieser Farbenmarke.
paint:product:412Ein einzelner Farbton.

Die Grammatik lautet category:level:id[@value][.value]. Der Teil nach dem @ trägt Geometrie-Wertslugs, die innerhalb ihrer Kategorie eindeutig sind, sodass die zugehörige Achse nachgeschlagen und nicht ausgeschrieben wird. Ein unbekanntes Token wird mit 422 abgelehnt und nie stillschweigend übergangen.

Durchgehende Sitzung

Ein Gebäude, ein Foto, ein Entwurf, dann die beiden Dokumente. Die Anweisung, die das erzeugt:

Lege ein Gebäude namens Ahornstraße 14 an, lade ./front.jpg als Ansicht hoch und starte einen Entwurf mit warmgrauen Wänden und weißen Zierleisten. Bestelle Kostenschätzung und Album zum Ergebnis.
MCP-Sitzung
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)

Material