Ideal House
콘텐츠로 이동

스마트 교체 API 문서#

기본 URL: https://api.ideal.house
버전: v1
갱신일: 2026-03-06


📖 개요#

스마트 교체 API는 이미지에서 선택한 영역을 텍스트 프롬프트에 따라 AI가 생성한 콘텐츠로 지능적으로 교체합니다. 원본 이미지, 교체할 영역을 정의하는 마스크 이미지, 해당 영역을 채울 내용을 설명하는 텍스트 프롬프트를 제공합니다. AI가 생성한 콘텐츠를 원본 이미지에 자연스럽게 합성합니다. 작업 흐름은 다음 두 단계의 비동기 방식입니다.

  1. 작업 생성 — 이미지, 마스크 및 프롬프트를 제출하고 taskId를 받습니다.
  2. 결과 폴링taskId로 작업 상태를 조회하고 결과 이미지를 가져옵니다.

🔐 인증#

모든 API 요청은 API 키로 인증해야 합니다.

요청 헤더에 API 키를 포함하세요.

헤더
APIKEYyour_api_key_here

⚠️ API 키를 안전하게 보관하세요. 클라이언트 측 코드 또는 공개 저장소에 노출하지 마세요.


💰 크레딧 차감#

[!WARNING] 🪙 작업이 성공적으로 생성되면 계정에서 작업당 1크레딧이 차감됩니다. 작업이 최종적으로 실패하면 차감된 크레딧은 계정으로 자동 환불됩니다.
크레딧이 부족하면 오류 코드 9051을 반환합니다. 📄 크레딧 차감 참조를 참고하세요.


🖼️ 마스크 이미지 형식#

마스크 이미지는 원본 이미지에서 교체할 영역을 정의합니다.

마스크 규칙:

색상의미
검정교체할 영역 (새 콘텐츠가 생성될 영역)
흰색보존할 영역 (변경하지 않을 배경)

⚠️ 마스크 이미지는 원본 이미지(imageUrl)와 크기가 같아야 합니다.

마스크 예제:

마스크 예제

마스크의 검은 영역은 AI가 교체할 부분을 표시하며 흰 영역은 보존할 배경입니다.


📌 API 엔드포인트#


1. 스마트 교체 작업 생성#

새 AI 스마트 교체 작업을 만들고 폴링용 고유 taskId를 반환합니다.

엔드포인트

일반 텍스트
POST /api/v1/smartReplace/generate

요청 헤더

헤더필수 여부설명
APIKEY✅ 예API 인증 키
Content-Type✅ 예application/json

요청 본문

필드유형필수 여부설명
imageUrlstring✅ 예원본 이미지 URL
promptstring✅ 예마스크 영역에 생성할 콘텐츠를 설명하는 텍스트 프롬프트 (예: "a modern armchair", "marble flooring")
maskUrlstring⚠️ maskUrl 또는 maskBase64 중 하나마스크 이미지 URL. 검은 영역은 교체되고 흰 영역은 보존됩니다.
maskBase64string⚠️ maskUrl 또는 maskBase64 중 하나Base64로 인코딩된 마스크 이미지 (PNG 형식 권장). 호스팅된 URL을 제공할 수 없을 때 사용합니다.

⚠️ maskUrl 또는 maskBase64 중 하나 이상을 제공해야 합니다. 둘 다 제공하면 maskUrl이 우선합니다.

🖼️ 이미지 요건: 원본 이미지와 마스크는 JPG/JPEG, PNG 또는 WebP여야 합니다. 각 이미지는 20 MB 이하여야 하며 크기는 128 × 128 px부터 6,000 × 6,000 px까지 허용됩니다(경계값 포함). 최대 픽셀 크기를 초과하는 이미지는 처리 전에 6,000 × 6,000 px 안에 들어오도록 비율을 유지하여 자동 축소됩니다. 이미지 URL은 API 서버에서 직접 접근할 수 있어야 합니다. Base64 마스크에도 디코딩된 이미지 기준으로 동일한 제한이 적용되며 data-URL 접두사를 포함하면 안 됩니다.


📥 요청 예제#

cURL
bash
# Using maskUrl
curl -X POST "https://api.ideal.house/api/v1/smartReplace/generate" \
  -H "APIKEY: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "imageUrl": "https://example.com/room.jpg",
    "prompt": "a modern velvet sofa in dark blue",
    "maskUrl": "https://example.com/mask.png"
  }'

# Using maskBase64
curl -X POST "https://api.ideal.house/api/v1/smartReplace/generate" \
  -H "APIKEY: your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "imageUrl": "https://example.com/room.jpg",
    "prompt": "a modern velvet sofa in dark blue",
    "maskBase64": "iVBORw0KGgoAAAANSUhEUgAA..."
  }'
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 SmartReplaceApiExample {

    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",
                "prompt": "a modern velvet sofa in dark blue",
                "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",
        //         "prompt": "a modern velvet sofa in dark blue",
        //         "maskBase64": "%s"
        //     }
        //     """.formatted(maskBase64);

        Request request = new Request.Builder()
            .url(BASE_URL + "/api/v1/smartReplace/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",
    "prompt": "a modern velvet sofa in dark blue",
    "maskUrl": "https://example.com/mask.png"
}

# Option 2: Use maskBase64 (encode local mask file)
# 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",
#     "prompt": "a modern velvet sofa in dark blue",
#     "maskBase64": mask_base64
# }

response = requests.post(
    f"{BASE_URL}/api/v1/smartReplace/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 createSmartReplaceTask() {
  try {
    // Option 1: Use maskUrl
    const payload = {
      imageUrl: 'https://example.com/room.jpg',
      prompt: 'a modern velvet sofa in dark blue',
      maskUrl: 'https://example.com/mask.png'
    };

    // Option 2: Use maskBase64 (encode local mask file)
    // const maskBuffer = fs.readFileSync('/path/to/mask.png');
    // const maskBase64 = maskBuffer.toString('base64');
    // const payload = {
    //   imageUrl: 'https://example.com/room.jpg',
    //   prompt: 'a modern velvet sofa in dark blue',
    //   maskBase64: maskBase64
    // };

    const response = await axios.post(
      `${BASE_URL}/api/v1/smartReplace/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);
  }
}

createSmartReplaceTask();

📤 응답#

성공 응답

json
{
  "code": 0,
  "message": "success",
  "data": 1234567890123456789
}
필드유형설명
codeinteger0은 성공을 의미함
messagestring응답 메시지
datalong결과 폴링용 고유 작업 ID

2. 작업 결과 조회#

이전에 생성한 스마트 교체 작업의 현재 상태와 출력을 조회합니다.

엔드포인트

일반 텍스트
GET /api/v1/smartReplace/result

요청 헤더

헤더필수 여부설명
APIKEY✅ 예API 인증 키

쿼리 매개변수

매개변수유형필수 여부설명
taskIdlong✅ 예작업 생성 엔드포인트가 반환한 작업 ID

📥 요청 예제#

cURL
bash
curl -X GET "https://api.ideal.house/api/v1/smartReplace/result?taskId=1234567890123456789" \
  -H "APIKEY: your_api_key_here"
Java (OkHttp)
java
import okhttp3.*;
import java.io.IOException;

public class SmartReplaceResultExample {

    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/smartReplace/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/smartReplace/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 ended with status:", status)
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/smartReplace/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 ended with status:', status);
      }
      break;
    }

    // Wait 3 seconds before next poll
    await new Promise(resolve => setTimeout(resolve, 3000));
  }
}

pollResult(1234567890123456789n);

📤 응답#

성공 응답 (작업 완료)

json
{
  "code": 0,
  "message": "success",
  "data": {
    "id": 1234567890123456789,
    "status": "Success",
    "waitNumber": 0,
    "percentage": 100,
    "input": {
      "imageUrl": "https://example.com/room.jpg",
      "prompt": "a modern velvet sofa in dark blue",
      "maskUrl": "https://example.com/mask.png"
    },
    "output": {
      "resultUrl": "https://cdn.ideal.house/output/smart_replace_result.jpg",
      "width": 1024,
      "height": 1024
    }
  }
}

응답 (작업 처리 중 / 대기열에 있음)

json
{
  "code": 0,
  "message": "success",
  "data": {
    "id": 1234567890123456789,
    "status": "Processing",
    "waitNumber": 1,
    "percentage": 45,
    "input": {
      "imageUrl": "https://example.com/room.jpg",
      "prompt": "a modern velvet sofa in dark blue",
      "maskUrl": "https://example.com/mask.png"
    },
    "output": null
  }
}

응답 (작업 실패)

json
{
  "code": 0,
  "message": "success",
  "data": {
    "id": 1234567890123456789,
    "status": "Failed",
    "waitNumber": 0,
    "percentage": 0,
    "input": {
      "imageUrl": "https://example.com/room.jpg",
      "prompt": "a modern velvet sofa in dark blue",
      "maskUrl": "https://example.com/mask.png"
    },
    "output": null
  }
}

응답 필드

필드유형설명
idlong작업 고유 식별자
statusstring현재 작업 상태 (작업 상태 참조)
waitNumberinteger대기열에서 앞에 있는 작업 수 (0은 현재 처리 중임을 의미함)
percentageinteger작업 완료 비율 (0–100)
inputobject작업의 원래 입력 매개변수
input.imageUrlstring원본 이미지 URL
input.promptstring교체 콘텐츠를 설명하는 텍스트 프롬프트
input.maskUrlstring마스크 이미지 URL (maskUrl로 제공된 경우)
outputobject생성 결과 (statusSuccess일 때만 제공됨)
output.resultUrlstring스마트 교체 결과 이미지 URL
output.widthinteger출력 너비(픽셀)
output.heightinteger출력 높이(픽셀)

📊 작업 상태#

상태설명
Unprocessed작업이 생성되었지만 아직 시작되지 않음
Processing작업이 현재 처리 중
Success작업이 성공적으로 완료되어 출력 사용 가능
Failed오류로 작업이 실패함

3-5초마다 폴링하세요. API 작업 제한을 참고하세요.


❌ 오류 응답#

모든 오류 응답은 동일한 JSON 구조를 사용합니다.

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

오류 코드 참조#

코드이름설명권장 조치
1001FAILED요청 실패 (일반 오류)구체적인 오류 내용은 message 필드 확인
1003INTERNAL_ERROR내부 서버 오류잠시 후 재시도하고 계속 발생하면 지원팀에 문의
1011PARAM_ERROR요청 매개변수 오류 — 예: prompt 또는 마스크 누락prompt와 하나 이상의 마스크 필드가 모두 제공되었는지 확인
5002API_KEY_INVALID유효하지 않거나 누락된 API 키APIKEY 헤더가 있고 값이 올바른지 확인
9010SCAN_TEXT_ERROR텍스트 프롬프트가 콘텐츠 검토를 통과하지 못함민감하거나 금지된 콘텐츠를 제거하도록 프롬프트 수정
9038PROHIBITED_CONTENT생성된 출력 이미지에 금지된 콘텐츠가 포함됨프롬프트/스타일/입력을 조정하고 재시도
9051COINS_NOT_ENOUGH코인 / 크레딧 부족계정 크레딧을 충전하고 재시도

📄 전체 공통 API 오류 코드 목록은 오류 코드 참조를 참고하세요.