実装 · モバイルTry-On
iOSまたはAndroidアプリにバーチャルtry-onを追加する
要約
PhottaのAPIキーはバックエンドに保持します。商品画像とマネキンIDを受け取り、/api/v1/tryon/apparelへ転送し、生成IDをユーザーに紐づけて保存し、モバイルアプリが画像生成完了まで3秒ごとにpollingするステータスendpointを公開するプロキシendpoint(/mobile/try-on)を用意します。スマートフォン側にPhottaキーの存在が知られることはありません。
- Credits: 2Kで5 credits · 4Kで6 credits
- 所要時間の目安: 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')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.statusimport os, requests
res = requests.post(
"https://api.photta.app/api/v1/tryon/apparel",
headers={"Authorization": f"Bearer {os.environ['PHOTTA_API_KEY']}"},
json={
"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."
},
)
data = res.json()["data"] # data["id"], data["status"]仕組み
デバイス、バックエンド、Photta — 3つの層、1つのフロー
最初のApp Store申請前に下すべき5つの具体的な決定事項。
ステップ 1
キーはサーバー上に保持する
アプリバイナリ、info.plist、AndroidManifest、またはいかなるビルド時の環境変数ファイルにもPhottaキーを含めないでください。バイナリの逆コンパイルは容易であり、キーが漏洩します。キーを置くべき場所はバックエンドのみです。
ステップ 2
クリーンなプロキシendpointを設計する
アプリに対して /mobile/try-on を公開します。リクエストは独自のユーザーセッションで認証し、プロキシ経由で生のAPIキーを渡さないでください。プロキシは認証済みユーザーの代理としてPhottaを呼び出します。
ステップ 3
データベースにPhottaのジョブステータスをミラーリングする
Phottaが生成IDを返したら、user_idをキーとして独自のジョブテーブルに行を挿入します。モバイルアプリはPhottaのendpointではなく、自社の /mobile/try-on/:id をpollingするため、rate limitは各ユーザーのデバイスごとではなく、自社の契約plansに応じてスケールします。
ステップ 4
結果URLをキャッシュする
Phottaがcompletedを返したら、output_urlをジョブ行にコピーし、必要に応じてバイトデータを独自のCDNにダウンロードします。モバイルユーザーはMB単位で通信料を支払います — PDP表示の全期間にわたってPhottaのCDNへ直リンクしないでください。
ステップ 5
オフライン状態を適切に処理する
モバイルネットワークはpollingの途中で切断されます。致命的なエラーを表示するのではなく「再試行中」の状態を表示し、指数バックオフでリトライを行い、ジョブIDをローカルに永続化して、コールドスタート時でも前回のセッションの中断箇所から再開できるようにします。
統合の3つのレイヤー
アプリのコントラクト、バックエンドプロキシ、クライアント側のpolling — 必要とされる正確な境界線。
// 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 } immediatelyconst 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キーをアプリバンドル内に含める必要があり、アプリをインストールするすべてのデバイスにキーを配布することになります。キーを自身が管理するサーバー上にとどめるため、自社のバックエンドを経由させてください。
低速なモバイルネットワークはどのように処理すればよいですか?
2つの対策があります。1つ目:ジョブの投入はデバイスからではなくバックエンドから行います — スマートフォンからは自社APIへ商品画像をアップロードするだけです。2つ目:自社のステータスendpointを3秒間隔でpollingし、失敗時には指数バックオフを適用します。ユーザーがタブを切り替えたり電波を失ったりした場合に備え、ジョブIDをローカルストレージに保持して復帰時に再開できるようにします。
PhottaはWebhookに対応していますか?
対応していません。このAPIが提供する完了シグナルはpollingのみであるため、ワーカーのループを維持してください — そしてバックエンド側でジョブの完了を確認した瞬間に、Server-Sent Eventsでスマートフォンへプッシュ通知します。
PhottaをReact NativeやFlutterで使用できますか?
はい — 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キーを取得し、午後のひとときでプロキシを配線しましょう。