GetFacades agent-API

Fasadprojektering via MCP och HTTP. Varje design arbetas fram för det land där byggnaden står: material som går att använda där, produkter som tillverkarna faktiskt säljer där, och den tekniska uppbyggnaden bakom ytan. En rendering visar det på fotot av huset, kostnadsuppskattningen prissätter det rad för rad, och PDF-albumet dokumenterar det för laget som bygger. Varje sökväg nedan är en befintlig GetFacade-endpoint, samma som iOS-, Android- och webbappen anropar. En agentnyckel begränsar bara vem som får anropa den, mäter vad den spenderar och stannar vid sitt tak.

Bas-URL
https://api.getfacade.ai/api/v1
Autentisering
Bearer <agent key>
Paket
@getfacade/mcp
Körmiljö
Node.js 20+
Transport
stdio (MCP), HTTPS (REST)
Specifikation
OpenAPI 3.1, v1.0.0

Snabbstart

  1. Skapa en nyckel

    app.getfacade.aiKontoInställningarAPISkapa nyckel

    Värdet visas en gång och går inte att återskapa, bara ersätta. Utgiftstaket sätts när nyckeln skapas och gäller vid varje betald anropning.

    Skapa en agentnyckel
  2. Registrera MCP-servern

    En post i klientens konfiguration, sedan omstart av klienten. Claude Desktop håller den i claude_desktop_config.json; varje annan MCP-klient tar samma tre fält.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    Miljövariabler
    VariabelObligatoriskStandardvärde
    GETFACADE_API_KEYJa
    GETFACADE_API_BASE_URLNejhttps://api.getfacade.ai/api/v1
  3. Eller anropa HTTP-API:t direkt

    Samma nyckel fungerar som bearer-token. Anrop och svar är JSON:API-dokument, där id är ett fält på toppnivå och aldrig ligger inne i 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"}}}'

Verktyg

Tjugoett verktyg. MCP-servern håller inget tillstånd och inga egna regler: varje verktyg är ett eller flera anrop till de endpoints som står bredvid, och varje meddelande agenten återger är skrivet av API:t.

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

    Skapar en byggnad. Namnet är unikt inom kontot och högst 50 tecken; en dubblett avvisas med 422.

    AnroparPOST /projects

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

    Registrerar en vy, laddar upp byten till en försignerad URL, bekräftar dem och pollar tills fotot godtas eller avvisas. Bredd, höjd och md5 beräknas lokalt; bildförhållandet härleder servern.

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

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

    Projekterar fasaden på en vald vy och visar den på fotot: material som går att använda i byggnadens land, produkter som faktiskt säljs där och uppbyggnaden bakom ytan. Skapar en design, köar arbetet och returnerar jobb-id. Seed är valfritt: utelämnas det genererar servern ett och returnerar det.

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

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

    Reviderar en färdig design i ord. Instruktionen tillämpas på den färdiga designen, så allt den inte nämner behålls. Att revidera en huvudvy skapar en ny design, så den tidigare skrivs aldrig över.

    AnroparGET /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? }

    Läser tillståndet för en rendering, kalkyl eller ett album.

    AnroparGET /renders/{render} · GET /estimates/{estimate}

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

    Senaste jobben i kontot, oavslutade först.

    AnroparGET /history

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

    Byggnadens gestaltningar med sina renderingar. Härifrån kommer renderings-id:n för kalkyl och album.

    AnroparGET /projects/{project}/concepts

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

    Prissätter designen rad för rad, i material och arbete, till vad de angivna materialen kostar i byggnadens land. Valuta och måttsystem följer som standard det landet.

    AnroparPOST /projects/{project}/concepts/{concept}/estimates

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

    Dokumenterar designen för laget som bygger: materialen, fasadens uppbyggnad, säkerhetsnoteringar och normerna bakom dem. Kräver en färdig huvudrendering.

    AnroparPOST /concepts/{concept}/album/generate

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

    Förstorar en färdig rendering. Kostar krediter och körs asynkront.

    AnroparPOST /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 }] }

    Själva kalkylen: summor, antagandena bakom dem och varje rad med mängd, enhet och pris. get_job rapporterar en kalkyls status, aldrig dess innehåll.

    AnroparGET /estimates/{estimate}

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

    Lägger till en rad i kalkylen. Enheterna kommer från kalkylens eget måttsystem.

    AnroparPOST /estimates/{estimate}/items

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

    Ändrar en rad i kalkylen. Bara skickade fält ändras; servern räknar om summorna.

    AnroparPATCH /estimates/{estimate}/items/{item}

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

    Tar bort en rad ur kalkylen.

    AnroparDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    Raderar en rendering. Raderas huvudrenderingen går dess design tillbaka till utkast.

    AnroparDELETE /renders/{render}

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

    Raderar en design med renderingarna under den.

    AnroparDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    Raderar en byggnad med allt i den. Redan spenderade krediter betalas inte tillbaka.

    AnroparDELETE /projects/{project}

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

    Paketen kontot kan köpa, med pris och antal krediter.

    AnroparGET /tokens/packages

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

    Köper ett paket till den här nyckelns plånbok. Kräver en nyckel utfärdad med köp påslaget och går aldrig utöver vad nyckeln fortfarande får spendera.

    AnroparPOST /tokens/purchase

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

    Agentplånbok, nyckelns tak och om nästa betalda anrop kommer att släppas igenom.

    AnroparGET /tokens/balance

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

    Rapporterar ett fel i detta API: ett fält som beskrivs här men aldrig kommer, ett avslag vars formulering inte visar vägen vidare, ett resultat som inte motsvarar beställningen. Gratis och tas emot med tom plånbok; tillbaka kommer en referens, inte ett svar.

    AnroparPOST /feedback

Autentisering och nycklar

  • Nyckeln färdas som bearer-token i Authorization-huvudet. MCP-servern läser den ur GETFACADE_API_KEY och skickar inget annat.
  • Värdet visas en gång, när nyckeln skapas, och bara dess hash sparas. Rotation innebär att skapa en ny nyckel och återkalla den gamla.
  • Varje nyckel bär ett utgiftstak som tillämpas på servern innan anropet når en controller. Ett nått tak stoppar den nyckeln, inte kontot.
  • Nycklar hanterar inte nycklar: det är en mänsklig handling, och de endpointerna svarar 403 på en agentnyckel.
  • Återkallning gäller omedelbart. Anrop med en återkallad nyckel svarar 401.

Asynkront arbete och pollning

  • start_design, order_estimate och order_album returnerar ett jobb-id och är därmed klara. En rendering tar minuter: polla GET /renders/{render} eller GET /estimates/{estimate} tills tillståndet är slutgiltigt.
  • Att fotogranskningen är klar meddelas över en websocket som en agent inte har. Polla GET /angles/{angle}/validation och läs validation.is_in_progress; härled inte slutgiltigheten själv ur statustexten.
  • En färdig rendering och ett färdigt album ligger på permanenta publika URL:er: utan signatur och utan utgångstid. Länken kan ges direkt till en person, som svar på ”visa mig resultatet”. Eftersom den inte är signerad frågar den ingen om lov: den fortsätter fungera för var och en som får den och går inte att återkalla.
  • GET /renders/{render}/download är något annat: en signerad URL som går ut inom minuter och bär ett filnamn. Den är till för att spara filen, inte för att dela den.

Hastighetsgränser per nyckel

En agentnyckel har egna kvoter, skilda från de mänskliga sessionerna på samma konto, så att en agent i loop inte äter upp kvoten för personen framför skärmen. Avslaget är billigt: det fattas i mellanvaran, före allt databasarbete.

OmrådePer minutPer timme
Läsningar och vanliga skrivningar1202000
Status- och granskningspollning1202000
Beställning av rendering, kalkyl och album10200

Idempotens

Ett betalt anrop skapar ett jobb, och debiteringen följer jobbet. Att namnge anropet är det som låter en upprepning returnera samma jobb i stället för att skapa ett andra.

  • Idempotency-Key krävs i varje betalt anrop med en API-nyckel: starta eller finjustera en design, förstora en render, beställa en kostnadsberäkning eller ett album, göra om en beräkning. Utan den svarar anropet 422 IDEMPOTENCY_KEY_REQUIRED, och ingenting köas.
  • Vilket värde som helst på 8 till 191 tecken, ett per beställning; vanligen ett UUID. En ny beställning får ett nytt värde: två identiska anrop under två värden är två designer.
  • Att upprepa ett anrop med samma värde och samma body ger tillbaka ursprunglig status och body, med Idempotent-Replay: true i svaret. Ingenting köas och ingenting debiteras två gånger.
  • Samma värde med en annan body svarar 422 IDEMPOTENCY_KEY_REUSED. En upprepning som kommer medan det första anropet fortfarande pågår svarar 409 IDEMPOTENCY_IN_PROGRESS: vänta och skicka samma anrop igen.
  • Varje 4xx frigör värdet, så samma värde kan skickas igen när orsaken är åtgärdad. Värden minns i 24 timmar, per konto.
  • @getfacade/mcp skapar värdet och gör om anropet under det på egen hand, så ett verktygsanrop behöver inte skicka något.

Fel

Fel kommer som JSON:API-feldokument. Laravels valideringssvar har inte JSON:API-form och bär sin text i message.

StatusKodInnebördGår att upprepa
401Nyckeln saknas, är återkallad eller har gått ut.Nej
402AGENT_CREDITS_EXHAUSTEDKontot har inga krediter kvar i api-omfånget.Nej
402AGENT_KEY_CAP_REACHEDDen här nyckeln har förbrukat sitt tak. Skapa en ny nyckel eller höj taket.Nej
403Den här endpointen är inte tillgänglig för API-nycklar. Agent-API:et omfattar byggnader, foton, designer, renderingar, kalkyler, album och API-plånboken. Inställningar för konto, inloggning och betalning ändras av en person som är inloggad i appen.Nej
403AGENT_PURCHASE_NOT_ALLOWEDDen här nyckeln utfärdades utan rätt att köpa krediter.Nej
403AGENT_PURCHASE_EXCEEDS_CAPKöpet skulle föra nyckeln förbi dess utgiftstak.Nej
409IDEMPOTENCY_IN_PROGRESSDet första anropet med den här Idempotency-Key har inte svarat än. Vänta och skicka samma anrop igen.Ja
422Anropet förstods och avvisades: dubblerat byggnadsnamn, avvisat foto, album beställt innan huvudrenderingen blev klar.Nej
422IDEMPOTENCY_KEY_REQUIREDEtt betalt anrop med API-nyckel utan Idempotency-Key-rubrik. Ingenting köades; skicka det igen med rubriken.Nej
422IDEMPOTENCY_KEY_REUSEDDen här Idempotency-Key har använts för en annan begäran. Använd ett nytt värde för en ny beställning.Nej
429Nyckelns egen kvot är slut. Backa av, upprepa inte i tät loop.Ja

Den läsbara texten skrivs av API:t, på anroparens språk. Visa errors[].detail som den står i stället för att formulera ett eget meddelande.

Betalning och tillträde

  • Betalda anrop dras från krediter i api-scopet, och antagningen tittar bara på det saldot: varje nyckel betalar i krediter.
  • Ett aktivt Pro Plan fyller api-plånboken till 1 000 krediter en gång per faktureringsperiod. Därutöver köps krediter.
  • En nyckel fyller på sin egen plånbok bara om den utfärdats med köp påslaget, och högst med det den fortfarande får spendera, så ett köp höjer aldrig utgiftstaket.
  • api-omfånget är en egen plånbok. Appens krediter, gratisnivån inräknad, förbrukas aldrig av en nyckel.
  • Förbrukningen räknas per nyckel, så varje assistents konsumtion syns för sig.
  • Förhandskontrollen är GET /tokens/balance, fältet data.attributes.agent.is_admissible. Blocket finns bara för agentnycklar, och flaggan speglar tillträdesmellanvaran exakt. Läs den i stället för att själv jämföra saldo med tak.
  • Tillträdet avgörs innan arbete köas, så ett avvisat anrop kostar ingenting.

Färg- och varumärkestoken

start_design tar två oberoende listor med högst tio poster vardera. Ordningen bär rollen 60/30/10: första posten är den dominerande väggfärgen.

colors

TokenInnebörd
palette:1Ett kurerat GetFacade-schema, via id.
#8A8F7DEn fri färg, sex hexadecimala tecken.
paint:412En tillverkarkulör, i den tvådelade formen som behålls för bakåtkompatibilitet.

brand_selections

TokenInnebörd
siding:brand:12Vilken produkt som helst från den tillverkaren i den kategorin.
siding:line:40@double-4-dutchlapEn serie, på en geometri.
siding:product:88@double-4-dutchlapEn produkt, fullt bestämd.
paint:brand:3Vilken kulör som helst från det färgmärket.
paint:product:412En enskild färgkulör.

Grammatiken är category:level:id[@value][.value]. Delen efter @ bär sluggar för geometrivärden, unika inom sin kategori, så axeln de hör till slås upp i stället för att skrivas ut i token. En okänd token avvisas med 422 och förbigås aldrig tyst.

Session från början till slut

En byggnad, ett foto, en gestaltning och sedan de två dokumenten. Instruktionen som ger det:

Skapa en byggnad som heter Maple Street 14, ladda upp ./front.jpg som dess vy och starta en gestaltning med varmgrå väggar och vita foder. Beställ kalkylen och albumet för resultatet.
MCP-session
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)

Resurser