Documentation de l'API de génération de plans d'étage#
URL de base :
https://api.ideal.house
Version : v1
Mis à jour : 2026-08-09
📖 Vue d'ensemble#
L'API de génération de plans d'étage crée un plan d'étage résidentiel conceptuel en noir et blanc, vu de dessus, style CAO, généré par IA, à partir de besoins structurés en pièces et d'une invite personnalisée ou d'une image de référence optionnelle.
La sortie est destinée à l'exploration précoce de l'agencement. Il ne s'agit pas d'un plan de construction, et les dimensions, la géométrie, le placement des équipements et la conformité aux codes générés doivent être examinés par un professionnel qualifié.
Le flux de travail est asynchrone :
- Créer une tâche — Soumettez les paramètres du plan d'étage et recevez un
taskId. - Interrogation périodique des résultats — Interrogez le point de terminaison des résultats avec le
taskIdjusqu'à ce que la tâche atteigne un statut terminal.
🔐 Authentification#
Toutes les requêtes de l'API publique doivent inclure une clé API.
| En-tête | Obligatoire | Valeur |
|---|---|---|
APIKEY | ✅ Oui | Votre clé API |
Content-Type | ✅ Oui pour POST | application/json |
[!WARNING] Gardez votre clé API en sécurité. Ne l'exposez pas dans le code côté client ou dans les dépôts publics.
💰 Déduction de crédits#
Les crédits sont déduits après la création réussie d'une tâche de génération. Si la tâche échoue finalement, les crédits déduits sont automatiquement remboursés. Des crédits insuffisants retournent le code d'erreur 9051.
Modèle (modelType) | Taille de sortie | Crédits |
|---|---|---|
Base | 1536 × 1024 | 10 |
Pro | 2496 × 1664 | 20 |
Flash n'est pas pris en charge par l'API de plans d'étage.
Voir Référence de Déduction de Crédits pour le comportement de facturation courant.
📌 Points de terminaison de l'API#
1. Créer une Tâche de Plan d'Étage#
Crée une tâche de génération de plan d'étage et renvoie un ID de tâche unique.
Point de terminaison
POST /api/v1/floorPlan/generate
En-têtes de requête
| En-tête | Requis | Description |
|---|---|---|
APIKEY | ✅ Oui | Clé d'authentification API |
Content-Type | ✅ Oui | Doit être application/json |
Corps de la requête#
| Champ | Type | Obligatoire | Description | Défaut |
|---|---|---|---|---|
bedrooms | integer | ❌ Non | Nombre de chambres de 0 à 5 | 2 |
bathrooms | number | ❌ Non | Nombre total de salles de bains de 0.5 à 4, par incréments de 0.5 | 1.5 |
totalArea | string | ✅ Oui | Surface totale cible positive avec unité m² ou ft², comme 220 m² ou 1386 ft² | — |
bedroomAreaRanges | array<object> | ❌ Non | Conseils de dimensionnement des chambres facultatifs. Voir Plages de Surface de Chambre | Déduit de totalArea lorsqu'omis |
bathroomDetails | object | ❌ Non | Préférences pour les salles de bains complètes uniquement. Voir Détails Salle de Bains | — |
kitchenDetails | object | ❌ Non | Configuration de cuisine facultative. Voir Détails Cuisine | — |
keyRooms | array<string> | ❌ Non | Pièces ou espaces supplémentaires. Voir Pièces Clés | [] |
prompt | string | ❌ Non | Priorités d'agencement supplémentaires. Cela ne peut pas remplacer les nombres définis par les champs structurés ou les contraintes visuelles rigides | "" |
refImageUrl | string | ❌ Non | URL d'une image de référence accessible publiquement | "" |
modelType | string | ❌ Non | Enum : Base, Pro | Base |
[!IMPORTANT] L'API publique valide actuellement
bedroomscomme0–5etbathroomscomme0.5–4. Les valeurs disponibles dans une autre interface cliente n'élargissent pas ces limites côté serveur.
Règles générales de requête#
- Toutes les valeurs enum sont sensibles à la casse et doivent utiliser les valeurs anglaises affichées dans ce document.
totalAreaest une surface totale cible utilisée pour guider l'échelle et les proportions ; elle n'est pas traitée comme une dimension de construction exacte.- L'invite personnalisée effective est limitée aux 800 premiers caractères lorsque l'invite d'image structurée est assemblée.
- Les champs structurés ont la priorité sur les instructions contradictoires dans
prompt. - Une tâche réussie génère exactement une image.
📐 Surface Totale#
totalArea contient une valeur numérique positive unique suivie d'une unité de surface.
| Unité | Exemple |
|---|---|
m² | 220 m² |
ft² | 1386 ft² |
Un espace blanc avant l'unité est recommandé. Les valeurs décimales sont acceptées lorsqu'elles sont positives.
Exemples valides :
{
"totalArea": "200 m²"
}
{
"totalArea": "1850 ft²"
}
🛏️ Plages de Surface de Chambre#
bedroomAreaRanges fournit des conseils de dimensionnement relatif des chambres. Il ne demande pas d'étiquettes de surface numérique dans l'image générée.
Chaque élément a la forme suivante :
| Champ | Type | Requis | Description |
|---|---|---|---|
name | string | ❌ Non | Identité de la chambre, par exemple Room 1 (Master) ou Room 2 |
minArea | string | ❌ Non | Surface minimale positive |
maxArea | string | ❌ Non | Surface maximale positive ; ne peut pas être inférieure à minArea |
unit | string | ❌ Non | Enum : m², ft² ; utilisez la même unité que totalArea |
Exemple de plage explicite
{
"bedroomAreaRanges": [
{
"name": "Room 1 (Master)",
"minArea": "30",
"maxArea": "40",
"unit": "m²"
},
{
"name": "Room 2",
"minArea": "20",
"maxArea": "30",
"unit": "m²"
}
]
}
Règles lorsqu'un tableau non vide est fourni :
- Sa longueur doit être égale à
bedrooms. - Chaque
minAreaetmaxAreafourni doit être une chaîne numérique positive. - Lorsque les deux valeurs sont fournies,
minArea <= maxArea. unit, lorsqu'il est fourni, doit êtrem²ouft².- Les noms sont conservés. Les éléments vides ou nuls ne fournissent pas de conseils de dimensionnement.
Plages automatiques lorsqu'omis#
Le champ peut être omis ou envoyé comme un tableau vide. Lorsqu'aucun élément ne contient de minArea ou maxArea effectif, le chemin de génération structuré déduit des plages internes de chambres à partir de totalArea et bedrooms :
- Le budget de surface des chambres commence à 20% de la surface totale pour une chambre.
- Le budget augmente de 7.5 points de pourcentage pour chaque chambre supplémentaire, plafonné à 50%.
- La première chambre reçoit un coefficient de dimensionnement de
1.3; chaque autre chambre reçoit un coefficient de1.0. - Chaque cible devient une plage approximative de
±10%, arrondie à des unités de surface entières. - L'unité est héritée de
totalArea. - Les noms de pièces non vides existants sont conservés ; sinon, le serveur utilise
Room 1,Room 2, etc.
Pour 200 m² et 4 chambres, les conseils déduits actuels sont approximativement :
[
{ "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²" }
]
Ces valeurs sont des conseils proportionnels internes, pas des surfaces finales de pièce garanties. Les plages explicites valides ont toujours la priorité sur les plages automatiques.
Lorsque bedrooms est 0, omettez bedroomAreaRanges ou envoyez [].
🛁 Détails Salle de Bains#
bathrooms représente le nombre total de salles de bains :
- Sa partie entière est le nombre de salles de bains complètes.
- Une fraction
.5ajoute une demi-salle de bains. - Chaque salle de bains complète est invitée à inclure des toilettes, un meuble vasque/lavabo et une douche ou zone humide.
- Une demi-salle de bains contient des toilettes et un meuble vasque/lavabo uniquement, sans douche ni baignoire.
bathroomDetails configure uniquement les salles de bains complètes :
{
"bathroomDetails": {
"fullBathroomOptions": [
{
"name": "Bathroom 1",
"wetDrySeparation": "yes",
"bathtub": "required"
},
{
"name": "Bathroom 2",
"wetDrySeparation": "no",
"bathtub": "optional"
}
]
}
}
| Champ | Type | Valeurs autorisées | Description |
|---|---|---|---|
name | string | Bathroom 1, Bathroom 2, etc. | Identité d'affichage optionnelle |
wetDrySeparation | string / null | yes, no, null | Indique s'il faut afficher une zone humide séparée |
bathtub | string / null | no, optional, required, null | Préférence de baignoire |
Règles :
fullBathroomOptions.lengthne peut pas dépasserfloor(bathrooms).- Le tableau peut contenir uniquement les salles de bains complètes pour lesquelles des préférences ont été sélectionnées.
- Une valeur
nullsignifie non spécifiée. - Une baignoire requise est supplémentaire par rapport aux équipements standard de salle de bains complète ; elle ne remplace pas les toilettes ni la douche.
- La séparation humide/sec est une cloison interne dans une salle de bains comptée, pas une salle de bains supplémentaire.
🍳 Détails Cuisine#
Tous les sous-champs de kitchenDetails sont facultatifs. Omettez l'objet entier lorsqu'aucune préférence de cuisine n'est sélectionnée.
{
"kitchenDetails": {
"type": "open",
"size": "standard",
"layout": "U",
"islandType": "preparation",
"storage": "maximum",
"features": ["breakfast nook", "pantry"]
}
}
| Champ | Type | Valeurs autorisées |
|---|---|---|
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 |
Une configuration partielle est valide. Par exemple :
{
"kitchenDetails": {
"type": "semi-open"
}
}
🚪 Pièces Clés#
keyRooms accepte un tableau de ces valeurs exactes :
| Valeur | Description |
|---|---|
walk-in closet | Pièce-penderie dédiée reliée à une chambre |
laundry room | Espace buanderie dédié |
storage room | Pièce de rangement général |
utility room | Pièce technique ou de service |
home office | Bureau ou cabinet dédié |
garage | Garage avec ouverture extérieure pour véhicule et accès intérieur à la maison |
pantry | Garde-manger adjacent à la cuisine |
combined living-dining | Une zone salon et salle à manger combinée |
balcony | Balcon extérieur connecté à l'espace de vie ou à une chambre principale |
La valeur Web héritée balcon est également acceptée et normalisée en balcony.
Règles :
- Les valeurs vides sont ignorées et les valeurs en double sont supprimées.
- Les pièces clés sélectionnées sont demandées une seule fois.
- Les espaces optionnels non sélectionnés sont exclus du programme de pièce généré.
- Si
pantryapparaît à la fois danskitchenDetails.featuresetkeyRooms, un seul garde-manger est demandé.
Exemple :
{
"keyRooms": [
"garage",
"home office",
"combined living-dining"
]
}
🖼️ Image de Référence#
refImageUrl est facultatif et doit être directement accessible par le serveur API.
Conditions requises :
- Format : JPG/JPEG, PNG ou WebP.
- Taille maximale du fichier : 20 Mo.
- Dimensions minimales : 128 × 128 px.
- Dimensions maximales : 6,000 × 6,000 px. Les images plus grandes sont redimensionnées de manière proportionnelle avant traitement.
L'image de référence guide l'agencement, l'adjacence, les proportions ou le style visuel. Elle ne remplace pas les nombres de pièces définis par les champs structurés ou d'autres contraintes rigides.
🤖 Types de Modèle#
| Valeur | Description |
|---|---|
Base | Défaut. Qualité de génération équilibrée, sortie 1536 × 1024 |
Pro | Sortie plus haute résolution 2496 × 1664 avec un temps de génération plus long attendu |
Seuls Base et Pro sont pris en charge.
Champs non présents dans le contrat fonctionnel public#
Les champs suivants ne doivent pas être utilisés par les clients de l'API publique :
| Champ | Remarques |
|---|---|
imageNumbers | Le générateur actuel retourne toujours une image ; ce champ n'est pas nécessaire |
extData | Métadonnées internes de suivi de groupe de tâches Web ; les clients publics doivent l'omettre |
isApiCall | Déterminé par le point de terminaison de l'API, pas par le corps de la requête |
genByMember | Métadonnées de génération internes, pas un champ de requête de Plan d'Étage |
Champs hérités supprimés qui ne doivent pas être envoyés :
floorplanSetting
roomCounts
grossArea
totalAreaValue
totalAreaUnit
totalAreaType
fullBathrooms
halfBathrooms
halfBathroomRequirement
kitchenType
diningRooms
livingRooms
extras
referenceImage
hasDetailOptions
📥 Exemples de Création de Tâche#
Requête minimale avec plages de chambres automatiques#
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"
}'
Requête complète#
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();
Réponse de succès de création de tâche#
{
"code": 0,
"message": "success",
"data": 1234567890123456789
}
| Champ | Type | Description |
|---|---|---|
code | integer | 0 indique que la tâche a été créée avec succès |
message | string | Message de réponse |
data | long | ID de tâche utilisé pour interroger le point de terminaison des résultats |
2. Obtenir le résultat de la tâche#
Retourne l'avancement de la tâche et l'image générée lorsqu'elle est disponible.
Point de terminaison
GET /api/v1/floorPlan/result?taskId={taskId}
En-têtes de requête
| En-tête | Requis | Description |
|---|---|---|
APIKEY | ✅ Oui | Clé d'authentification API |
Paramètres de requête
| Paramètre | Type | Requis | Description |
|---|---|---|---|
taskId | long | ✅ Oui | ID de tâche retourné par le point de terminaison de création |
Exemples de requête de résultat#
cURL
curl -X GET "https://api.ideal.house/api/v1/floorPlan/result?taskId=1234567890123456789" \
-H "APIKEY: your_api_key_here"
Python interrogation
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 interrogation
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');
Réponse de tâche terminée#
{
"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
}
}
}
Réponse de traitement#
{
"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
}
}
Réponse de tâche échouée#
{
"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
}
}
Champs de résultat#
| Champ | Type | Description |
|---|---|---|
id | long | ID de tâche |
status | string | Statut actuel de la tâche |
waitNumber | integer | Nombre de tâches devant dans la file d'attente ; 0 signifie aucune tâche en attente devant |
percentage | integer | Pourcentage de complétion approximatif de 0 à 100 |
input | object | Entrée de tâche normalisée, y compris les plages de chambres déduites automatiquement lorsque cela s'applique |
output | object / null | Sortie générée lorsque la tâche réussit ; sinon généralement null |
output.resultUrl | string | URL signée de l'image de plan d'étage générée |
output.width | integer | Largeur de sortie en pixels |
output.height | integer | Hauteur de sortie en pixels |
📊 État de la tâche#
| État | Description |
|---|---|
Unprocessed | La tâche a été créée mais n'a pas commencé |
Processing | La tâche est en cours de traitement |
Success | La tâche est terminée et output.resultUrl est disponible |
Failed | La tâche a échoué |
Termination | La tâche a été interrompue ou terminée |
Interroger toutes les 3–5 secondes. Voir Limite de Tâche de l'API.
❌ Réponses d'erreur#
Toutes les réponses d'erreur utilisent la structure de réponse commune :
{
"code": 1011,
"message": "bedroomAreaRanges size must match bedrooms",
"data": null
}
| Code | Nom | Description | Action suggérée |
|---|---|---|---|
1001 | FAILED | Échec générique de la requête | Vérifiez le champ message |
1003 | INTERNAL_ERROR | Erreur interne du serveur | Réessayez plus tard ; contactez le support si cela persiste |
1011 | PARAM_ERROR | Paramètre de requête invalide | Vérifiez les nombres de pièces, unités, valeurs enum et tableaux imbriqués |
5002 | API_KEY_INVALID | Clé API invalide ou manquante | Vérifiez l'en-tête APIKEY |
9010 | SCAN_TEXT_ERROR | L'invite a échoué au contrôle de contenu | Modifiez l'invite |
9038 | PROHIBITED_CONTENT | La sortie générée contient du contenu interdit | Ajustez les entrées et réessayez |
9051 | COINS_NOT_ENOUGH | Crédits insuffisants | Ajoutez des crédits et réessayez |
Voir Référence des Codes d'Erreur pour la liste complète des erreurs courantes.
🔄 Notes d'Intégration Web#
L'application Web authentifiée et l'API publique utilisent des points de terminaison et des méthodes d'authentification différentes :
| Client | Point de terminaison | Authentification |
|---|---|---|
| Application Web | POST /floorPlan/generate | En-tête de connexion token |
| API publique | POST /api/v1/floorPlan/generate | En-tête APIKEY |
Les formes de champs commerciaux sont alignées, mais les clients de l'API publique doivent suivre les limites côté serveur et le contrat public dans ce document. En particulier :
- Les clients Web peuvent inclure
imageNumbersetextDatainternes ; les clients publics n'en ont pas besoin. - L'API publique détermine les métadonnées d'appel API à partir de le point de terminaison et des identifiants. Des champs de requête tels que
isApiCalletgenByMembersont inutiles. balconest accepté pour la compatibilité et normalisé enbalcony; les nouvelles intégrations doivent envoyerbalcony.- Les limites serveurs publiques actuelles restent
0–5chambres et0.5–4salles de bains même si une autre interface utilisateur présente temporairement des sélecteurs plus larges.