GetFacade agent-API

Gevelontwerp via MCP en HTTP. Elk ontwerp wordt uitgewerkt voor het land waar het gebouw staat: materialen die daar toepasbaar zijn, producten die fabrikanten daar echt verkopen, en de technische opbouw achter het oppervlak. Een render laat het zien op de foto van het huis, de kostenraming zet er regel voor regel een prijs op, en het pdf-album legt het vast voor de ploeg die het uitvoert. Elk pad hieronder is een bestaand GetFacade-endpoint, hetzelfde dat de iOS-, Android- en web-app aanroepen. Een agentsleutel beperkt alleen wie het mag aanroepen, meet wat er wordt uitgegeven en stopt bij het plafond.

getfacade/mcpMIT
Basis-URL
https://api.getfacade.ai/api/v1
Authenticatie
Bearer <agent key>
Pakket
@getfacade/mcp
Runtime
Node.js 20+
Transport
stdio (MCP), HTTPS (REST)
Specificatie
OpenAPI 3.1, v1.0.0

Snelstart

  1. Maak een sleutel aan

    app.getfacade.aiAccountInstellingenAPISleutel aanmaken

    De waarde wordt één keer getoond en is niet te herstellen, alleen te vervangen. De bestedingslimiet wordt bij het aanmaken ingesteld en geldt bij elke betaalde aanroep.

    Agentsleutel aanmaken
  2. Registreer de MCP-server

    Eén regel in de clientconfiguratie, daarna de client herstarten. Claude Desktop bewaart die in claude_desktop_config.json; elke andere MCP-client neemt dezelfde drie velden.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    Omgevingsvariabelen
    VariabeleVerplichtStandaardwaarde
    GETFACADE_API_KEYJa
    GETFACADE_API_BASE_URLNeehttps://api.getfacade.ai/api/v1
  3. Of roep de HTTP-API rechtstreeks aan

    Dezelfde sleutel werkt als bearer-token. Verzoeken en antwoorden zijn JSON:API-documenten, waarin id een veld op het hoogste niveau is en nooit in attributes staat.

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

Tools

Eenentwintig tools. De MCP-server houdt geen staat bij en heeft geen eigen regels: elke tool is een of meer aanroepen naar de endpoints ernaast, en elk bericht dat de agent doorgeeft komt van de API.

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

    Maakt een gebouw aan. De naam is uniek binnen het account en maximaal 50 tekens; een duplicaat wordt geweigerd met 422.

    Roept aanPOST /projects

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

    Registreert een aanzicht, uploadt de bytes naar een vooraf ondertekende URL, bevestigt ze en pollt tot de foto is geaccepteerd of geweigerd. Breedte, hoogte en md5 worden lokaal berekend; de beeldverhouding leidt de server af.

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

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

    Ontwerpt de gevel op een gekozen aanzicht en laat het zien op de foto: materialen die in het land van het gebouw toepasbaar zijn, producten die daar echt verkocht worden en de opbouw achter het oppervlak. Maakt een ontwerp aan, zet het werk in de wachtrij en geeft het taak-id terug. De seed is optioneel: laat je hem weg, dan genereert de server er een en geeft die terug.

    Roept aanPOST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/renders

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

    Herziet een afgerond ontwerp in woorden. De instructie wordt op het afgeronde ontwerp toegepast, dus alles wat niet genoemd wordt blijft staan. Het herzien van een hoofdaanzicht maakt een nieuw ontwerp, zodat het eerdere nooit wordt overschreven.

    Roept aanGET /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? }

    Leest de stand van één render, kostenraming of album.

    Roept aanGET /renders/{render} · GET /estimates/{estimate}

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

    Recente taken van het account, onafgeronde eerst.

    Roept aanGET /history

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

    Ontwerpen van een gebouw met hun renders. Hier komen de render-id's vandaan voor een raming of een album.

    Roept aanGET /projects/{project}/concepts

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

    Zet regel voor regel een prijs op het ontwerp, in materiaal en arbeid, tegen wat de genoemde materialen kosten in het land van het gebouw. Valuta en maatstelsel volgen standaard dat land.

    Roept aanPOST /projects/{project}/concepts/{concept}/estimates

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

    Legt het ontwerp vast voor de ploeg die het uitvoert: de materialen, de opbouw van de gevel, veiligheidsnotities en de normen daarachter. Vereist een afgeronde hoofdrender.

    Roept aanPOST /concepts/{concept}/album/generate

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

    Vergroot een afgeronde render. Kost tegoed en verloopt asynchroon.

    Roept aanPOST /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 }] }

    De calculatie zelf: totalen, de aannames erachter en elke regel met hoeveelheid, eenheid en prijs. get_job meldt de status van een calculatie, nooit de inhoud.

    Roept aanGET /estimates/{estimate}

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

    Voegt een regel toe aan de begroting. De eenheden komen uit haar eigen maatsysteem.

    Roept aanPOST /estimates/{estimate}/items

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

    Wijzigt een regel van de begroting. Alleen meegegeven velden veranderen; de server rekent de totalen opnieuw.

    Roept aanPATCH /estimates/{estimate}/items/{item}

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

    Verwijdert een regel uit de begroting.

    Roept aanDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    Verwijdert een render. Verwijder je de hoofdrender, dan gaat het ontwerp terug naar concept.

    Roept aanDELETE /renders/{render}

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

    Verwijdert een ontwerp met de renders eronder.

    Roept aanDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    Verwijdert een gebouw met alles erin. Al besteed tegoed wordt niet terugbetaald.

    Roept aanDELETE /projects/{project}

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

    De pakketten die dit account kan kopen, met prijs en aantal tegoeden.

    Roept aanGET /tokens/packages

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

    Koopt één pakket voor de portemonnee van deze sleutel. Vereist een sleutel met koopmogelijkheid en gaat nooit verder dan wat de sleutel nog mag uitgeven.

    Roept aanPOST /tokens/purchase

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

    Agentportemonnee, de limiet van deze sleutel en of de volgende betaalde aanroep wordt toegelaten.

    Roept aanGET /tokens/balance

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

    Meldt een fout in deze API: een veld dat hier beschreven staat maar nooit aankomt, een weigering waarvan de formulering geen weg vooruit geeft, een resultaat dat niet klopt met de vraag. Gratis en ook met een leeg saldo aanvaard; terug komt een referentie, geen antwoord.

    Roept aanPOST /feedback

Authenticatie en sleutels

  • De sleutel reist als bearer-token in de Authorization-header. De MCP-server leest hem uit GETFACADE_API_KEY en stuurt niets anders mee.
  • De waarde wordt één keer getoond, bij het aanmaken, en alleen de hash wordt bewaard. Roteren betekent een nieuwe sleutel aanmaken en de oude intrekken.
  • Elke sleutel draagt een bestedingslimiet, die aan de serverkant geldt voordat een aanroep een controller bereikt. Een bereikte limiet stopt die sleutel, niet het account.
  • Sleutels beheren geen sleutels: dat is een menselijke handeling, en die endpoints antwoorden een agentsleutel met 403.
  • Intrekken werkt onmiddellijk. Aanroepen met een ingetrokken sleutel antwoorden 401.

Asynchroon werk en pollen

  • start_design, order_estimate en order_album geven een taak-id terug en zijn daarmee klaar. Een render duurt minuten: poll GET /renders/{render} of GET /estimates/{estimate} tot de staat definitief is.
  • Het einde van de fotovalidatie wordt gemeld via een websocket die een agent niet heeft. Poll GET /angles/{angle}/validation en lees validation.is_in_progress; leid de eindtoestand niet zelf af uit de statustekst.
  • Een afgeronde render en een afgerond album staan op permanente publieke URL's: zonder handtekening en zonder vervaldatum. De link kan rechtstreeks aan iemand worden gegeven, als antwoord op “laat het resultaat zien”. Omdat hij niet ondertekend is, vraagt hij niemand om toestemming: hij blijft werken voor iedereen die hem ontvangt en is niet in te trekken.
  • GET /renders/{render}/download is iets anders: een ondertekende URL die binnen minuten verloopt en een bestandsnaam meedraagt. Bedoeld om het bestand op te slaan, niet om het te delen.

Snelheidslimieten per sleutel

Een agentsleutel heeft eigen tellers, gescheiden van de menselijke sessies van hetzelfde account, zodat een agent in een lus niet het quotum opeet van de persoon achter het scherm. Weigeren is goedkoop: het gebeurt in de middleware, vóór enig databasewerk.

BereikPer minuutPer uur
Lezen en gewoon schrijven1202000
Status- en validatiepolling1202000
Bestellingen van render, raming en album10200

Idempotentie

Een betaalde aanroep maakt een taak aan, en de kosten volgen de taak. Het benoemen van de aanroep is wat een herhaling dezelfde taak laat teruggeven in plaats van een tweede aan te maken.

  • Idempotency-Key is verplicht bij elke betaalde aanroep met een API-sleutel: een ontwerp starten of bijwerken, een render vergroten, een begroting of album bestellen, een begroting opnieuw genereren. Zonder de header antwoordt de aanroep met 422 IDEMPOTENCY_KEY_REQUIRED en wordt er niets in de wachtrij gezet.
  • Elke waarde van 8 tot 191 tekens, één per opdracht; meestal een UUID. Een nieuwe opdracht krijgt een nieuwe waarde: twee identieke aanroepen met twee waarden zijn twee ontwerpen.
  • Een aanroep herhalen met dezelfde waarde en dezelfde body geeft de oorspronkelijke status en body terug, met Idempotent-Replay: true in het antwoord. Er wordt niets in de wachtrij gezet en niets dubbel in rekening gebracht.
  • Dezelfde waarde met een andere body antwoordt met 422 IDEMPOTENCY_KEY_REUSED. Een herhaling die binnenkomt terwijl de eerste aanroep nog loopt, antwoordt met 409 IDEMPOTENCY_IN_PROGRESS: wacht en stuur dezelfde aanroep opnieuw.
  • Elke 4xx geeft de waarde vrij, dus dezelfde kan opnieuw worden gestuurd zodra de oorzaak is verholpen. Waarden worden 24 uur onthouden, per account.
  • @getfacade/mcp maakt de waarde zelf aan en herhaalt de aanroep ermee, dus in de tool-aanroep hoef je niets mee te geven.

Fouten

Mislukkingen komen als JSON:API-foutdocumenten. Validatieantwoorden van Laravel hebben die vorm niet en dragen hun tekst in message.

StatusCodeBetekenisHerhaalbaar
401De sleutel ontbreekt, is ingetrokken of verlopen.Nee
402AGENT_CREDITS_EXHAUSTEDHet account heeft geen api-tegoed meer.Nee
402AGENT_KEY_CAP_REACHEDDeze sleutel heeft zijn limiet opgebruikt. Maak een andere sleutel aan of verhoog de limiet.Nee
403Dit endpoint is niet beschikbaar voor API-sleutels. De agent-API omvat gebouwen, foto's, ontwerpen, renders, begrotingen, albums en de API-portemonnee. Account-, inlog- en betaalinstellingen wijzigt een persoon die is ingelogd in de app.Nee
403AGENT_PURCHASE_NOT_ALLOWEDDeze sleutel is aangemaakt zonder recht om tegoed te kopen.Nee
403AGENT_PURCHASE_EXCEEDS_CAPDe aankoop zou de sleutel over haar bestedingsplafond tillen.Nee
409IDEMPOTENCY_IN_PROGRESSDe eerste aanroep met deze Idempotency-Key heeft nog niet geantwoord. Wacht en stuur dezelfde aanroep opnieuw.Ja
422Het verzoek is begrepen en geweigerd: dubbele gebouwnaam, afgewezen foto, album besteld voordat de hoofdrender klaar was.Nee
422IDEMPOTENCY_KEY_REQUIREDEen betaalde aanroep met API-sleutel zonder Idempotency-Key-header. Er is niets in de wachtrij gezet; stuur hem opnieuw mét header.Nee
422IDEMPOTENCY_KEY_REUSEDDeze Idempotency-Key is voor een ander verzoek gebruikt. Gebruik een nieuwe waarde voor een nieuwe opdracht.Nee
429De eigen teller van deze sleutel is op. Wacht even, herhaal niet in een strakke lus.Ja

De leesbare tekst schrijft de API, in de taal van de aanroeper. Toon errors[].detail ongewijzigd in plaats van een eigen bericht op te stellen.

Facturering en toelating

  • Betaalde aanroepen putten uit api-scope credits, en de toelating kijkt alleen naar dat saldo: elke sleutel betaalt in credits.
  • Een actief Pro Plan vult de api-wallet eens per factuurperiode aan tot 1.000 credits. Daarboven worden credits gekocht.
  • Een sleutel vult haar eigen portemonnee alleen aan als ze met koopmogelijkheid is aangemaakt, en niet meer dan ze nog mag uitgeven, dus een aankoop tilt het bestedingsplafond nooit op. Het antwoord meldt charged als de opgeslagen betaalmethode dekte, of requires_human met een betaallink die een mens opent.
  • De api-scope is een aparte portemonnee. De credits van de app, inclusief de gratis laag, worden nooit door een sleutel uitgegeven.
  • Al betaalde credits uit de app gaan via het API-paneel naar de api-portemonnee, op het web en in beide mobiele apps. Gratis credits blijven waar ze zijn, en de overdracht gaat maar één kant op.
  • Uitgaven worden per sleutel geteld, zodat het verbruik van elke assistent apart zichtbaar is.
  • De voorafgaande controle is GET /tokens/balance, veld data.attributes.agent.is_admissible. Het blok verschijnt alleen bij agentsleutels en de vlag spiegelt de toelatings-middleware exact. Lees hem in plaats van zelf saldo en limiet te vergelijken.
  • Toelating wordt beslist voordat werk in de wachtrij gaat, dus een geweigerde aanroep kost niets.

Kleur- en merktokens

start_design neemt twee onafhankelijke lijsten van maximaal tien items. De volgorde draagt de 60/30/10-rol: het eerste item is de dominante muurkleur.

colors

TokenBetekenis
palette:1Een samengesteld GetFacade-schema, op id.
#8A8F7DEen vrije kleur, zes hexadecimale tekens.
paint:412Een fabrikantstaal, in de tweedelige vorm die om compatibiliteitsredenen blijft.

brand_selections

TokenBetekenis
siding:brand:12Elk product van die fabrikant in die categorie.
siding:line:40@double-4-dutchlapEén lijn, op één geometrie.
siding:product:88@double-4-dutchlapEén product, volledig bepaald.
paint:brand:3Elke kleur van dat verfmerk.
paint:product:412Eén verfstaal.

De grammatica is category:level:id[@value][.value]. Het deel na @ draagt slugs van geometriewaarden, die uniek zijn binnen hun categorie, zodat de bijbehorende as wordt opgezocht in plaats van uitgeschreven. Een onbekend token wordt geweigerd met 422 en nooit stilzwijgend genegeerd.

Volledige sessie

Eén gebouw, één foto, één ontwerp en dan de twee documenten. De opdracht die dat oplevert:

Maak een gebouw met de naam Maple Street 14, upload ./front.jpg als aanzicht en start een ontwerp met warmgrijze muren en witte lijsten. Bestel de kostenraming en het album voor het resultaat.
MCP-sessie
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)

Bronnen