구현 가이드 · 모바일 Try-On

iOS 또는 Android 앱에 가상 try-on 추가하기

한 줄 요약

Photta API 키는 백엔드에 보관하세요. 제품 이미지와 마네킹 ID를 받아 /api/v1/tryon/apparel로 전달하고, 사용자별로 생성 ID를 저장하며, 모바일 앱이 이미지가 준비될 때까지 3초마다 폴링할 수 있는 상태 엔드포인트를 노출하는 프록시 엔드포인트(/mobile/try-on)를 구현하세요. 휴대폰에서는 Photta 키의 존재 자체를 알 필요가 없습니다.

  • 크레딧: 2K에서 5 크레딧 · 4K에서 6 크레딧
  • 일반적인 소요 시간: 1.5–4 min
  • 처리 방식: 비동기, 폴링

이 페이지의 모든 수치는 다음 출처를 기반으로 합니다: Photta API 문서 · 확인 완료

디바이스는 Photta와 직접 통신하지 않습니다. 디바이스는 백엔드와 통신하고, 백엔드가 Photta와 통신합니다. 이 경계가 있어야 API 키가 사용자 휴대폰에 노출되지 않고, rate limit을 자체적으로 관리할 수 있으며, 모든 스토어에서 앱 심사를 통과할 수 있습니다.

RESPONSE=$(curl -s -X POST https://api.photta.app/api/v1/tryon/apparel \
  -H "Authorization: Bearer $PHOTTA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "product_type": "top",
  "product_images": [
    "https://cdn.yourstore.com/products/shirt-front.jpg"
  ],
  "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
  "product_category": "t_shirt",
  "mannequin_id": "mnk_f3a9b1",
  "pose_id": "pose_c2d4e5",
  "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
  "lock_background": true,
  "resolution": "2K",
  "aspect_ratio": "3:4",
  "body_size": "M",
  "expression": "neutral",
  "user_instruction": "Keep the collar pattern crisp and centered."
}')
ID=$(echo "$RESPONSE" | jq -r '.data.id')

동작 원리

디바이스, 백엔드, Photta — 3계층, 단일 플로우

첫 App Store 제출 전에 결정해야 할 5가지 구체적 사항.

  1. 단계 1

    서버에 키 보관하기

    앱 바이너리, info.plist, AndroidManifest 또는 빌드 타임 환경 변수 파일 내에 Photta 키를 포함하지 마세요. 바이너리 디컴파일은 매우 간단하여 키가 유출될 수 있습니다. 키가 존재해야 하는 곳은 오직 백엔드뿐입니다.

  2. 단계 2

    깔끔한 프록시 엔드포인트 설계

    앱에 /mobile/try-on을 노출하세요. 원시 API 키를 프록시로 전달하지 말고 자체 사용자 세션으로 요청을 인증하세요. 그런 다음 프록시가 인증된 사용자를 대신하여 Photta를 호출합니다.

  3. 단계 3

    데이터베이스에 Photta 작업 상태 미러링

    Photta가 생성 ID를 반환하면 user_id를 키로 하여 자체 jobs 테이블에 행을 삽입하세요. 모바일 앱은 Photta가 아닌 '자체' /mobile/try-on/:id를 폴링하므로 rate limit은 각 사용자의 디바이스가 아니라 '귀사'의 플랜에 맞춰 확장됩니다.

  4. 단계 4

    결과 URL 캐싱

    Photta가 completed를 반환하면 output_url을 jobs 행에 복사하고, 필요에 따라 바이트 데이터를 자체 CDN으로 다운로드하세요. 모바일 사용자는 MB당 요금을 지불합니다. PDP 노출 기간 내내 Photta CDN으로 핫링크하지 마세요.

  5. 단계 5

    오프라인 상태에 유연하게 대응

    모바일 네트워크는 폴링 중에 끊길 수 있습니다. 치명적인 오류 대신 '재시도 중' 상태를 표시하고, 지수 백오프로 재시도하며, 이전 세션이 중단된 지점부터 콜드 스타트 시 이어갈 수 있도록 작업 ID를 로컬에 영속화하세요.

연동의 3가지 계층

앱 인터페이스 규격, 백엔드 프록시, 클라이언트 측 폴링 — 개발에 필요한 정확한 아키텍처 경계입니다.

// Never ship your PHOTTA_API_KEY to the device. The mobile app
// calls YOUR API; your API calls Photta. Simple, safe, billable.
POST /mobile/try-on
{
  "productImageUrl": "...",
  "mannequinId": "...",
  "poseId": "..."
}
// → returns { jobId } immediately
const res = await fetch("https://api.photta.app/api/v1/tryon/apparel", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.PHOTTA_API_KEY}`, "Content-Type": "application/json" },
  body: JSON.stringify({
    "product_type": "top",
    "product_images": [
      "https://cdn.yourstore.com/products/shirt-front.jpg"
    ],
    "product_back_image": "https://cdn.yourstore.com/products/shirt-back.jpg",
    "product_category": "t_shirt",
    "mannequin_id": "mnk_f3a9b1",
    "pose_id": "pose_c2d4e5",
    "background": "https://cdn.yourstore.com/backgrounds/studio-loft.jpg",
    "lock_background": true,
    "resolution": "2K",
    "aspect_ratio": "3:4",
    "body_size": "M",
    "expression": "neutral",
    "user_instruction": "Keep the collar pattern crisp and centered."
  }),
});
const { data } = await res.json(); // data.id, data.status
// Store { id: data.id, user_id, status: "processing" } in your jobs table
// and return { jobId: data.id } to the device.
// App polls YOUR /mobile/try-on/:id — you poll Photta server-side
// and mirror status. This way rate limits are YOUR problem, not
// each device's, and you can add caching + analytics in one place.
async function pollJob(jobId: string) {
  while (true) {
    const { status, imageUrl } = await api.get(`/mobile/try-on/${jobId}`);
    if (status === "completed") return imageUrl;
    if (status === "failed") throw new Error("Try-on failed");
    await sleep(3000);
  }
}

개발자가 자주 묻는 질문

Photta 기반 모바일 기능 배포하기

디바이스에서 Photta API를 직접 호출할 수 있나요?

기술적으로는 가능하지만, 앱 번들 내에 API 키를 포함해야 하므로 앱을 설치하는 모든 디바이스에 키가 노출됩니다. 직접 제어할 수 있는 서버에 키를 보관할 수 있도록 자체 백엔드를 거치도록 라우팅하세요.

느린 모바일 네트워크는 어떻게 처리하나요?

두 가지 조치가 필요합니다. 첫째: 디바이스가 아닌 백엔드에서 작업을 제출하세요. 휴대폰에서는 자체 API로 제품 이미지만 업로드하면 됩니다. 둘째: 3초 간격 및 실패 시 지수 백오프를 적용하여 자체 상태 엔드포인트를 폴링하세요. 사용자가 탭을 전환하거나 신호를 잃을 경우, 다시 돌아왔을 때 이어갈 수 있도록 작업 ID를 로컬 스토리지에 유지하세요.

Photta는 웹훅을 지원하나요?

아니요. API가 제공하는 완료 신호는 폴링뿐이므로 워커 루프를 유지해야 합니다. 그리고 자체 백엔드에서 작업 완료를 확인하는 즉시 휴대폰으로 서버 전송 이벤트(SSE)를 푸시하세요.

React Native나 Flutter에서 Photta를 사용할 수 있나요?

예 — JavaScript / Dart 관점에서는 자체 백엔드 API를 호출하기만 하면 됩니다. Photta 관련 세부 구현은 클라이언트에 노출되지 않습니다. Flutter 앱도 React Native나 네이티브 SwiftUI / Jetpack Compose 앱과 동일한 방식으로 /mobile/try-on을 호출(fetch)합니다.

Apple 심사 팀에서 이 연동 방식을 문제 삼나요?

아니요 — 앱이 Photta를 직접 호출하지 않기 때문입니다. 자체 인증을 갖춘 자체 백엔드를 호출합니다. Apple의 관점에서 보면 일반적인 REST 기반 앱에 불과합니다. Google Play 및 Huawei AppGallery에도 동일하게 적용됩니다.

다음 앱 릴리스에 가상 try-on 기능 배포하기

3개의 얇은 계층으로 디바이스에 추가되는 SDK 부담이 전혀 없습니다. API 키를 발급받아 반나절 만에 프록시를 연결해 보세요.