API הסוכנים של GetFacade

תכנון חזיתות דרך MCP ו-HTTP. כל תכנון נבנה עבור המדינה שבה עומד המבנה: חומרים שישימים שם, מוצרים שהיצרנים באמת מוכרים שם, ושכבות המבנה הטכניות מאחורי פני השטח. הרינדור מציג אותו על תצלום הבית, האומדן מתמחר אותו שורה אחר שורה, ואלבום ה-PDF מתעד אותו עבור הצוות שיבצע. כל נתיב למטה הוא נקודת קצה קיימת של GetFacade, אותה אחת שאפליקציות iOS, אנדרואיד והדפדפן קוראות לה. מפתח סוכן רק מצמצם מי רשאי לקרוא לה, מודד את ההוצאה ונעצר בתקרה שלו.

כתובת בסיס
https://api.getfacade.ai/api/v1
אימות
Bearer <agent key>
חבילה
@getfacade/mcp
סביבת הרצה
Node.js 20+
תעבורה
stdio (MCP), HTTPS (REST)
מפרט
OpenAPI 3.1, v1.0.0

התחלה מהירה

  1. הנפיקו מפתח

    app.getfacade.aiחשבוןהגדרותAPIיצירת מפתח

    הערך מוצג פעם אחת ואי אפשר לשחזר אותו, רק להחליף. תקרת ההוצאה נקבעת בהנפקה ונאכפת בכל קריאה בתשלום.

    הנפקת מפתח סוכן
  2. רשמו את שרת ה-MCP

    רשומה אחת בתצורת הלקוח, ואז הפעלה מחדש של הלקוח. Claude Desktop שומר אותה ב-claude_desktop_config.json; כל לקוח MCP אחר מקבל את אותם שלושה שדות.

    claude_desktop_config.json
    {
      "mcpServers": {
        "getfacade": {
          "command": "npx",
          "args": ["-y", "@getfacade/mcp"],
          "env": { "GETFACADE_API_KEY": "your-key" }
        }
      }
    }
    משתני סביבה
    משתנהנדרשברירת מחדל
    GETFACADE_API_KEYכן
    GETFACADE_API_BASE_URLלאhttps://api.getfacade.ai/api/v1
  3. או קראו ישירות ל-API

    אותו מפתח משמש כאסימון Bearer. הבקשות והתשובות הן מסמכי JSON:API, שבהם id הוא שדה ברמה העליונה ולעולם אינו יושב בתוך 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"}}}'

כלים

עשרים ואחד כלים. שרת ה-MCP אינו שומר מצב ואין לו כללים משלו: כל כלי הוא קריאה אחת או יותר לנקודות הקצה המצוינות לצידו, וכל הודעה שהסוכן מוסר נכתבת על ידי ה-API.

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

    יוצר מבנה. השם ייחודי בתוך החשבון ואורכו עד 50 תווים; כפילות נדחית עם 422.

    קורא לPOST /projects

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

    רושם תצוגה, מעלה את הבתים לכתובת חתומה מראש, מאשר אותם ומתשאל עד שהתצלום מתקבל או נדחה. רוחב, גובה ו-md5 מחושבים מקומית; את יחס הממדים גוזר השרת.

    קורא לPOST /projects/{project}/angles → PUT (presigned) → POST /angles/{angle}/confirm → GET /angles/{angle}/validation

  • start_designאסינכרוני
    start_design(building_id, view_id, prompt?, style_ids?, colors?,
                 brand_selections?, render_effort?, seed?)
      -> { design_id, job_id, status, seed }

    מתכנן את החזית בזווית שנבחרה ומציג אותה על התצלום: חומרים ישימים במדינת המבנה, מוצרים שנמכרים שם באמת, ושכבות המבנה שמאחורי פני השטח. יוצר תכנון, מכניס את העבודה לתור ומחזיר מזהה משימה. ה-seed אופציונלי: אם לא נמסר, השרת מייצר אותו ומחזיר אותו.

    קורא לPOST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/renders

  • refine_designאסינכרוני
    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 }

    מתקן במילים תכנון מוגמר. ההוראה חלה על התכנון המוגמר, ולכן כל מה שלא הוזכר בה נשמר. תיקון של הזווית הראשית יוצר תכנון חדש, כך שהקודם לעולם אינו נדרס.

    קורא ל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? }

    קורא את מצבם של רינדור, אומדן או אלבום בודדים.

    קורא לGET /renders/{render} · GET /estimates/{estimate}

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

    המשימות האחרונות בחשבון, הלא גמורות בראש.

    קורא לGET /history

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

    העיצובים של מבנה יחד עם הרינדורים שלהם. מכאן מגיעים מזהי הרינדור לאומדן ולאלבום.

    קורא לGET /projects/{project}/concepts

  • order_estimateאסינכרוני
    order_estimate(design_id, render_ids, currency?,
                   measurement_system?, special_requirements?)
      -> { job_id, status }

    מתמחר את התכנון שורה אחר שורה, בחומרים ובעבודה, במחירים שיש לחומרים שצוינו במדינת המבנה. המטבע ושיטת המידה נגזרים כברירת מחדל מאותה מדינה.

    קורא לPOST /projects/{project}/concepts/{concept}/estimates

  • order_albumאסינכרוני
    order_album(design_id, render_ids, language?, include_blueprints?,
                include_estimate?, requirements?)
      -> { job_id, status }

    מתעד את התכנון עבור הצוות שיבצע: החומרים, שכבות החזית, הערות בטיחות והתקנים שעליהם הן נשענות. דורש רינדור ראשי מוגמר.

    קורא לPOST /concepts/{concept}/album/generate

  • upscale_renderאסינכרוני
    upscale_render(render_id)
      -> { job_id, status }

    מגדיל רינדור שהושלם. עולה קרדיטים ורץ באופן אסינכרוני.

    קורא ל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 }] }

    האומדן עצמו: הסכומים, ההנחות שמאחוריהם וכל שורה עם כמות, יחידה ומחיר. get_job מדווח על מצב האומדן, לעולם לא על תוכנו.

    קורא לGET /estimates/{estimate}

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

    מוסיף שורה לאומדן. היחידות מגיעות משיטת המידות של האומדן עצמו.

    קורא לPOST /estimates/{estimate}/items

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

    משנה שורה באומדן. רק השדות שנשלחו משתנים, והסכומים מחושבים מחדש בשרת.

    קורא לPATCH /estimates/{estimate}/items/{item}

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

    מסיר שורה מהאומדן.

    קורא לDELETE /estimates/{estimate}/items/{item}

  • delete_render
    delete_render(render_id)
      -> { deleted }

    מוחק רינדור. מחיקת הרינדור הראשי מחזירה את העיצוב שלו לטיוטה.

    קורא לDELETE /renders/{render}

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

    מוחק עיצוב יחד עם הרינדורים שתחתיו.

    קורא לDELETE /projects/{project}/concepts/{concept}

  • delete_building
    delete_building(building_id)
      -> { deleted }

    מוחק מבנה על כל תכולתו. קרדיטים שכבר הוצאו אינם מוחזרים.

    קורא לDELETE /projects/{project}

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

    החבילות שהחשבון יכול לקנות, עם המחיר ומספר הקרדיטים.

    קורא לGET /tokens/packages

  • buy_tokensאסינכרוני
    buy_tokens(package)
      -> { status, transaction_id, tokens, checkout_url?, detail }

    קונה חבילה אחת לארנק של המפתח הזה. דורש מפתח שהונפק עם הרשאת רכישה, ולעולם לא חורג ממה שעוד מותר למפתח להוציא.

    קורא לPOST /tokens/purchase

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

    ארנק הסוכן, תקרת המפתח הזה, והאם הקריאה הבאה בתשלום תתקבל.

    קורא לGET /tokens/balance

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

    מדווח על תקלה ב-API הזה: שדה שמתואר כאן ואינו מגיע, סירוב שמנוסחו לא נובע צעד הבא, תוצאה שאינה תואמת את מה שהתבקש. חינם ומתקבל גם בארנק ריק; חוזר מספר סימוכין, לא תשובה.

    קורא לPOST /feedback

אימות ומפתחות

  • המפתח נשלח כאסימון Bearer בכותרת Authorization. שרת ה-MCP קורא אותו מ-GETFACADE_API_KEY ואינו שולח דבר מלבדו.
  • הערך מוצג פעם אחת, בהנפקה, ונשמר ממנו רק גיבוב. סבב מפתחות פירושו הנפקת מפתח חדש וביטול הישן.
  • לכל מפתח יש תקרת הוצאה, הנאכפת בשרת לפני שהקריאה מגיעה לבקר. הגעה לתקרה עוצרת את המפתח הזה, לא את החשבון.
  • מפתחות אינם מנהלים מפתחות: זו פעולה אנושית, ונקודות הקצה האלה משיבות 403 למפתח סוכן.
  • ביטול נכנס לתוקף מיד. קריאות במפתח מבוטל מקבלות 401.

עבודה אסינכרונית ותשאול

  • start_design, order_estimate ו-order_album מחזירים מזהה משימה ומסתיימים. רינדור אורך דקות: תשאלו את GET /renders/{render} או GET /estimates/{estimate} עד שהמצב סופי.
  • סיום בדיקת התצלום מוכרז בערוץ websocket שאין לסוכן. תשאלו את GET /angles/{angle}/validation וקראו את validation.is_in_progress; אל תסיקו בעצמכם סופיות ממחרוזת המצב.
  • רינדור מוגמר ואלבום מוגמר נמצאים בכתובות ציבוריות קבועות: בלי חתימה ובלי תפוגה. אפשר למסור את הקישור לאדם ישירות, וזו התשובה ל«תראה לי את התוצאה». מכיוון שאינו חתום הוא אינו מבקש רשות מאיש: הוא ממשיך לעבוד אצל כל מי שמקבל אותו, ואי אפשר לבטל אותו.
  • GET /renders/{render}/download הוא דבר אחר: כתובת חתומה שפגה בתוך דקות ונושאת שם קובץ. היא נועדה לשמירת הקובץ, לא לשיתופו.

מגבלות קצב לכל מפתח

למפתח סוכן יש מכסות משלו, נפרדות מהפעילות האנושית באותו חשבון, כדי שסוכן שנתקע בלולאה לא יכלה את המכסה של מי שיושב מול המסך. הסירוב זול: הוא מתקבל בשכבת הביניים, לפני כל עבודה מול מסד הנתונים.

תחוםלדקהלשעה
קריאות וכתיבות רגילות1202000
תשאול מצב ובדיקה1202000
הזמנות רינדור, אומדן ואלבום10200

אידמפוטנטיות

קריאה בתשלום יוצרת משימה, והחיוב הולך אחרי המשימה. מתן שם לקריאה הוא מה שמאפשר לחזרה עליה להחזיר את אותה משימה במקום ליצור שנייה.

  • Idempotency-Key נדרשת בכל קריאה בתשלום שנעשית עם מפתח API: התחלת עיצוב או שיפורו, הגדלת רינדור, הזמנת אומדן או אלבום, יצירת אומדן מחדש. בלעדיה הקריאה משיבה 422 IDEMPOTENCY_KEY_REQUIRED ודבר לא נכנס לתור.
  • כל ערך באורך 8 עד 191 תווים, אחד לכל הזמנה; בדרך כלל UUID. הזמנה חדשה מקבלת ערך חדש: שתי קריאות זהות תחת שני ערכים הן שני עיצובים.
  • חזרה על קריאה עם אותו ערך ואותו גוף מחזירה את הסטטוס והגוף המקוריים, עם Idempotent-Replay: true בתשובה. דבר לא נכנס לתור ודבר לא מחויב פעמיים.
  • אותו ערך עם גוף שונה משיב 422 IDEMPOTENCY_KEY_REUSED. חזרה שמגיעה בזמן שהקריאה הראשונה עדיין רצה משיבה 409 IDEMPOTENCY_IN_PROGRESS: המתינו ושלחו את אותה קריאה שוב.
  • כל 4xx משחרר את הערך, כך שאפשר לשלוח אותו שוב אחרי שהסיבה תוקנה. הערכים נשמרים 24 שעות, לכל חשבון.
  • @getfacade/mcp מייצר את הערך וחוזר על הקריאה איתו בעצמו, כך שאין מה להעביר בקריאה לכלי.

שגיאות

כשלים מגיעים כמסמכי שגיאה של JSON:API. תשובות האימות של Laravel אינן בתבנית הזאת ונושאות את הטקסט בשדה message.

סטטוסקודמשמעותניתן לנסות שוב
401המפתח חסר, בוטל או פג.לא
402AGENT_CREDITS_EXHAUSTEDבחשבון לא נותרו קרדיטים בהיקף api.לא
402AGENT_KEY_CAP_REACHEDהמפתח הזה מיצה את התקרה שלו. הנפיקו מפתח אחר או העלו את התקרה.לא
403נקודת קצה זו אינה זמינה למפתחות API. ממשק הסוכנים מכסה מבנים, תמונות, עיצובים, רינדורים, אומדנים, אלבומים וארנק ה-API. הגדרות החשבון, ההתחברות והתשלום משנה אדם שמחובר באפליקציה.לא
403AGENT_PURCHASE_NOT_ALLOWEDהמפתח הזה הונפק בלי הרשאה לקנות קרדיטים.לא
403AGENT_PURCHASE_EXCEEDS_CAPהרכישה תוציא את המפתח מעבר לתקרת ההוצאה שלו.לא
409IDEMPOTENCY_IN_PROGRESSהקריאה הראשונה עם ‏Idempotency-Key זה עדיין לא השיבה. המתינו ושלחו את אותה קריאה שוב.כן
422הבקשה הובנה ונדחתה: שם מבנה כפול, תצלום שנדחה, אלבום שהוזמן לפני שהרינדור הראשי הסתיים.לא
422IDEMPOTENCY_KEY_REQUIREDקריאה בתשלום עם מפתח API ללא כותרת ‏Idempotency-Key. דבר לא נכנס לתור; שלחו אותה שוב עם הכותרת.לא
422IDEMPOTENCY_KEY_REUSEDIdempotency-Key זה שימש לבקשה אחרת. השתמשו בערך חדש עבור הזמנה חדשה.לא
429המכסה של המפתח הזה אזלה. המתינו, אל תנסו שוב בלולאה צפופה.כן

את הטקסט הקריא כותב ה-API, בשפת הקורא. הציגו את errors[].detail כפי שהוא במקום לנסח הודעה משלכם.

חיוב וקבלה

  • קריאות בתשלום נמשכות מקרדיטים של היקף api, והכניסה בוחנת רק את היתרה הזו: כל מפתח משלם בקרדיטים.
  • Pro Plan פעיל ממלא את ארנק ה-api עד 1,000 קרדיטים פעם בכל תקופת חיוב. מעבר לכך קונים קרדיטים.
  • מפתח ממלא את הארנק שלו רק אם הונפק עם הרשאת רכישה, ולכל היותר בגובה מה שעוד מותר לו להוציא, ולכן רכישה לעולם אינה מעלה את תקרת ההוצאה.
  • תחום api הוא ארנק נפרד. את הקרדיטים של האפליקציה, לרבות השכבה החינמית, מפתח לעולם אינו מוציא.
  • ההוצאה נספרת לכל מפתח בנפרד, כך שהצריכה של כל עוזר נראית לחוד.
  • בדיקה מקדימה היא GET /tokens/balance, השדה data.attributes.agent.is_admissible. הבלוק מופיע רק במפתחות סוכן, והדגל משקף במדויק את שכבת הקבלה. קראו אותו במקום להשוות בעצמכם יתרה מול תקרה.
  • הקבלה נקבעת לפני שעבודה נכנסת לתור, ולכן קריאה שנדחתה אינה עולה דבר.

אסימוני צבע ומותג

start_design מקבל שתי רשימות בלתי תלויות, עד עשרה פריטים בכל אחת. הסדר נושא את תפקיד 60/30/10: הפריט הראשון הוא צבע הקירות הדומיננטי.

colors

אסימוןמשמעות
palette:1מערך צבעים מוכן של GetFacade, לפי מזהה.
#8A8F7Dצבע חופשי, שש ספרות הקסדצימליות.
paint:412גוון של יצרן, בתבנית בת שני מקטעים שנשמרה לצורכי תאימות.

brand_selections

אסימוןמשמעות
siding:brand:12כל מוצר של אותו יצרן בקטגוריה הזאת.
siding:line:40@double-4-dutchlapקו מוצרים אחד, בגיאומטריה אחת.
siding:product:88@double-4-dutchlapמוצר אחד, מוגדר במלואו.
paint:brand:3כל גוון של מותג הצבע הזה.
paint:product:412גוון צבע יחיד.

הדקדוק הוא category:level:id[@value][.value]. החלק שאחרי @ נושא מזהי ערכי גיאומטריה, ייחודיים בתוך הקטגוריה שלהם, ולכן הציר שאליו הם שייכים נמצא בחיפוש ולא נכתב באסימון. אסימון לא מוכר נדחה עם 422 ולעולם אינו מנוטרל בשקט.

מפגש מקצה לקצה

מבנה אחד, תצלום אחד, עיצוב אחד ואז שני המסמכים. ההנחיה שמייצרת את זה:

צור מבנה בשם Maple Street 14, העלה את ./front.jpg כתצוגה שלו, והתחל עיצוב עם קירות אפורים חמים ומסגרות לבנות. הזמן את האומדן והאלבום עבור התוצאה.
מפגש 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)

חומרים