API-ul GetFacade pentru agenți

Proiectare de fațadă prin MCP și HTTP. Fiecare proiect este elaborat pentru țara în care se află clădirea: materiale aplicabile acolo, produse pe care producătorii chiar le vând acolo și stratificația tehnică din spatele suprafeței. Un render îl arată pe fotografia casei, devizul îl evaluează rând cu rând, iar albumul PDF îl documentează pentru echipa care va construi. Fiecare cale de mai jos este un endpoint GetFacade existent, același pe care îl apelează aplicațiile iOS, Android și web. O cheie de agent doar restrânge cine îl poate apela, măsoară cheltuiala și se oprește la plafonul ei.

URL de bază
https://api.getfacade.ai/api/v1
Autentificare
Bearer <agent key>
Pachet
@getfacade/mcp
Mediu de execuție
Node.js 20+
Transport
stdio (MCP), HTTPS (REST)
Specificație
OpenAPI 3.1, v1.0.0

Pornire rapidă

  1. Emite o cheie

    app.getfacade.aiContSetăriAPICreează cheia

    Valoarea se afișează o singură dată și nu poate fi recuperată, doar înlocuită. Plafonul de cheltuieli se stabilește la emitere și se aplică la fiecare apel plătit.

    Emite o cheie de agent
  2. Înregistrează serverul MCP

    O intrare în configurația clientului, apoi repornirea clientului. Claude Desktop o păstrează în claude_desktop_config.json; orice alt client MCP acceptă aceleași trei câmpuri.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    Variabile de mediu
    VariabilăObligatorieValoare implicită
    GETFACADE_API_KEYDa
    GETFACADE_API_BASE_URLNuhttps://api.getfacade.ai/api/v1
  3. Sau apelează direct API-ul HTTP

    Aceeași cheie funcționează ca jeton Bearer. Cererile și răspunsurile sunt documente JSON:API, în care id este un câmp de prim nivel și nu se află niciodată în 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"}}}'

Instrumente

Douăzeci și unu de instrumente. Serverul MCP nu păstrează stare și nu are reguli proprii: fiecare instrument înseamnă unul sau mai multe apeluri către endpointurile indicate alături, iar fiecare mesaj pe care agentul îl repetă este scris de API.

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

    Creează o clădire. Numele este unic în cadrul contului și are cel mult 50 de caractere; un duplicat este respins cu 422.

    ApeleazăPOST /projects

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

    Înregistrează o vedere, încarcă octeții la un URL presemnat, îi confirmă și interoghează până când fotografia este acceptată sau respinsă. Lățimea, înălțimea și md5 se calculează local; raportul de aspect îl deduce serverul.

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

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

    Proiectează fațada pe un unghi ales și o arată pe fotografie: materiale aplicabile în țara clădirii, produse vândute acolo în realitate și stratificația din spatele suprafeței. Creează un proiect, pune lucrarea la coadă și returnează id-ul sarcinii. Seed-ul este opțional: dacă lipsește, serverul îl generează și îl returnează.

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

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

    Revizuiește în cuvinte un proiect finalizat. Instrucțiunea se aplică proiectului finalizat, deci tot ce nu menționează rămâne. Revizuirea unghiului principal creează un proiect nou, așa că cel anterior nu este niciodată suprascris.

    ApeleazăGET /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? }

    Citește starea unei randări, a unui deviz sau a unui album.

    ApeleazăGET /renders/{render} · GET /estimates/{estimate}

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

    Sarcinile recente din cont, cele neterminate primele.

    ApeleazăGET /history

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

    Designurile unei clădiri împreună cu randările lor. De aici provin identificatorii de randare pentru deviz și album.

    ApeleazăGET /projects/{project}/concepts

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

    Evaluează proiectul rând cu rând, în materiale și manoperă, la prețurile materialelor indicate în țara clădirii. Moneda și sistemul de măsură urmează implicit acea țară.

    ApeleazăPOST /projects/{project}/concepts/{concept}/estimates

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

    Documentează proiectul pentru echipa care va construi: materialele, stratificația fațadei, notele de siguranță și normele care le susțin. Necesită un render principal finalizat.

    ApeleazăPOST /concepts/{concept}/album/generate

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

    Mărește un randare finalizată. Costă credite și rulează asincron.

    ApeleazăPOST /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 }] }

    Devizul în sine: totalurile, ipotezele din spatele lor și fiecare linie cu cantitate, unitate și preț. get_job raportează starea unui deviz, niciodată conținutul lui.

    ApeleazăGET /estimates/{estimate}

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

    Adaugă o linie la deviz. Unitățile vin din propriul lui sistem de măsură.

    ApeleazăPOST /estimates/{estimate}/items

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

    Modifică o linie a devizului. Se schimbă doar câmpurile trimise; totalurile le recalculează serverul.

    ApeleazăPATCH /estimates/{estimate}/items/{item}

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

    Șterge o linie din deviz.

    ApeleazăDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    Șterge o randare. Ștergerea randării principale readuce designul în ciornă.

    ApeleazăDELETE /renders/{render}

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

    Șterge un design împreună cu randările lui.

    ApeleazăDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    Șterge o clădire cu tot ce conține. Creditele deja cheltuite nu se restituie.

    ApeleazăDELETE /projects/{project}

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

    Pachetele pe care acest cont le poate cumpăra, cu preț și număr de credite.

    ApeleazăGET /tokens/packages

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

    Cumpără un pachet pentru portofelul acestei chei. Cere o cheie emisă cu achiziția activată și nu depășește niciodată ce mai poate cheltui cheia.

    ApeleazăPOST /tokens/purchase

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

    Portofelul agentului, plafonul acestei chei și dacă următorul apel plătit va fi admis.

    ApeleazăGET /tokens/balance

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

    Raportează un defect al acestui API: un câmp descris aici care nu ajunge niciodată, un refuz din a cărui formulare nu reiese pasul următor, un rezultat care nu corespunde cererii. Gratuit și acceptat cu portofelul gol; înapoi vine o referință, nu un răspuns.

    ApeleazăPOST /feedback

Autentificare și chei

  • Cheia călătorește ca jeton Bearer în antetul Authorization. Serverul MCP o citește din GETFACADE_API_KEY și nu trimite nimic altceva.
  • Valoarea se afișează o dată, la emitere, iar din ea se păstrează doar hash-ul. Rotația înseamnă emiterea unei chei noi și revocarea celei vechi.
  • Fiecare cheie poartă un plafon de cheltuieli, aplicat pe server înainte ca apelul să ajungă la un controler. Atingerea plafonului oprește acea cheie, nu contul.
  • Cheile nu administrează chei: este o acțiune umană, iar acele endpointuri răspund 403 unei chei de agent.
  • Revocarea are efect imediat. Apelurile cu o cheie revocată răspund 401.

Lucru asincron și interogare

  • start_design, order_estimate și order_album returnează un identificator de sarcină și se încheie. O randare durează minute: interoghează GET /renders/{render} sau GET /estimates/{estimate} până când starea este finală.
  • Încheierea validării fotografiei este anunțată printr-un websocket pe care agentul nu îl are. Interoghează GET /angles/{angle}/validation și citește validation.is_in_progress; nu deduce singur finalitatea din șirul de stare.
  • Un render finalizat și un album finalizat stau la adrese publice permanente: fără semnătură și fără expirare. Linkul poate fi dat direct unei persoane, ca răspuns la „arată-mi rezultatul”. Nefiind semnat, nu cere voie nimănui: funcționează pentru oricine îl primește și nu poate fi retras.
  • GET /renders/{render}/download este altceva: un URL semnat care expiră în câteva minute și poartă un nume de fișier. Servește la salvarea fișierului, nu la partajarea lui.

Limite de frecvență pe cheie

O cheie de agent are propriile cote, separate de sesiunile umane ale aceluiași cont, astfel încât un agent blocat într-o buclă să nu consume cota persoanei din fața ecranului. Refuzul este ieftin: se decide în middleware, înainte de orice lucru cu baza de date.

DomeniuPe minutPe oră
Citiri și scrieri obișnuite1202000
Interogarea stărilor și a validării1202000
Comenzi de randare, deviz și album10200

Idempotență

Un apel plătit creează o lucrare, iar plata urmează lucrarea. Denumirea apelului este ceea ce permite ca o repetare să returneze aceeași lucrare în loc să creeze a doua.

  • Idempotency-Key este obligatoriu la orice apel plătit făcut cu o cheie API: pornirea sau rafinarea unui design, mărirea unui render, comandarea unui deviz sau a unui album, regenerarea unui deviz. Fără el, apelul răspunde 422 IDEMPOTENCY_KEY_REQUIRED și nu se pune nimic la coadă.
  • Orice valoare de 8 până la 191 de caractere, una pentru fiecare comandă; de obicei un UUID. O comandă nouă primește o valoare nouă: două apeluri identice sub două valori sunt două designuri.
  • Repetarea unui apel cu aceeași valoare și același corp returnează statusul și corpul original, cu Idempotent-Replay: true în răspuns. Nu se pune nimic la coadă și nu se taxează de două ori.
  • Aceeași valoare cu un corp diferit răspunde 422 IDEMPOTENCY_KEY_REUSED. O repetare care sosește cât timp primul apel încă rulează răspunde 409 IDEMPOTENCY_IN_PROGRESS: așteaptă și trimite din nou același apel.
  • Orice 4xx eliberează valoarea, așa că aceeași poate fi trimisă din nou după ce cauza este rezolvată. Valorile sunt ținute minte 24 de ore, pe cont.
  • @getfacade/mcp generează valoarea și reia apelul sub ea de unul singur, deci apelul de instrument nu trebuie să transmită nimic.

Erori

Eșecurile sosesc ca documente de eroare JSON:API. Răspunsurile de validare Laravel nu au formă JSON:API și își poartă textul în message.

StareCodSemnificațieSe poate relua
401Cheia lipsește, a fost revocată sau a expirat.Nu
402AGENT_CREDITS_EXHAUSTEDContul nu mai are credite în domeniul api.Nu
402AGENT_KEY_CAP_REACHEDAceastă cheie și-a epuizat plafonul. Emite altă cheie sau ridică plafonul.Nu
403Acest endpoint nu este disponibil pentru cheile API. API-ul pentru agenți acoperă clădiri, fotografii, designuri, randări, devize, albume și portofelul API. Setările de cont, de autentificare și de plată sunt modificate de o persoană conectată în aplicație.Nu
403AGENT_PURCHASE_NOT_ALLOWEDAceastă cheie a fost emisă fără dreptul de a cumpăra credite.Nu
403AGENT_PURCHASE_EXCEEDS_CAPAchiziția ar duce cheia peste plafonul ei de cheltuială.Nu
409IDEMPOTENCY_IN_PROGRESSPrimul apel cu acest Idempotency-Key nu a răspuns încă. Așteaptă și trimite din nou același apel.Da
422Cererea a fost înțeleasă și respinsă: nume de clădire duplicat, fotografie respinsă, album comandat înainte de finalizarea randării principale.Nu
422IDEMPOTENCY_KEY_REQUIREDUn apel plătit cu cheie API, fără antetul Idempotency-Key. Nu s-a pus nimic la coadă; trimite-l din nou cu antetul.Nu
422IDEMPOTENCY_KEY_REUSEDAcest Idempotency-Key a fost folosit pentru altă cerere. Folosește o valoare nouă pentru o comandă nouă.Nu
429Cota proprie a acestei chei s-a epuizat. Așteaptă, nu relua într-o buclă strânsă.Da

Textul lizibil este scris de API, în limba apelantului. Afișează errors[].detail ca atare, în loc să compui propriul mesaj.

Facturare și admitere

  • Apelurile plătite consumă credite din domeniul api, iar admiterea se uită doar la acest sold: fiecare cheie plătește în credite.
  • Un Pro Plan activ completează portofelul api până la 1.000 de credite o dată pe perioadă de facturare. Peste asta, creditele se cumpără.
  • O cheie își alimentează portofelul doar dacă a fost emisă cu achiziția activată și cel mult cu cât mai poate cheltui, așa că o achiziție nu ridică niciodată plafonul de cheltuială.
  • Domeniul api este un portofel separat. Creditele aplicației, inclusiv nivelul gratuit, nu sunt cheltuite niciodată de o cheie.
  • Cheltuiala se contorizează pe cheie, așa că se vede separat consumul fiecărui asistent.
  • Verificarea prealabilă este GET /tokens/balance, câmpul data.attributes.agent.is_admissible. Blocul apare doar la cheile de agent, iar indicatorul reflectă exact middleware-ul de admitere. Citește-l în loc să compari singur soldul cu plafonul.
  • Admiterea se decide înainte ca lucrul să intre la coadă, așa că un apel respins nu costă nimic.

Jetoane de culoare și de marcă

start_design acceptă două liste independente, de cel mult zece intrări fiecare. Ordinea poartă rolul 60/30/10: prima intrare este culoarea dominantă a pereților.

colors

JetonSemnificație
palette:1O schemă GetFacade pregătită, după identificator.
#8A8F7DO culoare liberă, șase cifre hexazecimale.
paint:412Un eșantion de producător, în forma cu două segmente păstrată pentru compatibilitate.

brand_selections

JetonSemnificație
siding:brand:12Orice produs al acelui producător din acea categorie.
siding:line:40@double-4-dutchlapO gamă, pe o geometrie.
siding:product:88@double-4-dutchlapUn produs, complet precizat.
paint:brand:3Orice culoare a acelei mărci de vopsea.
paint:product:412Un singur eșantion de vopsea.

Gramatica este category:level:id[@value][.value]. Partea de după @ poartă slug-uri de valori de geometrie, unice în cadrul categoriei lor, astfel încât axa căreia îi aparțin se caută, nu se scrie în jeton. Un jeton necunoscut este respins cu 422 și nu este ignorat niciodată în tăcere.

Sesiune completă

O clădire, o fotografie, un design și apoi cele două documente. Instrucțiunea care le produce:

Creează o clădire numită Maple Street 14, încarcă ./front.jpg ca vedere a ei și pornește un design cu pereți gri cald și ancadramente albe. Comandă devizul și albumul pentru rezultat.
Sesiune 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)

Resurse