Documentación de la API de sustitución de texturas#
URL base:
https://api.ideal.house
Versión: v1
Actualizado: 2026-03-25
📖 Descripción general#
La API de sustitución de texturas te permite reemplazar la textura o el material de un área seleccionada en una imagen mediante una imagen de referencia de estilo. Proporcionas una imagen de origen, una imagen de referencia de estilo que define la textura/material objetivo, y una imagen de máscara que especifica el área donde se aplicará la nueva textura. La IA integra la nueva textura de forma uniforme en la escena original. El flujo de trabajo es asíncrono e implica dos pasos:
- Crear una tarea: envía tu imagen de origen, imagen de estilo, máscara y parámetros, luego recibe un
taskId. - Consultar resultados: utiliza el
taskIdpara consultar el estado de la tarea y obtener la imagen de resultado.
🔐 Autenticación#
Todas las solicitudes a la API deben autenticarse mediante una Clave de API.
Incluye tu Clave de API en el encabezado de la solicitud:
| Encabezado | Valor |
|---|---|
APIKEY | your_api_key_here |
⚠️ Mantén tu Clave de API segura. No la expongas en código del lado del cliente ni en repositorios públicos.
💰 Deducción de créditos#
[!WARNING] 🪙 Se deducen 3 créditos tras la creación exitosa de la tarea. Si la tarea finalmente falla, los créditos deducidos se restituirán automáticamente a tu cuenta.
Los créditos insuficientes devolverán el código de error9051. 📄 Consulta la Referencia de Deducción de Créditos.
| Operación | Créditos deducidos |
|---|---|
| Tarea de Sustitución de texturas | 3 créditos |
🖼️ Formato de la imagen de máscara#
La imagen de máscara define el área donde se aplicará el reemplazo de textura.
Reglas de la máscara:
| Color | Significado |
|---|---|
| ⬛ Negro | Área donde se aplicará la nueva textura (región a reemplazar) |
| ⬜ Blanco | Área a conservar (fondo que permanece sin cambios) |
⚠️ La imagen de máscara debe tener las mismas dimensiones que la imagen de origen (
imageUrl).
Ejemplo de máscara:
El área negra de la máscara define dónde se aplicará la nueva textura; el área blanca es el fondo que se debe conservar.
📌 Endpoints de la API#
1. Crear tarea de Sustitución de texturas#
Crea una nueva tarea de reemplazo de textura con IA y devuelve un taskId único para realizar sondeos.
Endpoint
POST /api/v1/textureReplacer/generate
Encabezados de la solicitud
| Encabezado | Requerido | Descripción |
|---|---|---|
APIKEY | ✅ Sí | Tu clave de autenticación de API |
Content-Type | ✅ Sí | application/json |
Cuerpo de la solicitud
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
imageUrl | string | ✅ Sí | URL de la imagen de origen (la habitación/escena a la que aplicar la textura) |
styleImageUrl | string | ✅ Sí | URL de la imagen de referencia de estilo que define la textura o material objetivo |
maskUrl | string | ⚠️ maskUrl o maskBase64 | URL de la imagen de máscara. Las áreas negras recibirán la nueva textura; las áreas blancas se conservan |
maskBase64 | string | ⚠️ maskUrl o maskBase64 | Imagen de máscara codificada en Base64 (se recomienda formato PNG). Úsala cuando no puedas proporcionar un URL alojado |
prompt | string | ❌ Opcional | Indicación textual adicional para guiar aún más la generación de la textura |
⚠️ Al menos uno de
maskUrlomaskBase64debe proporcionarse. Si se proporcionan ambos,maskUrltiene prioridad.
🖼️ Requisitos de imagen: las imágenes de origen, estilo y máscara deben ser JPG/JPEG, PNG o WebP. Cada imagen no debe superar 20 MB, con dimensiones desde 128 × 128 px hasta 6,000 × 6,000 px (inclusive). Las imágenes que excedan las dimensiones máximas en píxeles se reducirán proporcionalmente automáticamente para ajustarse dentro de 6,000 × 6,000 px antes del procesamiento. Las URLs de imagen deben ser accesibles directamente por el servidor de la API. Una máscara Base64 está sujeta a los mismos límites de imagen decodificada y no debe incluir un prefijo data-URL.
📥 Ejemplos de solicitud#
cURL
# Using maskUrl
curl -X POST "https://api.ideal.house/api/v1/textureReplacer/generate" \
-H "APIKEY: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"imageUrl": "https://example.com/room.jpg",
"styleImageUrl": "https://example.com/marble-texture.jpg",
"maskUrl": "https://example.com/mask.png"
}'
# Using maskBase64 with optional prompt
curl -X POST "https://api.ideal.house/api/v1/textureReplacer/generate" \
-H "APIKEY: your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"imageUrl": "https://example.com/room.jpg",
"styleImageUrl": "https://example.com/wood-texture.jpg",
"maskBase64": "iVBORw0KGgoAAAANSUhEUgAA...",
"prompt": "natural oak wood grain texture"
}'
Java (OkHttp)
import okhttp3.*;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Base64;
public class TextureReplacerApiExample {
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 IOException {
OkHttpClient client = new OkHttpClient();
// Option 1: Use maskUrl
String requestBody = """
{
"imageUrl": "https://example.com/room.jpg",
"styleImageUrl": "https://example.com/marble-texture.jpg",
"maskUrl": "https://example.com/mask.png"
}
""";
// Option 2: Use maskBase64 (encode local mask file)
// byte[] maskBytes = Files.readAllBytes(Path.of("/path/to/mask.png"));
// String maskBase64 = Base64.getEncoder().encodeToString(maskBytes);
// String requestBody = """
// {
// "imageUrl": "https://example.com/room.jpg",
// "styleImageUrl": "https://example.com/marble-texture.jpg",
// "maskBase64": "%s",
// "prompt": "natural oak wood grain texture"
// }
// """.formatted(maskBase64);
Request request = new Request.Builder()
.url(BASE_URL + "/api/v1/textureReplacer/generate")
.addHeader("APIKEY", API_KEY)
.addHeader("Content-Type", "application/json")
.post(RequestBody.create(requestBody, MediaType.parse("application/json")))
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println("Response: " + response.body().string());
}
}
}
Python (requests)
import requests
import base64
BASE_URL = "https://api.ideal.house"
API_KEY = "your_api_key_here"
headers = {
"APIKEY": API_KEY,
"Content-Type": "application/json"
}
# Option 1: Use maskUrl
payload = {
"imageUrl": "https://example.com/room.jpg",
"styleImageUrl": "https://example.com/marble-texture.jpg",
"maskUrl": "https://example.com/mask.png"
}
# Option 2: Use maskBase64 with optional prompt
# with open("/path/to/mask.png", "rb") as f:
# mask_base64 = base64.b64encode(f.read()).decode("utf-8")
# payload = {
# "imageUrl": "https://example.com/room.jpg",
# "styleImageUrl": "https://example.com/wood-texture.jpg",
# "maskBase64": mask_base64,
# "prompt": "natural oak wood grain texture"
# }
response = requests.post(
f"{BASE_URL}/api/v1/textureReplacer/generate",
headers=headers,
json=payload
)
data = response.json()
task_id = data.get("data")
print(f"Task ID: {task_id}")
Node.js (axios)
const axios = require('axios');
const fs = require('fs');
const BASE_URL = 'https://api.ideal.house';
const API_KEY = 'your_api_key_here';
async function createTextureReplacerTask() {
try {
// Option 1: Use maskUrl
const payload = {
imageUrl: 'https://example.com/room.jpg',
styleImageUrl: 'https://example.com/marble-texture.jpg',
maskUrl: 'https://example.com/mask.png'
};
// Option 2: Use maskBase64 with optional prompt
// const maskBuffer = fs.readFileSync('/path/to/mask.png');
// const maskBase64 = maskBuffer.toString('base64');
// const payload = {
// imageUrl: 'https://example.com/room.jpg',
// styleImageUrl: 'https://example.com/wood-texture.jpg',
// maskBase64: maskBase64,
// prompt: 'natural oak wood grain texture'
// };
const response = await axios.post(
`${BASE_URL}/api/v1/textureReplacer/generate`,
payload,
{
headers: {
'APIKEY': API_KEY,
'Content-Type': 'application/json'
}
}
);
const taskId = response.data.data;
console.log('Task ID:', taskId);
return taskId;
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
}
createTextureReplacerTask();
📤 Respuesta#
Respuesta de Éxito
{
"code": 0,
"message": "success",
"data": 1234567890123456789
}
| Campo | Tipo | Descripción |
|---|---|---|
code | integer | 0 indica éxito |
message | string | Mensaje de respuesta |
data | long | El ID único de la tarea para consultar resultados |
2. Obtener resultado de la tarea#
Obtiene el estado actual y la salida de una tarea de reemplazo de textura creada previamente.
Endpoint
GET /api/v1/textureReplacer/result
Encabezados de la solicitud
| Encabezado | Requerido | Descripción |
|---|---|---|
APIKEY | ✅ Sí | Tu clave de autenticación de API |
Parámetros de consulta
| Parámetro | Tipo | Requerido | Descripción |
|---|---|---|---|
taskId | long | ✅ Sí | El ID de tarea devuelto por el endpoint de creación de tareas |
📥 Ejemplos de solicitud#
cURL
curl -X GET "https://api.ideal.house/api/v1/textureReplacer/result?taskId=1234567890123456789" \
-H "APIKEY: your_api_key_here"
Java (OkHttp)
import okhttp3.*;
import java.io.IOException;
public class TextureReplacerResultExample {
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 IOException {
OkHttpClient client = new OkHttpClient();
long taskId = 1234567890123456789L;
Request request = new Request.Builder()
.url(BASE_URL + "/api/v1/textureReplacer/result?taskId=" + taskId)
.addHeader("APIKEY", API_KEY)
.get()
.build();
try (Response response = client.newCall(request).execute()) {
System.out.println("Response: " + response.body().string());
}
}
}
Python (requests)
import requests
import time
BASE_URL = "https://api.ideal.house"
API_KEY = "your_api_key_here"
headers = {
"APIKEY": API_KEY
}
task_id = 1234567890123456789
# Poll until task is complete
while True:
response = requests.get(
f"{BASE_URL}/api/v1/textureReplacer/result",
headers=headers,
params={"taskId": task_id}
)
data = response.json()
result = data.get("data", {})
status = result.get("status")
print(f"Status: {status}, Progress: {result.get('percentage')}%, Queue: {result.get('waitNumber')}")
if status in ("Success", "Failed"):
break
time.sleep(3) # Poll every 3 seconds
if status == "Success":
print("Result URL:", result["output"]["resultUrl"])
else:
print("Task failed")
Node.js (axios)
const axios = require('axios');
const BASE_URL = 'https://api.ideal.house';
const API_KEY = 'your_api_key_here';
async function pollResult(taskId) {
const headers = { 'APIKEY': API_KEY };
while (true) {
const response = await axios.get(
`${BASE_URL}/api/v1/textureReplacer/result`,
{
headers,
params: { taskId }
}
);
const result = response.data.data;
const { status, percentage, waitNumber } = result;
console.log(`Status: ${status} | Progress: ${percentage}% | Queue: ${waitNumber}`);
if (['Success', 'Failed'].includes(status)) {
if (status === 'Success') {
console.log('Result URL:', result.output.resultUrl);
console.log('Size:', result.output.width, 'x', result.output.height);
} else {
console.log('Task failed');
}
break;
}
// Wait 3 seconds before next poll
await new Promise(resolve => setTimeout(resolve, 3000));
}
}
pollResult(1234567890123456789n);
📤 Respuesta#
Respuesta de Éxito (Tarea Completada)
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Success",
"waitNumber": 0,
"percentage": 100,
"input": {
"imageUrl": "https://example.com/room.jpg",
"styleImageUrl": "https://example.com/marble-texture.jpg",
"maskUrl": "https://example.com/mask.png",
"prompt": "natural marble texture with grey veining"
},
"output": {
"resultUrl": "https://cdn.ideal.house/output/texture_replacer_result.jpg",
"width": 1024,
"height": 1024
}
}
}
Respuesta (tarea en procesamiento / en cola)
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Processing",
"waitNumber": 1,
"percentage": 50,
"input": {
"imageUrl": "https://example.com/room.jpg",
"styleImageUrl": "https://example.com/marble-texture.jpg",
"maskUrl": "https://example.com/mask.png"
},
"output": null
}
}
Respuesta (tarea fallida)
{
"code": 0,
"message": "success",
"data": {
"id": 1234567890123456789,
"status": "Failed",
"waitNumber": 0,
"percentage": 0,
"input": {
"imageUrl": "https://example.com/room.jpg",
"styleImageUrl": "https://example.com/marble-texture.jpg",
"maskUrl": "https://example.com/mask.png"
},
"output": null
}
}
Campos de Respuesta
| Campo | Tipo | Descripción |
|---|---|---|
id | long | Identificador único de la tarea |
status | string | Estado actual de la tarea (ver Estado de la tarea) |
waitNumber | integer | Número de tareas por delante de la tarea actual en la cola (0 indica procesamiento actual) |
percentage | integer | Porcentaje de finalización de la tarea (0–100) |
input | object | Los parámetros de entrada originales de la tarea |
input.imageUrl | string | URL de la imagen de origen |
input.styleImageUrl | string | URL de la imagen de referencia de estilo |
input.maskUrl | string | URL de la imagen de máscara (si se proporcionó vía maskUrl) |
input.prompt | string | Indicación textual adicional (si se proporcionó) |
output | object | Resultado de la generación (solo disponible cuando status es Success) |
output.resultUrl | string | URL a la imagen de resultado con textura reemplazada |
output.width | integer | Ancho de salida en píxeles |
output.height | integer | Alto de salida en píxeles |
📊 Estado de la tarea#
| Estado | Descripción |
|---|---|
Unprocessed | La tarea se ha creado pero aún no se ha iniciado |
Processing | La tarea se está procesando actualmente |
Success | La tarea se completó con éxito; la salida está disponible |
Failed | La tarea falló debido a un error |
Consulta cada 3-5 segundos. Consulta Límite de tareas de la API.
❌ Respuestas de error#
Todas las respuestas de error comparten la misma estructura JSON:
{
"code": 5002,
"message": "Invalid API Key",
"data": null
}
Referencia de Códigos de Error#
| Código | Nombre | Descripción | Acción sugerida |
|---|---|---|---|
1001 | FAILED | Fallo de la solicitud (error genérico) | Consulta el campo message para obtener detalles específicos del error |
1003 | INTERNAL_ERROR | Error interno del servidor | Reintenta tras un breve retraso; contacta a soporte si persiste |
1011 | PARAM_ERROR | Error de parámetro de solicitud — por ejemplo, imageUrl, styleImageUrl o falta la máscara | Asegúrate de proporcionar todos los campos requeridos |
5002 | API_KEY_INVALID | Clave API inválida o ausente | Asegúrate de que el encabezado APIKEY esté presente y su valor sea correcto |
9010 | SCAN_TEXT_ERROR | La indicación textual no pasó la revisión de contenido | Modifica la indicación para eliminar contenido sensible o prohibido |
9038 | PROHIBITED_CONTENT | La imagen de resultado generada contiene contenido prohibido | Ajusta la indicación/estilo/entradas y reintenta |
9051 | COINS_NOT_ENOUGH | Créditos/monedas insuficientes | Recarga los créditos de tu cuenta y reintenta |
📄 Para la lista completa de códigos de error comunes de la API, consulta la Referencia de códigos de error.
