API agent GetFacade
Conception de façade via MCP et HTTP. Chaque conception est élaborée pour le pays où se trouve le bâtiment : les matériaux qui y sont applicables, les produits que les fabricants y vendent réellement, et la composition technique derrière la surface. Un rendu la montre sur la photo de la maison, le devis la chiffre ligne par ligne, et l'album PDF la documente pour l'entreprise qui la réalise. Chaque chemin ci-dessous est un point d'entrée GetFacade existant, celui-là même qu'appellent les applications iOS, Android et web. Une clé agent restreint qui peut l'appeler, mesure ce qu'elle dépense et s'arrête à son plafond.
- URL de base
- https://api.getfacade.ai/api/v1
- Authentification
- Bearer <agent key>
- Paquet
- @getfacade/mcp
- Environnement d'exécution
- Node.js 20+
- Transport
- stdio (MCP), HTTPS (REST)
- Spécification
- OpenAPI 3.1, v1.0.0
Démarrage rapide
Créer une clé
app.getfacade.aiCompteParamètresAPICréer une clé
La valeur s'affiche une seule fois et ne peut être récupérée, seulement remplacée. Le plafond de dépense se fixe à la création et s'applique à chaque appel payant.
Créer une clé agentDéclarer le serveur MCP
Une entrée dans la configuration du client, puis redémarrage du client. Claude Desktop la garde dans claude_desktop_config.json ; tout autre client MCP accepte les trois mêmes champs.
{ "mcpServers": { "getfacade": { "command": "npx", "args": ["-y", "@getfacade/mcp"], "env": { "GETFACADE_API_KEY": "your-key" } } } }Variables d'environnement Variable Obligatoire Valeur par défaut GETFACADE_API_KEYOui —GETFACADE_API_BASE_URLNon https://api.getfacade.ai/api/v1Ou appeler l'API HTTP directement
La même clé sert de jeton Bearer. Requêtes et réponses sont des documents JSON:API, où id est un champ de premier niveau et ne se trouve jamais dans attributes.
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"}}}'
Outils
Vingt-et-un outils. Le serveur MCP ne conserve aucun état ni règle propre : chaque outil est un ou plusieurs appels aux points de terminaison indiqués à côté, et chaque message que l'agent répète est écrit par l'API.
create_buildingcreate_building(name, goals?, construction_region?) -> { building_id, name }Crée un bâtiment. Le nom est unique dans le compte et fait 50 caractères au plus ; un doublon est refusé avec un 422.
Appelle
POST /projectsupload_photoupload_photo(building_id, file_path, wait_for_validation? = true) -> { view_id, validation: { status, reason? } }Enregistre une vue, téléverse les octets vers une URL présignée, les confirme et interroge le statut jusqu'à ce que la photo soit acceptée ou refusée. Largeur, hauteur et md5 sont calculés localement ; le rapport d'aspect est déduit par le serveur.
Appelle
POST /projects/{project}/angles → PUT (presigned) → POST /angles/{angle}/confirm → GET /angles/{angle}/validationstart_designasynchronestart_design(building_id, view_id, prompt?, style_ids?, colors?, brand_selections?, render_effort?, seed?) -> { design_id, job_id, status, seed }Conçoit la façade sur une vue choisie et la montre sur la photo : matériaux applicables dans le pays du bâtiment, produits qui y sont réellement vendus et composition derrière la surface. Crée une conception, met le travail en file d'attente et renvoie l'identifiant de tâche. La graine est facultative : si elle est omise, le serveur en génère une et la renvoie.
Appelle
POST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/rendersrefine_designasynchronerefine_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 }Révise en mots une conception terminée. L'instruction s'applique à la conception terminée, donc tout ce qu'elle ne mentionne pas est conservé. Réviser une vue principale crée une nouvelle conception, la précédente n'est donc jamais écrasée.
Appelle
GET /renders/{render} → POST /concepts/{concept}/angles/{conceptAngle}/renders (mode: refine)get_jobget_job(job_id, kind: "render" | "album" | "estimate" = "render") -> { status, expected_seconds?, result_url?, error?, error_code? }Lit l'état d'un rendu, d'une estimation ou d'un album.
Appelle
GET /renders/{render} · GET /estimates/{estimate}list_jobslist_jobs(kind?, limit? = 20) -> [{ job_id, kind, status, building_id, created_at }]Tâches récentes du compte, les inachevées d'abord.
Appelle
GET /historylist_designslist_designs(building_id) -> [{ design_id, note, has_main_render, main_render_id, main_render_url, renders }]Designs d'un bâtiment avec leurs rendus. C'est de là que viennent les identifiants de rendu pour une estimation ou un album.
Appelle
GET /projects/{project}/conceptsorder_estimateasynchroneorder_estimate(design_id, render_ids, currency?, measurement_system?, special_requirements?) -> { job_id, status }Chiffre la conception ligne par ligne, en matériaux et en main-d'œuvre, au prix des matériaux indiqués dans le pays du bâtiment. La devise et le système de mesure suivent par défaut ce pays.
Appelle
POST /projects/{project}/concepts/{concept}/estimatesorder_albumasynchroneorder_album(design_id, render_ids, language?, include_blueprints?, include_estimate?, requirements?) -> { job_id, status }Documente la conception pour l'entreprise qui la réalise : les matériaux, la composition de la façade, les consignes de sécurité et les normes qui les fondent. Exige un rendu principal terminé.
Appelle
POST /concepts/{concept}/album/generateupscale_renderasynchroneupscale_render(render_id) -> { job_id, status }Agrandit un rendu terminé. Coûte des crédits et s'exécute de façon asynchrone.
Appelle
POST /renders/{render}/upscaleget_estimateget_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 }] }Le devis lui-même : totaux, hypothèses retenues et chaque ligne avec quantité, unité et prix. get_job indique l'état d'un devis, jamais son contenu.
Appelle
GET /estimates/{estimate}add_estimate_lineadd_estimate_line(estimate_id, section, name, quantity, unit_price, unit?, category?) -> { line_id }Ajoute une ligne au devis. Les unités viennent du système de mesure du devis lui-même.
Appelle
POST /estimates/{estimate}/itemsupdate_estimate_lineupdate_estimate_line(estimate_id, line_id, name?, quantity?, unit_price?, unit?, category?, section?) -> { line_id }Modifie une ligne du devis. Seuls les champs transmis changent ; le serveur recalcule les totaux.
Appelle
PATCH /estimates/{estimate}/items/{item}delete_estimate_linedelete_estimate_line(estimate_id, line_id) -> { deleted }Supprime une ligne du devis.
Appelle
DELETE /estimates/{estimate}/items/{item}delete_renderdelete_render(render_id) -> { deleted }Supprime un rendu. Supprimer le rendu principal ramène son design à l'état de brouillon.
Appelle
DELETE /renders/{render}delete_designdelete_design(building_id, design_id) -> { deleted }Supprime un design et les rendus qu'il contient.
Appelle
DELETE /projects/{project}/concepts/{concept}delete_buildingdelete_building(building_id) -> { deleted }Supprime un bâtiment avec tout son contenu. Les crédits déjà dépensés ne sont pas remboursés.
Appelle
DELETE /projects/{project}list_token_packageslist_token_packages() -> [{ package, tokens, price, currency }]Les packs que ce compte peut acheter, avec leur prix et leur nombre de crédits.
Appelle
GET /tokens/packagesbuy_tokensasynchronebuy_tokens(package) -> { status, transaction_id, tokens, checkout_url?, detail }Achète un pack pour le portefeuille de cette clé. Exige une clé créée avec l'achat autorisé et ne dépasse jamais ce que la clé peut encore dépenser.
Appelle
POST /tokens/purchaseget_balanceget_balance() -> { balance, scope: "api", spend_cap, spent, remaining, is_admissible }Portefeuille agent, plafond de cette clé et indication que le prochain appel payant sera admis.
Appelle
GET /tokens/balancereport_problemreport_problem(message, category?, context?: { tool, endpoint, status_code, job_id, expected, actual }) -> { reference, message }Signale un défaut de cette API : un champ décrit ici qui n'arrive jamais, un refus dont la formulation n'ouvre aucune suite, un résultat qui ne correspond pas à la demande. Gratuit et accepté avec un solde vide ; ce qui revient est une référence, pas une réponse.
Appelle
POST /feedback
Authentification et clés
- La clé voyage comme jeton Bearer dans l'en-tête
Authorization. Le serveur MCP la lit dansGETFACADE_API_KEYet n'envoie rien d'autre. - La valeur s'affiche une fois, à la création, et seul son hachage est conservé. La rotation consiste à créer une clé et à révoquer l'ancienne.
- Chaque clé porte un plafond de dépense, appliqué côté serveur avant que l'appel n'atteigne un contrôleur. Un plafond atteint arrête cette clé, pas le compte.
- Les clés ne gèrent pas les clés : c'est une action humaine, et ces points de terminaison répondent 403 à une clé agent.
- La révocation prend effet immédiatement. Les appels avec une clé révoquée répondent 401.
Travail asynchrone et interrogation
start_design,order_estimateetorder_albumrenvoient un identifiant de tâche et s'arrêtent là. Un rendu prend des minutes : interrogezGET /renders/{render}ouGET /estimates/{estimate}jusqu'à un état terminal.- La fin de la validation de la photo est annoncée par un websocket dont l'agent ne dispose pas. Interrogez
GET /angles/{angle}/validationet lisezvalidation.is_in_progress; ne déduisez pas vous-même la finalité de la chaîne de statut. - Un rendu terminé et un album terminé résident à des URL publiques permanentes : sans signature, sans expiration. Le lien peut être remis directement à une personne, en réponse à « montre-moi le résultat ». N'étant pas signé, il ne demande la permission à personne : il continue de fonctionner pour quiconque le reçoit et ne peut pas être révoqué.
GET /renders/{render}/downloadest autre chose : une URL signée qui expire en quelques minutes et porte un nom de fichier. Elle sert à enregistrer le fichier, pas à le partager.
Limites de débit par clé
Une clé agent dispose de ses propres compteurs, séparés des sessions humaines du même compte, afin qu'un agent en boucle ne consomme pas le quota de la personne devant l'écran. Le refus coûte peu : il est décidé dans le middleware, avant tout travail en base.
| Portée | Par minute | Par heure |
|---|---|---|
| Lectures et écritures ordinaires | 120 | 2000 |
| Interrogation des statuts et de la validation | 120 | 2000 |
| Commandes de rendu, d'estimation et d'album | 10 | 200 |
Idempotence
Un appel payant crée une tâche, et la facturation suit la tâche. C'est le fait de nommer l'appel qui permet à un renvoi de retourner la même tâche au lieu d'en créer une seconde.
Idempotency-Keyest obligatoire sur tout appel payant effectué avec une clé API : lancer ou retoucher un design, agrandir un rendu, commander un devis ou un album, régénérer un devis. Sans lui, l'appel répond 422IDEMPOTENCY_KEY_REQUIREDet rien n'est mis en file.- Toute valeur de 8 à 191 caractères, une par commande ; un UUID est le choix habituel. Une nouvelle commande prend une nouvelle valeur : deux appels identiques sous deux valeurs sont deux designs.
- Renvoyer un appel avec la même valeur et le même corps retourne le statut et le corps d'origine, avec
Idempotent-Replay: truedans la réponse. Rien n'est mis en file et rien n'est facturé deux fois. - La même valeur avec un corps différent répond 422
IDEMPOTENCY_KEY_REUSED. Un renvoi qui arrive pendant que le premier appel tourne encore répond 409IDEMPOTENCY_IN_PROGRESS: attendez, puis renvoyez le même appel. - Toute réponse 4xx libère la valeur, qui peut donc être renvoyée une fois la cause corrigée. Les valeurs sont mémorisées 24 heures, par compte.
@getfacade/mcpgénère la valeur et renvoie l'appel sous celle-ci de lui-même : il n'y a rien à passer dans l'appel d'outil.
Erreurs
Les échecs arrivent sous forme de documents d'erreur JSON:API. Les réponses de validation Laravel n'ont pas cette forme et portent leur texte dans message.
| Statut | Code | Signification | Réessayable |
|---|---|---|---|
401 | — | La clé est absente, révoquée ou expirée. | Non |
402 | AGENT_CREDITS_EXHAUSTED | Le compte n'a plus de crédits de portée api. | Non |
402 | AGENT_KEY_CAP_REACHED | Cette clé a dépensé son plafond. Créez une autre clé ou relevez le plafond. | Non |
403 | — | Ce point de terminaison n'est pas accessible avec une clé API. L'API pour agents couvre les bâtiments, les photos, les designs, les rendus, les devis, les albums et le portefeuille API. Les paramètres de compte, de connexion et de paiement sont modifiés par une personne connectée dans l'application. | Non |
403 | AGENT_PURCHASE_NOT_ALLOWED | Cette clé a été créée sans le droit d'acheter des crédits. | Non |
403 | AGENT_PURCHASE_EXCEEDS_CAP | L'achat ferait dépasser à la clé son plafond de dépense. | Non |
409 | IDEMPOTENCY_IN_PROGRESS | Le premier appel portant cet Idempotency-Key n'a pas encore répondu. Attendez et renvoyez le même appel. | Oui |
422 | — | La requête a été comprise et refusée : nom de bâtiment en double, photo rejetée, album commandé avant la fin du rendu principal. | Non |
422 | IDEMPOTENCY_KEY_REQUIRED | Un appel payant avec une clé API et sans en-tête Idempotency-Key. Rien n'a été mis en file ; renvoyez-le avec l'en-tête. | Non |
422 | IDEMPOTENCY_KEY_REUSED | Cet Idempotency-Key a servi pour une autre requête. Utilisez une nouvelle valeur pour une nouvelle commande. | Non |
429 | — | Le compteur propre à cette clé est épuisé. Ralentissez, ne réessayez pas en boucle serrée. | Oui |
Le texte lisible est écrit par l'API, dans la langue de l'appelant. Affichez errors[].detail tel quel plutôt que de composer votre propre message.
Facturation et admission
- Les appels payants puisent dans les crédits de portée
api, et l'admission ne regarde que ce solde : chaque clé paie en crédits. - Un Pro Plan actif porte le portefeuille
apià 1 000 crédits une fois par période de facturation. Au-delà, les crédits s'achètent. - Une clé ne recharge son portefeuille que si elle a été créée avec l'achat autorisé, et seulement à hauteur de ce qu'elle peut encore dépenser : un achat ne relève donc jamais le plafond.
- La portée
apiest un portefeuille distinct. Les crédits de l'application, tranche gratuite comprise, ne sont jamais dépensés par une clé. - La dépense est comptée par clé, ce qui rend visible la consommation de chaque assistant.
- Le contrôle préalable est
GET /tokens/balance, champdata.attributes.agent.is_admissible. Le bloc n'apparaît que pour les clés agent, et l'indicateur reflète exactement le middleware d'admission. Lisez-le au lieu de comparer vous-même le solde et le plafond. - L'admission est tranchée avant toute mise en file, donc un appel refusé ne dépense rien.
Jetons de couleur et de marque
start_design accepte deux listes indépendantes de dix entrées au plus. L'ordre porte le rôle 60/30/10 : la première entrée est la couleur dominante des murs.
colors
| Jeton | Signification |
|---|---|
palette:1 | Une harmonie GetFacade, par identifiant. |
#8A8F7D | Une couleur libre, six chiffres hexadécimaux. |
paint:412 | Une teinte de fabricant, dans la forme à deux segments conservée pour compatibilité. |
brand_selections
| Jeton | Signification |
|---|---|
siding:brand:12 | N'importe quel produit de ce fabricant dans cette catégorie. |
siding:line:40@double-4-dutchlap | Une gamme, sur une géométrie. |
siding:product:88@double-4-dutchlap | Un produit, entièrement précisé. |
paint:brand:3 | N'importe quelle teinte de cette marque de peinture. |
paint:product:412 | Une teinte de peinture. |
La grammaire est category:level:id[@value][.value]. La partie après @ porte des slugs de valeurs de géométrie, uniques dans leur catégorie : l'axe auquel ils appartiennent se retrouve par recherche au lieu d'être écrit dans le jeton. Un jeton inconnu est refusé avec un 422, jamais ignoré en silence.
Session de bout en bout
Un bâtiment, une photo, un design, puis les deux documents. L'instruction qui produit tout cela :
Crée un bâtiment nommé Maple Street 14, téléverse ./front.jpg comme vue et lance un design avec des murs gris chaud et des encadrements blancs. Commande l'estimation et l'album pour le résultat.
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)