API per agenti di GetFacade

Progettazione della facciata su MCP e HTTP. Ogni progetto è elaborato per il paese in cui sorge l'edificio: materiali applicabili lì, prodotti che i produttori vi vendono davvero e la stratigrafia tecnica dietro la superficie. Un render lo mostra sulla foto della casa, il preventivo lo quantifica voce per voce e l'album PDF lo documenta per l'impresa che lo realizza. Ogni percorso qui sotto è un endpoint GetFacade già esistente, lo stesso che chiamano le app iOS, Android e web. Una chiave agent restringe soltanto chi può chiamarlo, misura la spesa e si ferma al proprio tetto.

URL di base
https://api.getfacade.ai/api/v1
Autenticazione
Bearer <agent key>
Pacchetto
@getfacade/mcp
Ambiente di esecuzione
Node.js 20+
Trasporto
stdio (MCP), HTTPS (REST)
Specifica
OpenAPI 3.1, v1.0.0

Avvio rapido

  1. Emetti una chiave

    app.getfacade.aiAccountImpostazioniAPICrea chiave

    Il valore compare una sola volta e non è recuperabile, solo sostituibile. Il tetto di spesa si imposta all'emissione e vale su ogni chiamata a pagamento.

    Emetti una chiave agente
  2. Registra il server MCP

    Una voce nella configurazione del client, poi riavvia il client. Claude Desktop la tiene in claude_desktop_config.json; ogni altro client MCP accetta gli stessi tre campi.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    Variabili d'ambiente
    VariabileObbligatoriaValore predefinito
    GETFACADE_API_KEY
    GETFACADE_API_BASE_URLNohttps://api.getfacade.ai/api/v1
  3. Oppure chiama direttamente l'API HTTP

    La stessa chiave funziona come token Bearer. Richieste e risposte sono documenti JSON:API, dove id è un campo di primo livello e non sta mai dentro 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"}}}'

Strumenti

Ventuno strumenti. Il server MCP non conserva stato né regole proprie: ogni strumento è una o più chiamate agli endpoint indicati accanto, e ogni messaggio che l'agente riporta è scritto dall'API.

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

    Crea un edificio. Il nome è unico all'interno dell'account e lungo al massimo 50 caratteri; un duplicato viene rifiutato con 422.

    ChiamaPOST /projects

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

    Registra una vista, carica i byte su un URL prefirmato, li conferma e interroga finché la foto non è accettata o rifiutata. Larghezza, altezza e md5 si calcolano in locale; le proporzioni le deduce il server.

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

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

    Progetta la facciata su una vista scelta e la mostra sulla foto: materiali applicabili nel paese dell'edificio, prodotti davvero in vendita lì e la stratigrafia dietro la superficie. Crea un progetto, mette il lavoro in coda e restituisce l'id del lavoro. Il seed è facoltativo: se omesso, il server lo genera e lo restituisce.

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

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

    Rivede a parole un progetto terminato. L'istruzione si applica al progetto finito, quindi resta tutto ciò che non viene nominato. Rivedere una vista principale crea un nuovo progetto, così il precedente non viene mai sovrascritto.

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

    Legge lo stato di un render, di un preventivo o di un album.

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

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

    Lavori recenti dell'account, prima quelli non conclusi.

    ChiamaGET /history

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

    Design di un edificio con i loro render. Da qui arrivano gli identificativi dei render per preventivo e album.

    ChiamaGET /projects/{project}/concepts

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

    Quantifica il progetto voce per voce, in materiali e manodopera, ai prezzi che quei materiali hanno nel paese dell'edificio. Valuta e sistema di misura seguono per impostazione predefinita quel paese.

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

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

    Documenta il progetto per l'impresa che lo realizza: i materiali, la stratigrafia della facciata, le note di sicurezza e le norme che le sostengono. Richiede un render principale completato.

    ChiamaPOST /concepts/{concept}/album/generate

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

    Ingrandisce un render completato. Costa crediti e viene eseguito in modo asincrono.

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

    Il preventivo stesso: totali, le ipotesi alla base e ogni riga con quantità, unità e prezzo. get_job riporta lo stato di un preventivo, mai il suo contenuto.

    ChiamaGET /estimates/{estimate}

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

    Aggiunge una riga al preventivo. Le unità provengono dal suo sistema di misura.

    ChiamaPOST /estimates/{estimate}/items

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

    Modifica una riga del preventivo. Cambiano solo i campi passati; i totali li ricalcola il server.

    ChiamaPATCH /estimates/{estimate}/items/{item}

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

    Rimuove una riga dal preventivo.

    ChiamaDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    Elimina un render. Eliminando il render principale, il suo progetto torna in bozza.

    ChiamaDELETE /renders/{render}

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

    Elimina un progetto con i render che contiene.

    ChiamaDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    Elimina un edificio con tutto il suo contenuto. I crediti già spesi non vengono rimborsati.

    ChiamaDELETE /projects/{project}

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

    I pacchetti acquistabili da questo account, con prezzo e numero di crediti.

    ChiamaGET /tokens/packages

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

    Acquista un pacchetto per il portafoglio di questa chiave. Richiede una chiave emessa con l'acquisto abilitato e non va mai oltre ciò che la chiave può ancora spendere.

    ChiamaPOST /tokens/purchase

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

    Portafoglio dell'agente, tetto di questa chiave e se la prossima chiamata a pagamento sarà ammessa.

    ChiamaGET /tokens/balance

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

    Segnala un difetto di questa API: un campo descritto qui che non arriva mai, un rifiuto dalla cui formulazione non segue alcun passo, un risultato che non corrisponde alla richiesta. Gratuito e accettato anche a saldo zero; torna un riferimento, non una risposta.

    ChiamaPOST /feedback

Autenticazione e chiavi

  • La chiave viaggia come token Bearer nell'intestazione Authorization. Il server MCP la legge da GETFACADE_API_KEY e non invia altro.
  • Il valore compare una volta, all'emissione, e viene conservato solo il suo hash. Ruotare significa emettere una nuova chiave e revocare la vecchia.
  • Ogni chiave porta un tetto di spesa, applicato lato server prima che la chiamata raggiunga un controller. Il tetto raggiunto ferma quella chiave, non l'account.
  • Le chiavi non gestiscono chiavi: è un'azione umana, e quegli endpoint rispondono 403 a una chiave agente.
  • La revoca ha effetto immediato. Le chiamate con una chiave revocata rispondono 401.

Lavoro asincrono e polling

  • start_design, order_estimate e order_album restituiscono un identificativo di lavoro e finiscono lì. Un render richiede minuti: interroga GET /renders/{render} o GET /estimates/{estimate} finché lo stato non è terminale.
  • La fine della validazione della foto è annunciata da un websocket che l'agente non ha. Interroga GET /angles/{angle}/validation e leggi validation.is_in_progress; non dedurre da solo la terminalità dalla stringa di stato.
  • Un render completato e un album completato stanno a URL pubblici permanenti: senza firma e senza scadenza. Il link si può consegnare direttamente a una persona, come risposta a «mostrami il risultato». Non essendo firmato non chiede il permesso a nessuno: continua a funzionare per chiunque lo riceva e non può essere revocato.
  • GET /renders/{render}/download è un'altra cosa: un URL firmato che scade in pochi minuti e porta un nome file. Serve a salvare il file, non a condividerlo.

Limiti di frequenza per chiave

Una chiave agente ha contatori propri, separati dalle sessioni umane dello stesso account, così un agente in loop non consuma la quota di chi sta davanti allo schermo. Il rifiuto costa poco: viene deciso nel middleware, prima di qualsiasi lavoro sul database.

AmbitoAl minutoAll'ora
Letture e scritture ordinarie1202000
Polling di stato e validazione1202000
Ordini di render, preventivo e album10200

Idempotenza

Una chiamata a pagamento crea un lavoro, e l'addebito segue il lavoro. È il nome della chiamata a permettere che un rinvio restituisca lo stesso lavoro invece di crearne un secondo.

  • Idempotency-Key è obbligatoria su ogni chiamata a pagamento fatta con una chiave API: avviare o rifinire un design, ingrandire un render, ordinare un preventivo o un album, rigenerare un preventivo. Senza di essa la chiamata risponde 422 IDEMPOTENCY_KEY_REQUIRED e non viene messo in coda nulla.
  • Un valore qualsiasi da 8 a 191 caratteri, uno per ordine; di solito si usa un UUID. Un nuovo ordine prende un valore nuovo: due chiamate identiche con due valori sono due design.
  • Ripetere una chiamata con lo stesso valore e lo stesso corpo restituisce stato e corpo originali, con Idempotent-Replay: true nella risposta. Non viene messo in coda nulla e non si paga due volte.
  • Lo stesso valore con un corpo diverso risponde 422 IDEMPOTENCY_KEY_REUSED. Un rinvio che arriva mentre la prima chiamata è ancora in corso risponde 409 IDEMPOTENCY_IN_PROGRESS: attendi e invia di nuovo la stessa chiamata.
  • Qualsiasi 4xx libera il valore, che può essere inviato di nuovo una volta risolta la causa. I valori restano in memoria 24 ore, per account.
  • @getfacade/mcp genera il valore e ripete la chiamata da solo, quindi nella chiamata allo strumento non va passato nulla.

Errori

Gli errori arrivano come documenti JSON:API. Le risposte di validazione di Laravel non hanno forma JSON:API e portano il testo in message.

StatoCodiceSignificatoRipetibile
401La chiave manca, è revocata o è scaduta.No
402AGENT_CREDITS_EXHAUSTEDL'account non ha più crediti di ambito api.No
402AGENT_KEY_CAP_REACHEDQuesta chiave ha esaurito il suo tetto. Emetti un'altra chiave o alza il tetto.No
403Questo endpoint non è disponibile per le chiavi API. L'API per agenti copre edifici, foto, design, render, preventivi, album e il portafoglio API. Le impostazioni di account, accesso e pagamento le modifica una persona che ha effettuato l'accesso nell'app.No
403AGENT_PURCHASE_NOT_ALLOWEDQuesta chiave è stata emessa senza il permesso di acquistare crediti.No
403AGENT_PURCHASE_EXCEEDS_CAPL'acquisto porterebbe la chiave oltre il suo tetto di spesa.No
409IDEMPOTENCY_IN_PROGRESSLa prima chiamata con questo Idempotency-Key non ha ancora risposto. Attendi e invia di nuovo la stessa chiamata.
422La richiesta è stata compresa e rifiutata: nome edificio duplicato, foto respinta, album ordinato prima del completamento del render principale.No
422IDEMPOTENCY_KEY_REQUIREDUna chiamata a pagamento con chiave API e senza header Idempotency-Key. Non è stato messo in coda nulla; rinviala con l'header.No
422IDEMPOTENCY_KEY_REUSEDQuesto Idempotency-Key è stato usato per un'altra richiesta. Usa un valore nuovo per un nuovo ordine.No
429Il contatore proprio di questa chiave è esaurito. Rallenta, non ritentare in un ciclo stretto.

Il testo leggibile lo scrive l'API, nella lingua del chiamante. Mostra errors[].detail così com'è invece di comporre un messaggio tuo.

Fatturazione e ammissione

  • Le chiamate a pagamento attingono ai crediti dell'ambito api e l'ammissione guarda solo quel saldo: ogni chiave paga in crediti.
  • Un Pro Plan attivo riporta il portafoglio api a 1.000 crediti una volta per periodo di fatturazione. Oltre, i crediti si acquistano.
  • Una chiave ricarica il proprio portafoglio solo se è stata emessa con l'acquisto abilitato, e solo fino a quanto può ancora spendere: un acquisto non alza mai il tetto di spesa.
  • L'ambito api è un portafoglio a sé. I crediti dell'app, piano gratuito incluso, non vengono mai spesi da una chiave.
  • La spesa è contata per chiave, quindi il consumo di ciascun assistente è visibile separatamente.
  • Il controllo preliminare è GET /tokens/balance, campo data.attributes.agent.is_admissible. Il blocco compare solo per le chiavi agente e il flag rispecchia esattamente il middleware di ammissione. Leggilo invece di confrontare saldo e tetto.
  • L'ammissione è decisa prima che il lavoro entri in coda, quindi una chiamata rifiutata non spende nulla.

Token di colore e di marca

start_design accetta due elenchi indipendenti di al massimo dieci voci. L'ordine porta il ruolo 60/30/10: la prima voce è il colore dominante delle pareti.

colors

TokenSignificato
palette:1Uno schema curato da GetFacade, per identificativo.
#8A8F7DUn colore libero, sei cifre esadecimali.
paint:412Un campione di produttore, nella forma a due segmenti mantenuta per compatibilità.

brand_selections

TokenSignificato
siding:brand:12Qualsiasi prodotto di quel produttore in quella categoria.
siding:line:40@double-4-dutchlapUna linea, su una geometria.
siding:product:88@double-4-dutchlapUn prodotto, completamente specificato.
paint:brand:3Qualsiasi colore di quella marca di pitture.
paint:product:412Un singolo campione di pittura.

La grammatica è category:level:id[@value][.value]. La parte dopo @ porta slug di valori di geometria, unici nella loro categoria, così l'asse a cui appartengono si ricava con una ricerca invece di essere scritto nel token. Un token sconosciuto viene rifiutato con 422 e mai ignorato in silenzio.

Sessione completa

Un edificio, una foto, un design e poi i due documenti. L'istruzione che lo produce:

Crea un edificio chiamato Maple Street 14, carica ./front.jpg come sua vista e avvia un design con pareti grigio caldo e cornici bianche. Ordina il preventivo e l'album per il risultato.
Sessione 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)

Risorse