Документация по API генерации плана этажа#
Базовый URL:
https://api.ideal.house
Версия: v1
Обновлено: 2026-08-09
📖 Обзор#
API генерации плана этажа создаёт с помощью ИИ один концептуальный план жилого помещения: чёрно-белый вид сверху в стиле CAD. Основа — структурированные требования к помещениям и необязательный пользовательский запрос или изображение-образец.
Результат предназначен для предварительной проработки планировки. Это не строительный чертёж: размеры, геометрию, размещение оборудования и соответствие нормам должен проверить квалифицированный специалист.
Рабочий процесс является асинхронным:
- Создание задачи — Отправьте параметры плана этажа и получите
taskId. - Опрос результатов — Регулярно обращайтесь к конечной точке получения результата с
taskId, пока задача не перейдёт в конечное состояние.
🔐 Аутентификация#
Все публичные запросы API должны включать ключ API.
| Заголовок | Обязательный | Значение |
|---|---|---|
APIKEY | ✅ Да | Ваш ключ API |
Content-Type | ✅ Да для POST | application/json |
[!WARNING] Держите ваш ключ API в безопасности. Не раскрывайте его в клиентском коде или публичных репозиториях.
💰 Списание кредитов#
Кредиты списываются после успешного создания задачи генерации. Если задача в итоге завершится ошибкой, списанные кредиты автоматически возвращаются. При недостатке кредитов возвращается код ошибки 9051.
Модель (modelType) | Размер вывода | Кредиты |
|---|---|---|
Base | 1536 × 1024 | 10 |
Pro | 2496 × 1664 | 20 |
Flash не поддерживается в API генерации плана этажа.
Общие правила оплаты приведены в Справочнике по списанию кредитов.
📌 Конечные точки API#
1. Создание задачи генерации плана этажа#
Создает задачу генерации плана этажа и возвращает уникальный идентификатор задачи.
Конечная точка
POST /api/v1/floorPlan/generate
Заголовки запроса
| Заголовок | Обязательный | Описание |
|---|---|---|
APIKEY | ✅ Да | Ключ аутентификации API |
Content-Type | ✅ Да | Должен быть application/json |
Тело запроса#
| Поле | Тип | Обязательное | Описание | По умолчанию |
|---|---|---|---|---|
bedrooms | integer | ❌ Нет | Количество спален от 0 до 5 | 2 |
bathrooms | number | ❌ Нет | Общее количество ванных комнат от 0.5 до 4, с шагом 0.5 | 1.5 |
totalArea | string | ✅ Да | Положительная целевая общая площадь с единицей m² или ft², например 220 m² или 1386 ft² | — |
bedroomAreaRanges | array<object> | ❌ Нет | Необязательные рекомендации по размерам спален. См. Диапазоны площади спален | Выводится из totalArea при отсутствии |
bathroomDetails | object | ❌ Нет | Предпочтения только для полноценных ванных комнат. См. Детали ванных комнат | — |
kitchenDetails | object | ❌ Нет | Необязательная конфигурация кухни. См. Детали кухни | — |
keyRooms | array<string> | ❌ Нет | Дополнительные помещения или пространства. См. Ключевые помещения | [] |
prompt | string | ❌ Нет | Дополнительные пожелания по планировке. Они не могут изменить количество помещений, заданное структурированными полями, или обязательные визуальные ограничения | "" |
refImageUrl | string | ❌ Нет | Публично доступный URL референс-изображения | "" |
modelType | string | ❌ Нет | Перечисление: Base, Pro | Base |
[!IMPORTANT] Публичный API в настоящее время валидирует
bedroomsкак0–5иbathroomsкак0.5–4. Значения, доступные в другом клиентском интерфейсе, не расширяют эти серверные ограничения.
Общие правила запроса#
- Все значения перечислений чувствительны к регистру и должны использовать английские значения, показанные в этом документе.
totalArea— целевая общая площадь, которая задаёт масштаб и пропорции, а не точный строительный размер.- При формировании структурированного запроса на генерацию изображения учитываются только первые 800 символов пользовательского запроса.
- Структурированные поля имеют приоритет над противоречащими инструкциями в
prompt. - Успешная задача генерирует ровно одно изображение.
📐 Общая площадь#
totalArea содержит одно положительное числовое значение, за которым следует единица площади.
| Единица | Пример |
|---|---|
m² | 220 m² |
ft² | 1386 ft² |
Пробел перед единицей рекомендуется. Дробные значения принимаются, если они положительные.
Допустимые примеры:
{
"totalArea": "200 m²"
}
{
"totalArea": "1850 ft²"
}
🛏️ Диапазоны площади спален#
bedroomAreaRanges задаёт относительные размеры спален. Этот параметр не требует добавлять на изображение числовые подписи площадей.
Каждый элемент имеет следующую структуру:
| Поле | Тип | Обязательный | Описание |
|---|---|---|---|
name | string | ❌ Нет | Идентификатор спальни, например Room 1 (Master) или Room 2 |
minArea | string | ❌ Нет | Положительная минимальная площадь |
maxArea | string | ❌ Нет | Положительная максимальная площадь; не может быть меньше minArea |
unit | string | ❌ Нет | Перечисление: m², ft²; используйте ту же единицу, что и в totalArea |
Пример явного диапазона
{
"bedroomAreaRanges": [
{
"name": "Room 1 (Master)",
"minArea": "30",
"maxArea": "40",
"unit": "m²"
},
{
"name": "Room 2",
"minArea": "20",
"maxArea": "30",
"unit": "m²"
}
]
}
Правила при предоставлении непустого массива:
- Его длина должна быть равна
bedrooms. - Каждое предоставленное
minAreaиmaxAreaдолжно быть положительной числовой строкой. - Если предоставлены оба значения,
minArea <= maxArea. unit, если предоставлено, должно бытьm²илиft².- Имена сохраняются. Пустые или null-элементы не предоставляют рекомендаций по размерам.
Автоматические диапазоны при отсутствии#
Поле можно не передавать или отправить пустой массив. Если ни один элемент не содержит действующего значения minArea или maxArea, при структурированной генерации внутренние диапазоны площадей спален рассчитываются по totalArea и bedrooms:
- Для одной спальни отводится 20% общей площади.
- На каждую дополнительную спальню выделяемая доля увеличивается на 7.5 процентных пунктов, но не превышает 50%.
- При распределении площади первая спальня получает вес
1.3, а каждая из остальных — вес1.0. - Вокруг каждого целевого значения задаётся приблизительный диапазон
±10%с округлением до целых единиц площади. - Единица наследуется из
totalArea. - Существующие непустые имена помещений сохраняются; в противном случае сервер использует
Room 1,Room 2и т. д.
Для 200 m² и 4 спален текущий расчёт даёт примерно следующие ориентиры:
[
{ "name": "Room 1", "minArea": "23", "maxArea": "28", "unit": "m²" },
{ "name": "Room 2", "minArea": "18", "maxArea": "22", "unit": "m²" },
{ "name": "Room 3", "minArea": "18", "maxArea": "22", "unit": "m²" },
{ "name": "Room 4", "minArea": "18", "maxArea": "22", "unit": "m²" }
]
Эти значения являются внутренними пропорциональными рекомендациями, а не гарантированными конечными площадями помещений. Явные допустимые диапазоны всегда имеют приоритет над автоматическими диапазонами.
Если bedrooms равно 0, опустите bedroomAreaRanges или отправьте [].
🛁 Детали ванных комнат#
bathrooms представляет общее количество ванных комнат:
- Его целая часть — это количество полноценных ванных комнат.
- Дробная часть
.5добавляет один санузел без душа и ванны. - В каждой полноценной ванной комнате предполагается наличие унитаза, умывальника/раковины и душа или мокрой зоны.
- Санузел без душа и ванны содержит только унитаз и тумбу с раковиной/раковину.
bathroomDetails настраивает только полноценные ванные комнаты:
{
"bathroomDetails": {
"fullBathroomOptions": [
{
"name": "Bathroom 1",
"wetDrySeparation": "yes",
"bathtub": "required"
},
{
"name": "Bathroom 2",
"wetDrySeparation": "no",
"bathtub": "optional"
}
]
}
}
| Поле | Тип | Допустимые значения | Описание |
|---|---|---|---|
name | string | Bathroom 1, Bathroom 2 и т. д. | Необязательный отображаемый идентификатор |
wetDrySeparation | string / null | yes, no, null | Показывать ли выделенную мокрую зону |
bathtub | string / null | no, optional, required, null | Предпочтение по ванне |
Правила:
fullBathroomOptions.lengthне может превышатьfloor(bathrooms).- Массив может содержать только те полноценные ванные комнаты, для которых выбраны предпочтения.
- Значение
nullозначает, что не указано. - Обязательная ванна является дополнительной к стандартным сантехническим приборам полноценной ванной комнаты; она не заменяет унитаз или душ.
- Разделение сухой и мокрой зон означает перегородку внутри уже учтённого санузла, а не дополнительный санузел.
🍳 Детали кухни#
Все дочерние поля kitchenDetails являются необязательными. Опустите весь объект, если не выбрано предпочтение по кухне.
{
"kitchenDetails": {
"type": "open",
"size": "standard",
"layout": "U",
"islandType": "preparation",
"storage": "maximum",
"features": ["breakfast nook", "pantry"]
}
}
| Поле | Тип | Допустимые значения |
|---|---|---|
type | string | open, semi-open, closed |
size | string | small, standard, large, extra large |
layout | string | I, L, U, gallery |
islandType | string | no, preparation, cooking, entertainment |
storage | string | minimal, standard, maximum |
features | array<string> | eating bar, breakfast nook, pantry |
Частичная конфигурация допустима. Например:
{
"kitchenDetails": {
"type": "semi-open"
}
}
🚪 Ключевые помещения#
keyRooms принимает массив этих точных значений:
| Значение | Описание |
|---|---|
walk-in closet | Выделенная гардеробная, соединенная с зоной спальни |
laundry room | Выделенное прачечное помещение |
storage room | Общее кладовое помещение |
utility room | Помещение для инженерного оборудования или хозяйственных нужд |
home office | Выделенный офис или кабинет |
garage | Гараж с внешним въездом для транспорта и внутренним доступом в дом |
pantry | Кладовая, примыкающая к кухне |
combined living-dining | Одна общая зона гостиной и столовой |
balcony | Внешний балкон, соединенный с гостиной или главной спальней |
Устаревшее значение веб-приложения balcon также принимается и приводится к balcony.
Правила:
- Пустые значения игнорируются, а дублирующиеся значения удаляются.
- Выбранные ключевые помещения запрашиваются один раз.
- Не выбранные пользователем необязательные помещения исключаются из состава генерируемой планировки.
- Если
pantryвстречается как вkitchenDetails.features, так и вkeyRooms, запрашивается только одна кладовая.
Пример:
{
"keyRooms": [
"garage",
"home office",
"combined living-dining"
]
}
🖼️ Референс-изображение#
refImageUrl необязателен; изображение по этому адресу должно быть напрямую доступно серверу API.
Требования:
- Формат: JPG/JPEG, PNG или WebP.
- Максимальный размер файла: 20 МБ.
- Минимальные размеры: 128 × 128 px.
- Максимальные размеры: 6,000 × 6,000 px. Более крупные изображения масштабируются пропорционально перед обработкой.
Изображение-образец задаёт ориентиры для планировки, взаимного расположения помещений, пропорций и визуального стиля. Оно не меняет количество помещений, заданное структурированными полями, и другие обязательные ограничения.
🤖 Типы моделей#
| Значение | Описание |
|---|---|
Base | По умолчанию. Сбалансированное качество генерации, вывод 1536 × 1024 |
Pro | Вывод с более высоким разрешением 2496 × 1664 с более длительным ожидаемым временем генерации |
Поддерживаются только Base и Pro.
Поля, не входящие в публичную спецификацию#
Следующими полями не следует пользоваться публичным клиентам API:
| Поле | Примечания |
|---|---|
imageNumbers | Текущий генератор всегда возвращает одно изображение; это поле не требуется |
extData | Внутренние метаданные веб-приложения для отслеживания групп задач; клиенты публичного API должны опускать это поле |
isApiCall | Определяется конечной точкой API, а не телом запроса |
genByMember | Внутренние метаданные генерации, а не поле запроса плана этажа |
Удаленные устаревшие поля, которые не следует отправлять:
floorplanSetting
roomCounts
grossArea
totalAreaValue
totalAreaUnit
totalAreaType
fullBathrooms
halfBathrooms
halfBathroomRequirement
kitchenType
diningRooms
livingRooms
extras
referenceImage
hasDetailOptions
📥 Примеры создания задачи#
Минимальный запрос с автоматическими диапазонами спален#
curl -X POST "https://api.ideal.house/api/v1/floorPlan/generate" \
-H "APIKEY: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"modelType": "Pro",
"prompt": "Upper floor of a two-story Saudi Arabian villa with a master bedroom, family living area, staircase landing, and balcony"
}'
Полный запрос#
cURL
curl -X POST "https://api.ideal.house/api/v1/floorPlan/generate" \
-H "APIKEY: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"bedrooms": 3,
"bathrooms": 2.5,
"totalArea": "220 m²",
"bedroomAreaRanges": [
{"name": "Room 1 (Master)", "minArea": "30", "maxArea": "40", "unit": "m²"},
{"name": "Room 2", "minArea": "20", "maxArea": "30", "unit": "m²"},
{"name": "Room 3", "minArea": "20", "maxArea": "30", "unit": "m²"}
],
"bathroomDetails": {
"fullBathroomOptions": [
{"name": "Bathroom 1", "wetDrySeparation": "yes", "bathtub": "required"},
{"name": "Bathroom 2", "wetDrySeparation": "no", "bathtub": "optional"}
]
},
"kitchenDetails": {
"type": "open",
"size": "standard",
"layout": "U",
"islandType": "preparation",
"storage": "maximum",
"features": ["breakfast nook", "pantry"]
},
"keyRooms": ["garage", "home office", "combined living-dining"],
"prompt": "Bright modern home with good natural lighting",
"refImageUrl": "https://example.com/reference-plan.png",
"modelType": "Pro"
}'
Java (OkHttp)
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class FloorPlanApiExample {
private static final String BASE_URL = "https://api.ideal.house";
private static final String API_KEY = "your_api_key_here";
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient();
String json = """
{
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"keyRooms": ["walk-in closet", "balcony"],
"prompt": "Upper floor with a master bedroom and family living area",
"modelType": "Pro"
}
""";
Request request = new Request.Builder()
.url(BASE_URL + "/api/v1/floorPlan/generate")
.addHeader("APIKEY", API_KEY)
.addHeader("Content-Type", "application/json")
.post(RequestBody.create(json, MediaType.parse("application/json")))
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println(response.body().string());
}
}
}
Python (requests)
import requests
BASE_URL = "https://api.ideal.house"
API_KEY = "your_api_key_here"
payload = {
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"keyRooms": ["walk-in closet", "balcony"],
"prompt": "Upper floor with a master bedroom and family living area",
"modelType": "Pro",
}
response = requests.post(
f"{BASE_URL}/api/v1/floorPlan/generate",
headers={"APIKEY": API_KEY, "Content-Type": "application/json"},
json=payload,
)
response.raise_for_status()
print("Task ID:", response.json()["data"])
Node.js (axios)
const axios = require('axios');
const BASE_URL = 'https://api.ideal.house';
const API_KEY = 'your_api_key_here';
async function createFloorPlanTask() {
const response = await axios.post(
`${BASE_URL}/api/v1/floorPlan/generate`,
{
bedrooms: 4,
bathrooms: 2,
totalArea: '200 m²',
keyRooms: ['walk-in closet', 'balcony'],
prompt: 'Upper floor with a master bedroom and family living area',
modelType: 'Pro'
},
{
headers: {
APIKEY: API_KEY,
'Content-Type': 'application/json'
}
}
);
console.log('Task ID:', response.data.data);
return response.data.data;
}
createFloorPlanTask();
Ответ об успешном создании задачи#
{
"code": 0,
"message": "success",
"data": 1234567890123456789
}
| Поле | Тип | Описание |
|---|---|---|
code | integer | 0 указывает, что задача была успешно создана |
message | string | Сообщение в ответе |
data | long | Идентификатор задачи, используемый для опроса конечной точки результатов |
2. Получение результата задачи#
Возвращает прогресс задачи и сгенерированное изображение, если оно доступно.
Конечная точка
GET /api/v1/floorPlan/result?taskId={taskId}
Заголовки запроса
| Заголовок | Обязательный | Описание |
|---|---|---|
APIKEY | ✅ Да | Ключ аутентификации API |
Параметры запроса
| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
taskId | long | ✅ Обязательно | Идентификатор задачи, возвращенный конечной точкой создания |
Примеры запросов результатов#
cURL
curl -X GET "https://api.ideal.house/api/v1/floorPlan/result?taskId=1234567890123456789" \
-H "APIKEY: your_api_key_here"
Опрос с помощью Python
import time
import requests
BASE_URL = "https://api.ideal.house"
API_KEY = "your_api_key_here"
task_id = 1234567890123456789
while True:
response = requests.get(
f"{BASE_URL}/api/v1/floorPlan/result",
headers={"APIKEY": API_KEY},
params={"taskId": task_id},
)
response.raise_for_status()
task = response.json()["data"]
print(task["status"], task["percentage"], task["waitNumber"])
if task["status"] in ("Success", "Failed", "Termination"):
break
time.sleep(3)
if task["status"] == "Success":
print("Result URL:", task["output"]["resultUrl"])
Опрос с помощью Node.js
const axios = require('axios');
const BASE_URL = 'https://api.ideal.house';
const API_KEY = 'your_api_key_here';
async function pollFloorPlanResult(taskId) {
while (true) {
const response = await axios.get(
`${BASE_URL}/api/v1/floorPlan/result`,
{
headers: { APIKEY: API_KEY },
params: { taskId }
}
);
const task = response.data.data;
console.log(task.status, task.percentage, task.waitNumber);
if (['Success', 'Failed', 'Termination'].includes(task.status)) {
if (task.status === 'Success') {
console.log('Result URL:', task.output.resultUrl);
}
return task;
}
await new Promise(resolve => setTimeout(resolve, 3000));
}
}
pollFloorPlanResult('1234567890123456789');
Ответ для завершённой задачи#
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Success",
"waitNumber": 0,
"percentage": 100,
"input": {
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"bedroomAreaRanges": [
{"name": "Room 1", "minArea": "23", "maxArea": "28", "unit": "m²"},
{"name": "Room 2", "minArea": "18", "maxArea": "22", "unit": "m²"},
{"name": "Room 3", "minArea": "18", "maxArea": "22", "unit": "m²"},
{"name": "Room 4", "minArea": "18", "maxArea": "22", "unit": "m²"}
],
"keyRooms": ["walk-in closet", "balcony"],
"prompt": "Upper floor with a master bedroom and family living area",
"modelType": "Pro"
},
"output": {
"resultUrl": "https://cdn.ideal.house/output/floor-plan.jpg",
"width": 2496,
"height": 1664
}
}
}
Ответ в процессе обработки#
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Processing",
"waitNumber": 1,
"percentage": 45,
"input": {
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"modelType": "Pro"
},
"output": null
}
}
Ответ об ошибке задачи#
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Failed",
"waitNumber": 0,
"percentage": 0,
"input": {
"bedrooms": 4,
"bathrooms": 2,
"totalArea": "200 m²",
"modelType": "Pro"
},
"output": null
}
}
Поля результата#
| Поле | Тип | Описание |
|---|---|---|
id | long | Идентификатор задачи |
status | string | Текущий статус задачи |
waitNumber | integer | Количество задач в очереди впереди; 0 означает отсутствие задач в очереди впереди |
percentage | integer | Приблизительный процент завершения от 0 до 100 |
input | object | Нормализованные входные данные задачи, включая автоматически рассчитанные диапазоны площадей спален, когда это применимо |
output | object / null | Сгенерированный результат при успешном завершении задачи; в остальных случаях обычно null |
output.resultUrl | string | Подписанный URL сгенерированного изображения плана этажа |
output.width | integer | Ширина результата в пикселях |
output.height | integer | Высота результата в пикселях |
📊 Статус задачи#
| Статус | Описание |
|---|---|
Unprocessed | Задача создана, но еще не началась |
Processing | Задача обрабатывается |
Success | Задача завершена и output.resultUrl доступно |
Failed | Задача завершилась ошибкой |
Termination | Выполнение задачи было прервано или прекращено |
Опрашивайте каждые 3–5 секунд. См. Лимит задач API.
❌ Ответы об ошибках#
Все ответы об ошибках используют общую структуру ответа:
{
"code": 1011,
"message": "bedroomAreaRanges size must match bedrooms",
"data": null
}
| Код | Имя | Описание | Рекомендуемое действие |
|---|---|---|---|
1001 | FAILED | Общая ошибка запроса | Проверьте поле message |
1003 | INTERNAL_ERROR | Внутренняя ошибка сервера | Повторите позже; обратитесь в поддержку, если проблема сохраняется |
1011 | PARAM_ERROR | Некорректный параметр запроса | Проверьте количество помещений, единицы измерения, значения перечислений и вложенные массивы |
5002 | API_KEY_INVALID | Недействительный или отсутствующий ключ API | Проверьте заголовок APIKEY |
9010 | SCAN_TEXT_ERROR | Промпт не прошел проверку контента | Измените промпт |
9038 | PROHIBITED_CONTENT | Сгенерированный вывод содержит запрещенный контент | Отрегулируйте входные данные и повторите |
9051 | COINS_NOT_ENOUGH | Недостаточно кредитов | Добавьте кредиты и повторите |
См. Справочник кодов ошибок для полного списка общих ошибок.
🔄 Примечания по интеграции с веб-приложением#
Веб-приложение, требующее входа в аккаунт, и публичный API используют разные конечные точки и способы аутентификации:
| Клиент | Конечная точка | Аутентификация |
|---|---|---|
| Веб-приложение | POST /floorPlan/generate | Заголовок token с токеном входа |
| Публичный API | POST /api/v1/floorPlan/generate | Заголовок APIKEY |
Структуры полей согласованы, но клиенты публичного API должны соблюдать серверные ограничения и публичную спецификацию этого документа. В частности:
- Веб-клиенты могут включать внутренние
imageNumbersиextData; публичные клиенты не нуждаются в них. - Публичный API определяет метаданные вызова API из конечной точки и учетных данных. Поля запроса, такие как
isApiCallиgenByMember, не нужны. balconпринимается для совместимости и нормализуется доbalcony; новые интеграции должны отправлятьbalcony.- Для публичного API по-прежнему действуют серверные ограничения:
0–5спален и0.5–4санузла, даже если в другом интерфейсе временно доступны более широкие диапазоны выбора.