واجهة GetFacade البرمجية للوكلاء
تصميم الواجهات عبر MCP وHTTP. كل تصميم يُعَدّ للبلد الذي يقوم فيه المبنى: المواد القابلة للتطبيق هناك، والمنتجات التي تبيعها الشركات المصنّعة هناك فعلاً، وبنية الطبقات التقنية خلف السطح. يعرضه الريندر على صورة المنزل، ويحسبه تقدير التكلفة بنداً بنداً، ويوثّقه ألبوم PDF للفريق الذي سينفّذه. كل مسار أدناه هو نقطة نهاية قائمة في GetFacade، ذاتها التي تستدعيها تطبيقات iOS وAndroid والويب. مفتاح الوكيل يضيّق فقط من يحق له الاستدعاء، ويقيس الإنفاق، ويتوقف عند سقفه.
- العنوان الأساسي
- https://api.getfacade.ai/api/v1
- المصادقة
- Bearer <agent key>
- الحزمة
- @getfacade/mcp
- بيئة التشغيل
- Node.js 20+
- النقل
- stdio (MCP), HTTPS (REST)
- المواصفة
- OpenAPI 3.1, v1.0.0
بداية سريعة
أصدر مفتاحًا
app.getfacade.aiالحسابالإعداداتAPIإنشاء مفتاح
تظهر القيمة مرة واحدة ولا يمكن استرجاعها، بل استبدالها فقط. يُحدَّد سقف الإنفاق عند الإصدار ويُطبَّق في كل استدعاء مدفوع.
إصدار مفتاح وكيلسجّل خادم MCP
مدخل واحد في إعدادات العميل، ثم إعادة تشغيل العميل. يحفظه Claude Desktop في claude_desktop_config.json، وكل عميل MCP آخر يقبل الحقول الثلاثة نفسها.
{ "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أو استدعِ واجهة HTTP مباشرة
يعمل المفتاح نفسه كرمز Bearer. الطلبات والردود مستندات JSON:API، وفيها id حقل من المستوى الأعلى ولا يقع أبدًا داخل 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"}}}'
الأدوات
إحدى وعشرون أداة. لا يحتفظ خادم MCP بحالة ولا بقواعد خاصة به: كل أداة هي استدعاء واحد أو أكثر لنقاط النهاية المذكورة بجوارها، وكل رسالة ينقلها الوكيل تكتبها الواجهة البرمجية.
create_buildingcreate_building(name, goals?, construction_region?) -> { building_id, name }ينشئ مبنى. الاسم فريد داخل الحساب وبحد أقصى 50 حرفًا؛ ويُرفض التكرار برمز 422.
يستدعي
POST /projectsupload_photoupload_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}/validationstart_designغير متزامنةstart_design(building_id, view_id, prompt?, style_ids?, colors?, brand_selections?, render_effort?, seed?) -> { design_id, job_id, status, seed }يصمّم الواجهة على زاوية مختارة ويعرضها على الصورة: مواد قابلة للتطبيق في بلد المبنى، ومنتجات تُباع هناك فعلاً، وبنية الطبقات خلف السطح. ينشئ تصميماً، ويضع العمل في الطابور، ويعيد معرّف المهمة. البذرة اختيارية: عند إغفالها يولّدها الخادم ويعيدها.
يستدعي
POST /projects/{project}/concepts → POST /concepts/{concept}/angles/{conceptAngle}/rendersrefine_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_jobget_job(job_id, kind: "render" | "album" | "estimate" = "render") -> { status, expected_seconds?, result_url?, error?, error_code? }يقرأ حالة تصيير أو تقدير أو ألبوم واحد.
يستدعي
GET /renders/{render} · GET /estimates/{estimate}list_jobslist_jobs(kind?, limit? = 20) -> [{ job_id, kind, status, building_id, created_at }]أحدث المهام على مستوى الحساب، غير المكتملة أولًا.
يستدعي
GET /historylist_designslist_designs(building_id) -> [{ design_id, note, has_main_render, main_render_id, main_render_url, renders }]تصاميم المبنى مع تصييراتها. من هنا تأتي معرّفات التصيير اللازمة للتقدير والألبوم.
يستدعي
GET /projects/{project}/conceptsorder_estimateغير متزامنةorder_estimate(design_id, render_ids, currency?, measurement_system?, special_requirements?) -> { job_id, status }يسعّر التصميم بنداً بنداً، مواد وأجور عمل، بأسعار المواد المحدّدة في بلد المبنى. العملة ونظام القياس يتبعان ذلك البلد افتراضياً.
يستدعي
POST /projects/{project}/concepts/{concept}/estimatesorder_albumغير متزامنةorder_album(design_id, render_ids, language?, include_blueprints?, include_estimate?, requirements?) -> { job_id, status }يوثّق التصميم للفريق الذي سينفّذه: المواد، وبنية طبقات الواجهة، وملاحظات السلامة، والمعايير التي تستند إليها. يتطلب ريندراً رئيسياً مكتملاً.
يستدعي
POST /concepts/{concept}/album/generateupscale_renderغير متزامنةupscale_render(render_id) -> { job_id, status }يكبّر لقطة مكتملة. يكلّف رصيدًا ويعمل بشكل غير متزامن.
يستدعي
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 }] }التقدير نفسه: الإجماليات والافتراضات التي تقوم عليها وكل سطر بكميته ووحدته وسعره. يبلّغ get_job عن حالة التقدير لا عن محتواه.
يستدعي
GET /estimates/{estimate}add_estimate_lineadd_estimate_line(estimate_id, section, name, quantity, unit_price, unit?, category?) -> { line_id }يضيف سطرًا إلى التقدير. تأتي الوحدات من نظام القياس الخاص بالتقدير نفسه.
يستدعي
POST /estimates/{estimate}/itemsupdate_estimate_lineupdate_estimate_line(estimate_id, line_id, name?, quantity?, unit_price?, unit?, category?, section?) -> { line_id }يعدّل سطرًا في التقدير. تتغيّر الحقول المرسلة فقط، والمجاميع يعيد حسابها الخادم.
يستدعي
PATCH /estimates/{estimate}/items/{item}delete_estimate_linedelete_estimate_line(estimate_id, line_id) -> { deleted }يحذف سطرًا من التقدير.
يستدعي
DELETE /estimates/{estimate}/items/{item}delete_renderdelete_render(render_id) -> { deleted }يحذف لقطة واحدة. حذف اللقطة الرئيسية يعيد تصميمها إلى المسودة.
يستدعي
DELETE /renders/{render}delete_designdelete_design(building_id, design_id) -> { deleted }يحذف تصميمًا مع اللقطات التي تحته.
يستدعي
DELETE /projects/{project}/concepts/{concept}delete_buildingdelete_building(building_id) -> { deleted }يحذف مبنى بكل ما فيه. الرصيد المنفَق لا يُستردّ.
يستدعي
DELETE /projects/{project}list_token_packageslist_token_packages() -> [{ package, tokens, price, currency }]الباقات التي يمكن لهذا الحساب شراؤها، بأسعارها وعدد أرصدتها.
يستدعي
GET /tokens/packagesbuy_tokensغير متزامنةbuy_tokens(package) -> { status, transaction_id, tokens, checkout_url?, detail }يشتري باقة واحدة لمحفظة هذا المفتاح. يتطلّب مفتاحًا صادرًا بصلاحية الشراء، ولا يتجاوز أبدًا ما لا يزال مسموحًا للمفتاح بإنفاقه.
يستدعي
POST /tokens/purchaseget_balanceget_balance() -> { balance, scope: "api", spend_cap, spent, remaining, is_admissible }محفظة الوكيل، وسقف هذا المفتاح، وما إذا كان الاستدعاء المدفوع التالي سيُقبل.
يستدعي
GET /tokens/balancereport_problemreport_problem(message, category?, context?: { tool, endpoint, status_code, job_id, expected, actual }) -> { reference, message }يُبلغ عن خلل في هذه الواجهة البرمجية: حقل موصوف هنا لكنه لا يصل، رفض لا تُفهم منه الخطوة التالية، نتيجة لا تطابق ما طُلب. مجاني ويُقبل على محفظة فارغة، ويعود بمرجع لا برد.
يستدعي
POST /feedback
المصادقة والمفاتيح
- ينتقل المفتاح كرمز Bearer في ترويسة
Authorization. يقرأه خادم MCP منGETFACADE_API_KEYولا يرسل سواه. - تظهر القيمة مرة واحدة عند الإصدار، ولا يُخزَّن منها سوى البصمة. التدوير يعني إصدار مفتاح جديد وإبطال القديم.
- لكل مفتاح سقف إنفاق يُطبَّق على الخادم قبل أن يصل الاستدعاء إلى وحدة التحكم. بلوغ السقف يوقف ذلك المفتاح، لا الحساب.
- المفاتيح لا تدير المفاتيح: هذا إجراء بشري، وتلك النقاط تردّ 403 على مفتاح الوكيل.
- الإبطال يسري فورًا. الاستدعاءات بمفتاح مُبطَل تردّ 401.
العمل غير المتزامن والاستعلام
- تعيد
start_designوorder_estimateوorder_albumمعرّف مهمة ثم تنتهي. يستغرق التصيير دقائق: استعلم عنGET /renders/{render}أوGET /estimates/{estimate}حتى تصبح الحالة نهائية. - يُعلَن انتهاء فحص الصورة عبر مقبس ويب لا يملكه الوكيل. استعلم عن
GET /angles/{angle}/validationواقرأvalidation.is_in_progress؛ ولا تستنتج النهائية بنفسك من نص الحالة. - الريندر المكتمل والألبوم المكتمل موجودان على عناوين عامة دائمة: بلا توقيع وبلا انتهاء صلاحية. يمكن تسليم الرابط إلى شخص مباشرةً، وهذا هو الجواب على «أرِني النتيجة». ولأنه غير موقّع فهو لا يستأذن أحداً: يظل يعمل لدى كل من يصله، ولا يمكن سحبه لاحقاً.
GET /renders/{render}/downloadشيء آخر: رابط موقّع تنتهي صلاحيته خلال دقائق ويحمل اسم ملف. وظيفته حفظ الملف، لا مشاركته.
حدود المعدل لكل مفتاح
لمفتاح الوكيل حصص خاصة به، منفصلة عن الجلسات البشرية للحساب نفسه، حتى لا يلتهم وكيل عالق في حلقة حصة الشخص الجالس أمام الشاشة. الرفض رخيص: يُتخذ في الطبقة الوسيطة قبل أي عمل على قاعدة البيانات.
| النطاق | في الدقيقة | في الساعة |
|---|---|---|
| القراءات والكتابات المعتادة | 120 | 2000 |
| استعلامات الحالة والفحص | 120 | 2000 |
| طلبات التصيير والتقدير والألبوم | 10 | 200 |
خاصية عدم التكرار
النداء المدفوع يُنشئ مهمة، والرسوم تتبع المهمة. تسمية النداء هي ما يجعل إعادته تُرجع المهمة نفسها بدل إنشاء مهمة ثانية.
- ترويسة Idempotency-Key مطلوبة في كل نداء مدفوع يُجرى بمفتاح API: بدء تصميم أو تحسينه، تكبير صورة، طلب تقدير تكلفة أو ألبوم، إعادة توليد تقدير. بدونها يردّ النداء بـ 422
IDEMPOTENCY_KEY_REQUIREDولا يدخل شيء إلى الطابور. - أي قيمة بطول 8 إلى 191 حرفًا، واحدة لكل طلب، والمعتاد هو UUID. الطلب الجديد يأخذ قيمة جديدة: نداءان متطابقان بقيمتين هما تصميمان.
- إعادة النداء بالقيمة نفسها والجسم نفسه تُرجع الحالة والجسم الأصليين، مع
Idempotent-Replay: trueفي الاستجابة. لا يدخل شيء إلى الطابور ولا يُحتسب أي مبلغ مرتين. - القيمة نفسها بجسم مختلف تردّ بـ 422
IDEMPOTENCY_KEY_REUSED. والإعادة التي تصل بينما النداء الأول ما زال يعمل تردّ بـ 409IDEMPOTENCY_IN_PROGRESS: انتظر ثم أرسل النداء نفسه مرة أخرى. - أي استجابة 4xx تحرّر القيمة، فيمكن إرسالها من جديد بعد معالجة السبب. تُحفظ القيم 24 ساعة، لكل حساب.
-
@getfacade/mcpينشئ القيمة ويعيد النداء بها من تلقاء نفسه، فلا شيء يُمرَّر في نداء الأداة.
الأخطاء
تصل الإخفاقات كمستندات أخطاء بصيغة JSON:API. ردود التحقق في Laravel ليست بهذه الصيغة وتحمل نصها في الحقل message.
| الحالة | الرمز | المعنى | قابل للإعادة |
|---|---|---|---|
401 | — | المفتاح مفقود أو مُبطَل أو منتهي الصلاحية. | لا |
402 | AGENT_CREDITS_EXHAUSTED | لم يعد في الحساب رصيد في نطاق api. | لا |
402 | AGENT_KEY_CAP_REACHED | استنفد هذا المفتاح سقفه. أصدر مفتاحًا آخر أو ارفع السقف. | لا |
403 | — | نقطة النهاية هذه غير متاحة لمفاتيح واجهة البرمجة. تشمل واجهة الوكلاء المباني والصور والتصاميم وصور العرض والتقديرات والألبومات ومحفظة الواجهة. أما إعدادات الحساب وتسجيل الدخول والدفع فيغيّرها شخص مسجَّل الدخول في التطبيق. | لا |
403 | AGENT_PURCHASE_NOT_ALLOWED | أُصدر هذا المفتاح دون صلاحية شراء الرصيد. | لا |
403 | AGENT_PURCHASE_EXCEEDS_CAP | هذه العملية ستتجاوز سقف إنفاق المفتاح. | لا |
409 | IDEMPOTENCY_IN_PROGRESS | لم يستجب بعد أول نداء يحمل Idempotency-Key هذا. انتظر ثم أرسل النداء نفسه مرة أخرى. | نعم |
422 | — | فُهم الطلب ورُفض: اسم مبنى مكرر، أو صورة مرفوضة، أو ألبوم طُلب قبل اكتمال التصيير الرئيسي. | لا |
422 | IDEMPOTENCY_KEY_REQUIRED | نداء مدفوع بمفتاح API بلا ترويسة Idempotency-Key. لم يدخل شيء إلى الطابور؛ أعد إرساله مع الترويسة. | لا |
422 | IDEMPOTENCY_KEY_REUSED | استُخدم Idempotency-Key هذا في طلب آخر. استخدم قيمة جديدة لطلب جديد. | لا |
429 | — | نفدت الحصة الخاصة بهذا المفتاح. تمهّل، ولا تُعد المحاولة في حلقة ضيقة. | نعم |
النص المقروء تكتبه الواجهة البرمجية بلغة المُستدعي. اعرض errors[].detail كما هو بدل صياغة رسالة خاصة بك.
الدفع والقبول
- تُخصم المكالمات المدفوعة من أرصدة نطاق
api، ولا ينظر القبول إلا إلى هذا الرصيد: كل مفتاح يدفع بالأرصدة. - يملأ اشتراك Pro Plan النشط محفظة
apiحتى 1000 رصيد مرة واحدة في كل دورة فوترة. وبعد ذلك تُشترى الأرصدة. - لا يعبّئ المفتاح محفظته إلا إذا صدر بصلاحية الشراء، وبما لا يتجاوز ما لا يزال مسموحًا له بإنفاقه، فالشراء لا يرفع سقف الإنفاق أبدًا.
- نطاق
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 كمنظور له، وابدأ تصميمًا بجدران رمادية دافئة وإطارات بيضاء. اطلب التقدير والألبوم للنتيجة.
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)