Ideal House
Saltar al contenido

Documentación de la API de generación de planos de planta#

URL base: https://api.ideal.house
Versión: v1
Actualizado: 2026-08-09


📖 Descripción general#

API de generación de planos de planta crea un plano de planta conceptual residencial, en blanco y negro, visto desde arriba y con estilo CAD, generado por IA, a partir de requisitos estructurados de habitaciones y un prompt personalizado o imagen de referencia opcionales.

El resultado está destinado a la exploración temprana de la distribución. No es un dibujo de construcción, y las dimensiones generadas, la geometría, la colocación de accesorios y el cumplimiento normativo deben ser revisados por un profesional cualificado.

El flujo de trabajo es asíncrono:

  1. Crear una tarea: envía los parámetros del plano de planta y recibe un taskId.
  2. Consultar resultados: consulta el punto de conexión de resultados con el taskId hasta que la tarea alcance un estado terminal.

🔐 Autenticación#

Todas las solicitudes de API públicas deben incluir una clave API.

CabeceraObligatorioValor
APIKEY✅ SíTu clave API
Content-Type✅ Sí para POSTapplication/json

[!WARNING] Mantén tu clave API segura. No la expongas en código del lado del cliente ni en repositorios públicos.


💰 Deducción de créditos#

Los créditos se descuentan después de que una tarea de generación se haya creado correctamente. Si la tarea finalmente falla, los créditos descontados se reembolsan automáticamente. La insuficiencia de créditos genera el código de error 9051.

Modelo (modelType)Tamaño de salidaCréditos
Base1536 × 102410
Pro2496 × 166420

Flash no es compatible con Floor Plan API.

Consulta Referencia de deducción de créditos para conocer el comportamiento habitual de facturación.


📌 Endpoints de la API#

1. Crear tarea de plano de planta#

Crea una tarea de generación de plano de planta y devuelve un ID de tarea único.

Endpoint

http
POST /api/v1/floorPlan/generate

Cabeceras de solicitud

EncabezadoObligatorioDescripción
APIKEY✅ SíClave de autenticación API
Content-Type✅ SíDebe ser application/json

Cuerpo de la solicitud#

CampoTipoObligatorioDescripciónPredeterminado
bedroomsinteger❌ NoCantidad de dormitorios de 0 a 52
bathroomsnumber❌ NoCantidad total de baños de 0.5 a 4, en incrementos de 0.51.5
totalAreastring✅ SíÁrea total objetivo positiva con unidad o ft², como 220 m² o 1386 ft²
bedroomAreaRangesarray<object>❌ NoOrientación opcional del tamaño de los dormitorios. Ver rangos de área de dormitoriosSe deriva de totalArea cuando se omite
bathroomDetailsobject❌ NoPreferencias solo para baños completos. Ver detalles del baño
kitchenDetailsobject❌ NoConfiguración opcional de la cocina. Ver detalles de la cocina
keyRoomsarray<string>❌ NoHabitaciones o espacios adicionales. Ver habitaciones clave[]
promptstring❌ NoPrioridades de diseño adicionales. No puede anular los conteos estructurados ni las restricciones visuales fijas""
refImageUrlstring❌ NoURL de la imagen de referencia accesible públicamente""
modelTypestring❌ NoEnum: Base, ProBase

[!IMPORTANT] La API pública actual valida bedrooms como 0–5 y bathrooms como 0.5–4. Los valores disponibles en otra interfaz de cliente no amplían estos límites del lado del servidor.

Reglas generales de solicitud#

  • Todos los valores enum son sensibles a mayúsculas y deben usar los valores en inglés que se muestran en este documento.
  • totalArea es un área total objetivo utilizada para guiar la escala y las proporciones; no se trata como una dimensión de construcción exacta.
  • El prompt personalizado efectivo está limitado a los primeros 800 caracteres cuando se ensambla el prompt de imagen estructurado.
  • Los campos estructurados tienen prioridad sobre las instrucciones contradictorias en prompt.
  • Una tarea exitosa genera exactamente una imagen.

📐 Área total#

totalArea contiene un valor numérico positivo seguido de una unidad de área.

UnidadEjemplo
220 m²
ft²1386 ft²

Se recomienda un espacio en blanco antes de la unidad. Se aceptan valores decimales cuando son positivos.

Ejemplos válidos:

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

🛏️ Rangos de área de dormitorios#

bedroomAreaRanges proporciona orientación relativa del tamaño del dormitorio. No solicita etiquetas de área numéricas en la imagen generada.

Cada elemento tiene la siguiente estructura:

CampoTipoObligatorioDescripción
namestring❌ NoIdentidad del dormitorio, por ejemplo Room 1 (Master) o Room 2
minAreastring❌ NoÁrea mínima positiva
maxAreastring❌ NoÁrea máxima positiva; no puede ser menor que minArea
unitstring❌ NoEnum: , ft²; usa la misma unidad que totalArea

Ejemplo de rango explícito

json
{
  "bedroomAreaRanges": [
    {
      "name": "Room 1 (Master)",
      "minArea": "30",
      "maxArea": "40",
      "unit": "m²"
    },
    {
      "name": "Room 2",
      "minArea": "20",
      "maxArea": "30",
      "unit": "m²"
    }
  ]
}

Reglas cuando se proporciona una matriz no vacía:

  • Su longitud debe ser igual a bedrooms.
  • Cada minArea y maxArea suministrado debe ser una cadena numérica positiva.
  • Cuando ambos valores se suministran, minArea <= maxArea.
  • unit, cuando se suministra, debe ser o ft².
  • Los nombres se conservan. Los elementos vacíos o nulos no proporcionan orientación de tamaño.

Rangos automáticos cuando se omite#

El campo puede omitirse o enviarse como una matriz vacía. Cuando ningún elemento contiene un minArea o maxArea efectivo, la vía de generación estructurada deriva rangos internos de dormitorio a partir de totalArea y bedrooms:

  • El presupuesto de área del dormitorio comienza en 20% del área total para un dormitorio.
  • El presupuesto aumenta en 7.5 puntos porcentuales por cada dormitorio adicional, con un tope en 50%.
  • El primer dormitorio recibe un peso de tamaño de 1.3; cada otro dormitorio recibe un peso de 1.0.
  • Cada objetivo se convierte en un rango aproximado de ±10%, redondeado a unidades de área enteras.
  • La unidad se hereda de totalArea.
  • Los nombres existentes no vacíos de las habitaciones se conservan; de lo contrario, el servidor usa Room 1, Room 2, y así sucesivamente.

Para 200 m² y 4 dormitorios, la orientación derivada actual es aproximadamente:

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²" }
]

Estos valores son orientación proporcional interna, no áreas finales garantizadas de la habitación. Los rangos válidos explícitos siempre tienen prioridad sobre los rangos automáticos.

Cuando bedrooms es 0, omite bedroomAreaRanges o envía [].


🛁 Detalles del baño#

bathrooms representa el recuento total de baños:

  • Su parte entera es el número de baños completos.
  • Una fracción .5 añade un medio baño.
  • Se solicita que cada baño completo incluya un inodoro, mueble de lavabo/lavabo, y ducha o zona húmeda.
  • Un medio baño contiene solo un inodoro y mueble de lavabo/lavabo, sin ducha ni bañera.

bathroomDetails solo configura baños completos:

json
{
  "bathroomDetails": {
    "fullBathroomOptions": [
      {
        "name": "Bathroom 1",
        "wetDrySeparation": "yes",
        "bathtub": "required"
      },
      {
        "name": "Bathroom 2",
        "wetDrySeparation": "no",
        "bathtub": "optional"
      }
    ]
  }
}
CampoTipoValores permitidosDescripción
namestringBathroom 1, Bathroom 2, etc.Identidad visual opcional
wetDrySeparationstring / nullyes, no, nullSi mostrar una zona húmeda separada
bathtubstring / nullno, optional, required, nullPreferencia de bañera

Reglas:

  • fullBathroomOptions.length no puede exceder floor(bathrooms).
  • La matriz solo puede contener los baños completos para los que se hayan seleccionado preferencias.
  • Un valor de null significa no especificado.
  • Una bañera requerida es adicional a los accesorios estándar del baño completo; no reemplaza el inodoro ni la ducha.
  • La separación húmeda/seca es una partición interna dentro de un baño contado, no un baño adicional.

🍳 Detalles de la cocina#

Todos los campos secundarios de kitchenDetails son opcionales. Omite todo el objeto cuando no se seleccione preferencia de cocina.

json
{
  "kitchenDetails": {
    "type": "open",
    "size": "standard",
    "layout": "U",
    "islandType": "preparation",
    "storage": "maximum",
    "features": ["breakfast nook", "pantry"]
  }
}
CampoTipoValores permitidos
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

La configuración parcial es válida. Por ejemplo:

json
{
  "kitchenDetails": {
    "type": "semi-open"
  }
}

🚪 Habitaciones clave#

keyRooms acepta una matriz de estos valores exactos:

ValorDescripción
walk-in closetVestidor independiente conectado a una zona de dormitorio
laundry roomEspacio dedicado para lavandería
storage roomHabitación de almacenamiento general
utility roomHabitación mecánica o de servicio
home officeOficina o estudio dedicado
garageGaraje con apertura exterior para vehículos y acceso interno al hogar
pantryDespensa adyacente a la cocina
combined living-diningUna zona compartida de estar y comedor
balconyBalcón exterior conectado al espacio de estar o al dormitorio principal

El valor heredado de Web balcon también se acepta y se normaliza a balcony.

Reglas:

  • Los valores vacíos se ignoran y los valores duplicados se eliminan.
  • Las habitaciones clave seleccionadas se solicitan una sola vez.
  • Los espacios opcionales no seleccionados se excluyen del distribución de habitaciones generada.
  • Si pantry aparece tanto en kitchenDetails.features como en keyRooms, solo se solicita una despensa.

Ejemplo:

json
{
  "keyRooms": [
    "garage",
    "home office",
    "combined living-dining"
  ]
}

🖼️ Imagen de referencia#

refImageUrl es opcional y debe ser accesible directamente por el servidor de API.

Requisitos:

  • Formato: JPG/JPEG, PNG o WebP.
  • Tamaño máximo de archivo: 20 MB.
  • Dimensiones mínimas: 128 × 128 px.
  • Dimensiones máximas: 6,000 × 6,000 px. Las imágenes más grandes se escalan proporcionalmente antes del procesamiento.

La imagen de referencia guía la distribución, la adyacencia, las proporciones o el estilo visual. No anula los conteos estructurados de habitaciones ni otras restricciones fijas.


🤖 Tipos de modelo#

ValorDescripción
BasePredeterminado. Calidad de generación equilibrada, salida de 1536 × 1024
ProSalida de mayor resolución de 2496 × 1664 con un tiempo de generación esperado más largo

Solo se admiten Base y Pro.


Campos que no forman parte de la especificación funcional pública#

Los siguientes campos no deben ser utilizados por los clientes de API públicos:

CampoNotas
imageNumbersEl generador actual siempre devuelve una imagen; este campo no es necesario
extDataMetadatos de seguimiento de grupo de tareas de Web internas; los clientes públicos deben omitirlo
isApiCallDeterminado por el punto de conexión de API, no por el cuerpo de la solicitud
genByMemberMetadatos de generación interna, no un campo de solicitud de plano de planta

Campos heredados eliminados que no deben enviarse:

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

📥 Ejemplos de creación de tarea#

Solicitud mínima con rangos automáticos de dormitorios#

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"
  }'

Solicitud completa#

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();

Respuesta de éxito de creación de tarea#

json
{
  "code": 0,
  "message": "success",
  "data": 1234567890123456789
}
CampoTipoDescripción
codeinteger0 indica que la tarea se creó correctamente
messagestringMensaje de la respuesta
datalongID de tarea utilizado para consultar el punto de conexión de resultados

2. Obtener resultado de la tarea#

Devuelve el progreso de la tarea y la imagen generada cuando esté disponible.

Endpoint

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

Cabeceras de solicitud

EncabezadoObligatorioDescripción
APIKEY✅ SíClave de autenticación API

Parámetros de consulta

ParámetroTipoObligatorioDescripción
taskIdlong✅ SíID de la tarea devuelto por el endpoint de creación

Ejemplos de solicitud de resultado#

cURL
bash
curl -X GET "https://api.ideal.house/api/v1/floorPlan/result?taskId=1234567890123456789" \
  -H "APIKEY: your_api_key_here"
Sondeo con 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"])
Sondeo con 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');

Respuesta de tarea completada#

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
    }
  }
}

Respuesta de procesamiento#

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
  }
}

Respuesta de tarea fallida#

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
  }
}

Campos del resultado#

CampoTipoDescripción
idlongID de tarea
statusstringEstado actual de la tarea
waitNumberintegerNúmero de tareas por delante en la cola; 0 significa que no hay tareas por delante
percentageintegerPorcentaje aproximado de finalización de 0 a 100
inputobjectEntrada de tarea normalizada, incluidos los rangos de dormitorios derivados automáticamente cuando corresponda
outputobject / nullSalida generada cuando la tarea tiene éxito; de lo contrario, generalmente null
output.resultUrlstringURL firmada de la imagen del plano de planta generado
output.widthintegerAncho de salida en píxeles
output.heightintegerAlto de salida en píxeles

📊 Estado de la tarea#

EstadoDescripción
UnprocessedLa tarea se ha creado pero aún no ha comenzado
ProcessingLa tarea se está procesando
SuccessLa tarea se completó y output.resultUrl está disponible
FailedLa tarea falló
TerminationLa tarea fue interrumpida o terminada

Consulta cada 3–5 segundos. Consulta Límite de tareas de API.


❌ Respuestas de error#

Todas las respuestas de error utilizan la estructura de respuesta común:

json
{
  "code": 1011,
  "message": "bedroomAreaRanges size must match bedrooms",
  "data": null
}
CódigoNombreDescripciónAcción sugerida
1001FAILEDFalla genérica de la solicitudComprueba el campo message
1003INTERNAL_ERRORError interno del servidorReintenta más tarde; contacta con soporte si persiste
1011PARAM_ERRORParámetro de solicitud no válidoVerifica conteos, unidades, valores enum y matrices anidadas
5002API_KEY_INVALIDClave API no válida o faltanteVerifica la cabecera APIKEY
9010SCAN_TEXT_ERROREl prompt falló en la revisión de contenidoRevisa el prompt
9038PROHIBITED_CONTENTLa salida generada contiene contenido prohibidoAjusta las entradas y reintenta
9051COINS_NOT_ENOUGHCréditos insuficientesAñade créditos y reintenta

Consulta Referencia de códigos de error para la lista completa de errores comunes.


🔄 Notas de integración Web#

La aplicación Web autenticada y la API pública utilizan puntos de conexión y métodos de autenticación diferentes:

ClientePunto de conexiónAutenticación
Aplicación WebPOST /floorPlan/generateCabecera de inicio de sesión token
API públicaPOST /api/v1/floorPlan/generateCabecera APIKEY

Las estructuras de los campos funcionales están alineadas, pero los clientes de API pública deben seguir los límites del lado del servidor y el contrato público de este documento. En particular:

  • Los clientes Web pueden incluir imageNumbers y extData internos; los clientes públicos no los necesitan.
  • La API pública determina los metadatos de llamada de API a partir del punto de conexión y las credenciales. Los campos de solicitud como isApiCall y genByMember no son necesarios.
  • balcon se acepta por compatibilidad y se normaliza a balcony; las nuevas integraciones deben enviar balcony.
  • Los límites actuales del servidor público siguen siendo 0–5 dormitorios y 0.5–4 baños, incluso si otra UI presenta selectores más amplios de manera temporal.