Агентный API GetFacade
Проектирование фасада через MCP и HTTP. Каждый дизайн прорабатывается под страну, где стоит дом: материалы, применимые там, продукты производителей, которые там действительно продаются, и технический пирог отделки за поверхностью. Рендер показывает это на фотографии дома, смета считает построчно, а PDF-альбом документирует для бригады, которая будет строить. Каждый путь ниже это существующий эндпоинт GetFacade, тот же самый, что вызывают приложения iOS, Android и веб. Агентный ключ лишь сужает круг вызывающих, считает расход и останавливается на своём потолке.
- Базовый URL
- 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-API напрямую
Тот же ключ работает как токен 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-сервер не хранит состояния и не имеет своих правил: каждый инструмент — это один или несколько вызовов перечисленных рядом эндпоинтов, а любое сообщение, которое повторяет агент, написано API.
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? } }Регистрирует ракурс, загружает байты по подписанному URL, подтверждает их и опрашивает статус, пока фотография не будет принята или отклонена. Ширина, высота и 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 }Проектирует фасад на выбранном ракурсе и показывает его на фотографии: материалы, применимые в стране объекта, продукты, которые там действительно продаются, и пирог отделки за поверхностью. Создаёт дизайн, ставит работу в очередь и возвращает идентификатор задания. 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 }Сообщает о неисправности этого API: поле, описанное здесь и не приходящее в ответе, отказ, из формулировки которого не следует следующий шаг, результат, не соответствующий запросу. Бесплатно и принимается при пустом кошельке; в ответ приходит номер обращения, а не ответ.
Вызывает
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это другое: подписанный URL, который истекает за минуты и несёт имя файла. Он нужен, чтобы сохранить файл, а не чтобы поделиться им.
Лимиты частоты на ключ
У агентного ключа свои корзины лимитов, отдельные от человеческих сессий того же аккаунта, поэтому зациклившийся агент не съест лимит того, кто сидит за экраном. Отказ обходится дёшево: он выносится в middleware, до любой работы с базой.
| Область | В минуту | В час |
|---|---|---|
| Чтение и обычная запись | 120 | 2000 |
| Опрос статусов и валидации | 120 | 2000 |
| Заказ рендеров, смет и альбомов | 10 | 200 |
Идемпотентность
Платный вызов создаёт задачу, и списание идёт за задачей. Имя вызова — это то, что позволяет повтору вернуть ту же задачу вместо создания второй.
Idempotency-Keyобязателен для каждого платного вызова с API-ключом: создание и доработка дизайна, увеличение рендера, заказ сметы или альбома, перегенерация сметы. Без него вызов отвечает 422IDEMPOTENCY_KEY_REQUIRED, и в очередь ничего не ставится.- Любое значение длиной от 8 до 191 символа, по одному на заказ; обычно берут UUID. Новый заказ — новое значение: два одинаковых вызова под двумя значениями это два дизайна.
- Повтор вызова с тем же значением и тем же телом возвращает исходный статус и тело, с заголовком
Idempotent-Replay: true. В очередь ничего не ставится и второй раз ничего не списывается. - То же значение с другим телом отвечает 422
IDEMPOTENCY_KEY_REUSED. Повтор, пришедший пока первый вызов ещё выполняется, отвечает 409IDEMPOTENCY_IN_PROGRESS: подождите и отправьте тот же вызов снова. - Любой ответ 4xx освобождает значение, так что его можно отправить снова, когда причина устранена. Значения помнятся 24 часа, в пределах аккаунта.
@getfacade/mcpсам создаёт значение и сам повторяет вызов под ним, так что в вызове инструмента передавать нечего.
Ошибки
Отказы приходят документами ошибок JSON:API. Ответы валидации Laravel не имеют формы JSON:API и несут текст в поле message.
| Статус | Код | Значение | Повтор |
|---|---|---|---|
401 | — | Ключ отсутствует, отозван или истёк. | Нет |
402 | AGENT_CREDITS_EXHAUSTED | На аккаунте не осталось кредитов скоупа api. | Нет |
402 | AGENT_KEY_CAP_REACHED | Ключ израсходовал свой потолок. Выпустите другой ключ или поднимите потолок. | Нет |
403 | — | Этот эндпоинт недоступен по API-ключу. Агентный API охватывает объекты, фотографии, дизайны, рендеры, сметы, альбомы и кошелёк API. Настройки аккаунта, входа и оплаты меняет человек, вошедший в приложение. | Нет |
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 | — | Исчерпана собственная корзина лимитов этого ключа. Сделайте паузу, не повторяйте в плотном цикле. | Да |
Человекочитаемый текст пишет API, на языке вызывающего. Показывайте errors[].detail как есть, не составляя собственное сообщение.
Оплата и допуск
- Платные вызовы идут из кредитов скоупа
api, и допуск смотрит только на этот баланс: каждый ключ платит кредитами. - Активный Pro Plan раз в биллинг-период доводит кошелёк
apiдо 1000 кредитов. Дальше кредиты покупаются. - Ключ пополняет свой кошелёк, только если выпущен с разрешением на покупку, и не больше того, что ему ещё можно потратить, поэтому покупка не поднимает потолок расхода.
- Скоуп
apiэто отдельный кошелёк. Кредиты приложения, включая бесплатный тариф, ключом не расходуются никогда. - Расход считается по каждому ключу, поэтому потребление каждого ассистента видно отдельно.
- Предполётная проверка это
GET /tokens/balance, полеdata.attributes.agent.is_admissible. Блок присутствует только у агентских ключей, а флаг в точности повторяет middleware допуска. Читайте его вместо сравнения баланса с потолком. - Допуск решается до постановки работы в очередь, поэтому отклонённый вызов ничего не расходует.
Цветовые и брендовые токены
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 и никогда не игнорируется молча.
Сквозная сессия
Один объект, одна фотография, один дизайн и затем два документа. Запрос, который это порождает:
Создай объект «Кленовая 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)