Ideal House
Перейти к содержанию

Документация по API генерации плана этажа#

Базовый URL: https://api.ideal.house
Версия: v1
Обновлено: 2026-08-09


📖 Обзор#

API генерации плана этажа создаёт с помощью ИИ один концептуальный план жилого помещения: чёрно-белый вид сверху в стиле CAD. Основа — структурированные требования к помещениям и необязательный пользовательский запрос или изображение-образец.

Результат предназначен для предварительной проработки планировки. Это не строительный чертёж: размеры, геометрию, размещение оборудования и соответствие нормам должен проверить квалифицированный специалист.

Рабочий процесс является асинхронным:

  1. Создание задачи — Отправьте параметры плана этажа и получите taskId.
  2. Опрос результатов — Регулярно обращайтесь к конечной точке получения результата с taskId, пока задача не перейдёт в конечное состояние.

🔐 Аутентификация#

Все публичные запросы API должны включать ключ API.

ЗаголовокОбязательныйЗначение
APIKEY✅ ДаВаш ключ API
Content-Type✅ Да для POSTapplication/json

[!WARNING] Держите ваш ключ API в безопасности. Не раскрывайте его в клиентском коде или публичных репозиториях.


💰 Списание кредитов#

Кредиты списываются после успешного создания задачи генерации. Если задача в итоге завершится ошибкой, списанные кредиты автоматически возвращаются. При недостатке кредитов возвращается код ошибки 9051.

Модель (modelType)Размер выводаКредиты
Base1536 × 102410
Pro2496 × 166420

Flash не поддерживается в API генерации плана этажа.

Общие правила оплаты приведены в Справочнике по списанию кредитов.


📌 Конечные точки API#

1. Создание задачи генерации плана этажа#

Создает задачу генерации плана этажа и возвращает уникальный идентификатор задачи.

Конечная точка

http
POST /api/v1/floorPlan/generate

Заголовки запроса

ЗаголовокОбязательныйОписание
APIKEY✅ ДаКлюч аутентификации API
Content-Type✅ ДаДолжен быть application/json

Тело запроса#

ПолеТипОбязательноеОписаниеПо умолчанию
bedroomsinteger❌ НетКоличество спален от 0 до 52
bathroomsnumber❌ НетОбщее количество ванных комнат от 0.5 до 4, с шагом 0.51.5
totalAreastring✅ ДаПоложительная целевая общая площадь с единицей или ft², например 220 m² или 1386 ft²
bedroomAreaRangesarray<object>❌ НетНеобязательные рекомендации по размерам спален. См. Диапазоны площади спаленВыводится из totalArea при отсутствии
bathroomDetailsobject❌ НетПредпочтения только для полноценных ванных комнат. См. Детали ванных комнат
kitchenDetailsobject❌ НетНеобязательная конфигурация кухни. См. Детали кухни
keyRoomsarray<string>❌ НетДополнительные помещения или пространства. См. Ключевые помещения[]
promptstring❌ НетДополнительные пожелания по планировке. Они не могут изменить количество помещений, заданное структурированными полями, или обязательные визуальные ограничения""
refImageUrlstring❌ НетПублично доступный URL референс-изображения""
modelTypestring❌ НетПеречисление: Base, ProBase

[!IMPORTANT] Публичный API в настоящее время валидирует bedrooms как 0–5 и bathrooms как 0.5–4. Значения, доступные в другом клиентском интерфейсе, не расширяют эти серверные ограничения.

Общие правила запроса#

  • Все значения перечислений чувствительны к регистру и должны использовать английские значения, показанные в этом документе.
  • totalArea — целевая общая площадь, которая задаёт масштаб и пропорции, а не точный строительный размер.
  • При формировании структурированного запроса на генерацию изображения учитываются только первые 800 символов пользовательского запроса.
  • Структурированные поля имеют приоритет над противоречащими инструкциями в prompt.
  • Успешная задача генерирует ровно одно изображение.

📐 Общая площадь#

totalArea содержит одно положительное числовое значение, за которым следует единица площади.

ЕдиницаПример
220 m²
ft²1386 ft²

Пробел перед единицей рекомендуется. Дробные значения принимаются, если они положительные.

Допустимые примеры:

json
{
  "totalArea": "200 m²"
}
json
{
  "totalArea": "1850 ft²"
}

🛏️ Диапазоны площади спален#

bedroomAreaRanges задаёт относительные размеры спален. Этот параметр не требует добавлять на изображение числовые подписи площадей.

Каждый элемент имеет следующую структуру:

ПолеТипОбязательныйОписание
namestring❌ НетИдентификатор спальни, например Room 1 (Master) или Room 2
minAreastring❌ НетПоложительная минимальная площадь
maxAreastring❌ НетПоложительная максимальная площадь; не может быть меньше minArea
unitstring❌ НетПеречисление: , ft²; используйте ту же единицу, что и в totalArea

Пример явного диапазона

json
{
  "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, если предоставлено, должно быть или ft².
  • Имена сохраняются. Пустые или null-элементы не предоставляют рекомендаций по размерам.

Автоматические диапазоны при отсутствии#

Поле можно не передавать или отправить пустой массив. Если ни один элемент не содержит действующего значения minArea или maxArea, при структурированной генерации внутренние диапазоны площадей спален рассчитываются по totalArea и bedrooms:

  • Для одной спальни отводится 20% общей площади.
  • На каждую дополнительную спальню выделяемая доля увеличивается на 7.5 процентных пунктов, но не превышает 50%.
  • При распределении площади первая спальня получает вес 1.3, а каждая из остальных — вес 1.0.
  • Вокруг каждого целевого значения задаётся приблизительный диапазон ±10% с округлением до целых единиц площади.
  • Единица наследуется из totalArea.
  • Существующие непустые имена помещений сохраняются; в противном случае сервер использует Room 1, Room 2 и т. д.

Для 200 m² и 4 спален текущий расчёт даёт примерно следующие ориентиры:

json
[
  { "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 настраивает только полноценные ванные комнаты:

json
{
  "bathroomDetails": {
    "fullBathroomOptions": [
      {
        "name": "Bathroom 1",
        "wetDrySeparation": "yes",
        "bathtub": "required"
      },
      {
        "name": "Bathroom 2",
        "wetDrySeparation": "no",
        "bathtub": "optional"
      }
    ]
  }
}
ПолеТипДопустимые значенияОписание
namestringBathroom 1, Bathroom 2 и т. д.Необязательный отображаемый идентификатор
wetDrySeparationstring / nullyes, no, nullПоказывать ли выделенную мокрую зону
bathtubstring / nullno, optional, required, nullПредпочтение по ванне

Правила:

  • fullBathroomOptions.length не может превышать floor(bathrooms).
  • Массив может содержать только те полноценные ванные комнаты, для которых выбраны предпочтения.
  • Значение null означает, что не указано.
  • Обязательная ванна является дополнительной к стандартным сантехническим приборам полноценной ванной комнаты; она не заменяет унитаз или душ.
  • Разделение сухой и мокрой зон означает перегородку внутри уже учтённого санузла, а не дополнительный санузел.

🍳 Детали кухни#

Все дочерние поля kitchenDetails являются необязательными. Опустите весь объект, если не выбрано предпочтение по кухне.

json
{
  "kitchenDetails": {
    "type": "open",
    "size": "standard",
    "layout": "U",
    "islandType": "preparation",
    "storage": "maximum",
    "features": ["breakfast nook", "pantry"]
  }
}
ПолеТипДопустимые значения
typestringopen, semi-open, closed
sizestringsmall, standard, large, extra large
layoutstringI, L, U, gallery
islandTypestringno, preparation, cooking, entertainment
storagestringminimal, standard, maximum
featuresarray<string>eating bar, breakfast nook, pantry

Частичная конфигурация допустима. Например:

json
{
  "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, запрашивается только одна кладовая.

Пример:

json
{
  "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Внутренние метаданные генерации, а не поле запроса плана этажа

Удаленные устаревшие поля, которые не следует отправлять:

text
floorplanSetting
roomCounts
grossArea
totalAreaValue
totalAreaUnit
totalAreaType
fullBathrooms
halfBathrooms
halfBathroomRequirement
kitchenType
diningRooms
livingRooms
extras
referenceImage
hasDetailOptions

📥 Примеры создания задачи#

Минимальный запрос с автоматическими диапазонами спален#

bash
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
bash
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)
java
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)
python
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)
javascript
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();

Ответ об успешном создании задачи#

json
{
  "code": 0,
  "message": "success",
  "data": 1234567890123456789
}
ПолеТипОписание
codeinteger0 указывает, что задача была успешно создана
messagestringСообщение в ответе
datalongИдентификатор задачи, используемый для опроса конечной точки результатов

2. Получение результата задачи#

Возвращает прогресс задачи и сгенерированное изображение, если оно доступно.

Конечная точка

http
GET /api/v1/floorPlan/result?taskId={taskId}

Заголовки запроса

ЗаголовокОбязательныйОписание
APIKEY✅ ДаКлюч аутентификации API

Параметры запроса

ПараметрТипОбязательныйОписание
taskIdlong✅ ОбязательноИдентификатор задачи, возвращенный конечной точкой создания

Примеры запросов результатов#

cURL
bash
curl -X GET "https://api.ideal.house/api/v1/floorPlan/result?taskId=1234567890123456789" \
  -H "APIKEY: your_api_key_here"
Опрос с помощью Python
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
javascript
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');

Ответ для завершённой задачи#

json
{
  "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
    }
  }
}

Ответ в процессе обработки#

json
{
  "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
  }
}

Ответ об ошибке задачи#

json
{
  "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
  }
}

Поля результата#

ПолеТипОписание
idlongИдентификатор задачи
statusstringТекущий статус задачи
waitNumberintegerКоличество задач в очереди впереди; 0 означает отсутствие задач в очереди впереди
percentageintegerПриблизительный процент завершения от 0 до 100
inputobjectНормализованные входные данные задачи, включая автоматически рассчитанные диапазоны площадей спален, когда это применимо
outputobject / nullСгенерированный результат при успешном завершении задачи; в остальных случаях обычно null
output.resultUrlstringПодписанный URL сгенерированного изображения плана этажа
output.widthintegerШирина результата в пикселях
output.heightintegerВысота результата в пикселях

📊 Статус задачи#

СтатусОписание
UnprocessedЗадача создана, но еще не началась
ProcessingЗадача обрабатывается
SuccessЗадача завершена и output.resultUrl доступно
FailedЗадача завершилась ошибкой
TerminationВыполнение задачи было прервано или прекращено

Опрашивайте каждые 3–5 секунд. См. Лимит задач API.


❌ Ответы об ошибках#

Все ответы об ошибках используют общую структуру ответа:

json
{
  "code": 1011,
  "message": "bedroomAreaRanges size must match bedrooms",
  "data": null
}
КодИмяОписаниеРекомендуемое действие
1001FAILEDОбщая ошибка запросаПроверьте поле message
1003INTERNAL_ERRORВнутренняя ошибка сервераПовторите позже; обратитесь в поддержку, если проблема сохраняется
1011PARAM_ERRORНекорректный параметр запросаПроверьте количество помещений, единицы измерения, значения перечислений и вложенные массивы
5002API_KEY_INVALIDНедействительный или отсутствующий ключ APIПроверьте заголовок APIKEY
9010SCAN_TEXT_ERRORПромпт не прошел проверку контентаИзмените промпт
9038PROHIBITED_CONTENTСгенерированный вывод содержит запрещенный контентОтрегулируйте входные данные и повторите
9051COINS_NOT_ENOUGHНедостаточно кредитовДобавьте кредиты и повторите

См. Справочник кодов ошибок для полного списка общих ошибок.


🔄 Примечания по интеграции с веб-приложением#

Веб-приложение, требующее входа в аккаунт, и публичный API используют разные конечные точки и способы аутентификации:

КлиентКонечная точкаАутентификация
Веб-приложениеPOST /floorPlan/generateЗаголовок token с токеном входа
Публичный APIPOST /api/v1/floorPlan/generateЗаголовок APIKEY

Структуры полей согласованы, но клиенты публичного API должны соблюдать серверные ограничения и публичную спецификацию этого документа. В частности:

  • Веб-клиенты могут включать внутренние imageNumbers и extData; публичные клиенты не нуждаются в них.
  • Публичный API определяет метаданные вызова API из конечной точки и учетных данных. Поля запроса, такие как isApiCall и genByMember, не нужны.
  • balcon принимается для совместимости и нормализуется до balcony; новые интеграции должны отправлять balcony.
  • Для публичного API по-прежнему действуют серверные ограничения: 0–5 спален и 0.5–4 санузла, даже если в другом интерфейсе временно доступны более широкие диапазоны выбора.