Ideal House
Saltar al contenido

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:

  1. Crear una tarea: envía tu imagen de origen, imagen de estilo, máscara y parámetros, luego recibe un taskId.
  2. Consultar resultados: utiliza el taskId para 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:

EncabezadoValor
APIKEYyour_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 error 9051. 📄 Consulta la Referencia de Deducción de Créditos.

OperaciónCréditos deducidos
Tarea de Sustitución de texturas3 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:

ColorSignificado
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:

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

Texto plano
POST /api/v1/textureReplacer/generate

Encabezados de la solicitud

EncabezadoRequeridoDescripción
APIKEY✅ SíTu clave de autenticación de API
Content-Type✅ Síapplication/json

Cuerpo de la solicitud

CampoTipoRequeridoDescripción
imageUrlstring✅ SíURL de la imagen de origen (la habitación/escena a la que aplicar la textura)
styleImageUrlstring✅ SíURL de la imagen de referencia de estilo que define la textura o material objetivo
maskUrlstring⚠️ maskUrl o maskBase64URL de la imagen de máscara. Las áreas negras recibirán la nueva textura; las áreas blancas se conservan
maskBase64string⚠️ maskUrl o maskBase64Imagen de máscara codificada en Base64 (se recomienda formato PNG). Úsala cuando no puedas proporcionar un URL alojado
promptstring❌ OpcionalIndicación textual adicional para guiar aún más la generación de la textura

⚠️ Al menos uno de maskUrl o maskBase64 debe proporcionarse. Si se proporcionan ambos, maskUrl tiene 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
bash
# 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)
java
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)
python
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)
javascript
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

json
{
  "code": 0,
  "message": "success",
  "data": 1234567890123456789
}
CampoTipoDescripción
codeinteger0 indica éxito
messagestringMensaje de respuesta
datalongEl 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

Texto plano
GET /api/v1/textureReplacer/result

Encabezados de la solicitud

EncabezadoRequeridoDescripción
APIKEY✅ SíTu clave de autenticación de API

Parámetros de consulta

ParámetroTipoRequeridoDescripción
taskIdlong✅ SíEl ID de tarea devuelto por el endpoint de creación de tareas

📥 Ejemplos de solicitud#

cURL
bash
curl -X GET "https://api.ideal.house/api/v1/textureReplacer/result?taskId=1234567890123456789" \
  -H "APIKEY: your_api_key_here"
Java (OkHttp)
java
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)
python
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)
javascript
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)

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

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

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

CampoTipoDescripción
idlongIdentificador único de la tarea
statusstringEstado actual de la tarea (ver Estado de la tarea)
waitNumberintegerNúmero de tareas por delante de la tarea actual en la cola (0 indica procesamiento actual)
percentageintegerPorcentaje de finalización de la tarea (0–100)
inputobjectLos parámetros de entrada originales de la tarea
input.imageUrlstringURL de la imagen de origen
input.styleImageUrlstringURL de la imagen de referencia de estilo
input.maskUrlstringURL de la imagen de máscara (si se proporcionó vía maskUrl)
input.promptstringIndicación textual adicional (si se proporcionó)
outputobjectResultado de la generación (solo disponible cuando status es Success)
output.resultUrlstringURL a la imagen de resultado con textura reemplazada
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 se ha iniciado
ProcessingLa tarea se está procesando actualmente
SuccessLa tarea se completó con éxito; la salida está disponible
FailedLa 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:

json
{
  "code": 5002,
  "message": "Invalid API Key",
  "data": null
}

Referencia de Códigos de Error#

CódigoNombreDescripciónAcción sugerida
1001FAILEDFallo de la solicitud (error genérico)Consulta el campo message para obtener detalles específicos del error
1003INTERNAL_ERRORError interno del servidorReintenta tras un breve retraso; contacta a soporte si persiste
1011PARAM_ERRORError de parámetro de solicitud — por ejemplo, imageUrl, styleImageUrl o falta la máscaraAsegúrate de proporcionar todos los campos requeridos
5002API_KEY_INVALIDClave API inválida o ausenteAsegúrate de que el encabezado APIKEY esté presente y su valor sea correcto
9010SCAN_TEXT_ERRORLa indicación textual no pasó la revisión de contenidoModifica la indicación para eliminar contenido sensible o prohibido
9038PROHIBITED_CONTENTLa imagen de resultado generada contiene contenido prohibidoAjusta la indicación/estilo/entradas y reintenta
9051COINS_NOT_ENOUGHCréditos/monedas insuficientesRecarga 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.