Node.js · バーチャル試着 API

Node.js でのバーチャル試着 API

現在 @photta/node パッケージはありませんが、必要ありません。Node 18+ には `fetch` が標準搭載されており、20行のヘルパーを書くだけで、約5分で最初のモデル画像を生成できます。

要約

環境変数に `PHOTTA_API_KEY` を設定し、`Authorization: Bearer photta_live_xxx` を含めて `https://ai.photta.app/api/v1` を呼び出す小さな `phottaFetch()` ヘルパーを作成します。`/tryon/apparel` に商品画像URL、マネキンID、ポーズIDを POST し、`status === 'completed'` になるまで 3秒ごとに `/tryon/apparel/:id` をポーリングします(通常 1.5–4 分以内)。

更新日 · 2026-04-19

最初のリクエスト

Node.jsPythoncURLcURL
import { phottaFetch } from "./photta.js";

// 1. Submit the job — returns a generation ID immediately.
const created = await phottaFetch("/tryon/apparel", {
  method: "POST",
  body: JSON.stringify({
    product_type: "dress",
    product_images: ["https://example.com/dress.jpg"],
    mannequin_id: "mnq_athena_ts",
    pose_id: "pose_standing_front",
    resolution: "2K",
    aspect_ratio: "3:4",
  }),
});
const generationId = created.data.id;

// 2. Poll every 3 seconds until processing completes. Typical
// completion is 1.5–4 minutes; put an upper bound so a stuck
// job can't hang your request forever.
const pollInterval = 3000;
const maxAttempts = 120;     // 120 × 3s = 6 minutes
let result;

for (let i = 0; i < maxAttempts; i++) {
  result = await phottaFetch(`/tryon/apparel/${generationId}`);
  if (result.data.status === "completed") break;
  if (result.data.status === "failed") {
    throw new Error(result.data.error_message);
  }
  await new Promise((r) => setTimeout(r, pollInterval));
}

console.log("Result:", result.data.output_url);

期待される結果

Typical completion

1.5–4min

2K / 4K credits

5 / 7

Aspect ratios

5

Product types

6

仕組み

Node.js でのバーチャル試着 API

サインアップから最初の画像生成まで、5ステップ約5分。

  1. 01

    ステップ 1

    サインアップしてキーを生成する

    ai.photta.app でアカウントを作成します。ダッシュボードの Developers セクションで Generate API key をクリックし、`photta_live_` で始まる32文字のキーを取得します。

  2. 02

    ステップ 2

    キーはソースではなく環境変数に保存する

    `.env`(またはプラットフォームのシークレット管理)に `PHOTTA_API_KEY=...` を追加し、`process.env` 経由で読み込みます。キーをコミットしたり、`'use client'` と記述されたファイルにインポートしたりしないでください。ブラウザ側にキーが露出してしまいます。

  3. 03

    ステップ 3

    小さな fetch ヘルパーを作成する

    ベースURL、Authorization ヘッダー、JSON ボディ、エラーの正規化を処理する 20行程度の `fetch()` ラッパーを作成します。公式SDKがリリースされるまでは、この抽象化だけで十分です。

  4. 04

    ステップ 4

    試着ジョブを送信してポーリングする

    `/tryon/apparel` に `product_type`, `product_images`, `mannequin_id`, `pose_id`, `resolution`, `aspect_ratio` を含めて POST します。即座に返される生成IDを使用し、`status === 'completed'` になるまで 3秒ごとに `/tryon/apparel/:id` をポーリングします。

  5. 05

    ステップ 5

    結果を保存する

    完了時のペイロードには `output_url` と `thumbnail_url` が含まれます。バイトデータを一度取得して自社のオブジェクトストレージに保存してください。URLは安定していますが、レンダリングをPhottaのCDNに依存し続けるべきではありません。

エンドツーエンドのコード

Copy, paste, done.

Four snippets — install prerequisites, wrap the REST call, submit + poll, then handle the errors that actually happen in production.

01No SDK required — use native fetch in Node 18+
bash
# Node 18+ ships fetch natively. No install step needed.
node --version   # ensure v18 or later

# Optional: keep your API key out of source control
echo "PHOTTA_API_KEY=photta_live_xxxxx" >> .env
02Wrap the REST call in a tiny client helper
javascript
// photta.js — a 20-line wrapper you can reuse across your app.
const PHOTTA_BASE_URL = "https://ai.photta.app/api/v1";

export async function phottaFetch(path, init = {}) {
  const res = await fetch(`${PHOTTA_BASE_URL}${path}`, {
    ...init,
    headers: {
      "Authorization": `Bearer ${process.env.PHOTTA_API_KEY}`,
      "Content-Type": "application/json",
      ...init.headers,
    },
  });
  const body = await res.json();
  if (!res.ok) {
    const err = new Error(body?.error?.message ?? res.statusText);
    err.status = res.status;
    err.code = body?.error?.code;
    throw err;
  }
  return body;
}
03Submit a try-on job and poll until it lands
javascript
import { phottaFetch } from "./photta.js";

// 1. Submit the job — returns a generation ID immediately.
const created = await phottaFetch("/tryon/apparel", {
  method: "POST",
  body: JSON.stringify({
    product_type: "dress",
    product_images: ["https://example.com/dress.jpg"],
    mannequin_id: "mnq_athena_ts",
    pose_id: "pose_standing_front",
    resolution: "2K",
    aspect_ratio: "3:4",
  }),
});
const generationId = created.data.id;

// 2. Poll every 3 seconds until processing completes. Typical
// completion is 1.5–4 minutes; put an upper bound so a stuck
// job can't hang your request forever.
const pollInterval = 3000;
const maxAttempts = 120;     // 120 × 3s = 6 minutes
let result;

for (let i = 0; i < maxAttempts; i++) {
  result = await phottaFetch(`/tryon/apparel/${generationId}`);
  if (result.data.status === "completed") break;
  if (result.data.status === "failed") {
    throw new Error(result.data.error_message);
  }
  await new Promise((r) => setTimeout(r, pollInterval));
}

console.log("Result:", result.data.output_url);
04Handle 402 credit exhaustion and 429 rate limits
javascript
try {
  await phottaFetch("/tryon/apparel", {
    method: "POST",
    body: JSON.stringify({ /* … */ }),
  });
} catch (err) {
  if (err.status === 402) {
    // Out of credits — surface a top-up CTA to the user.
    // err.code === "insufficient_credits"
  } else if (err.status === 429) {
    // Rate-limited. Honour the Retry-After header.
    const retryAfter = err.retryAfter ?? 30;
    await new Promise((r) => setTimeout(r, retryAfter * 1000));
    // Then retry…
  } else if (err.status >= 500) {
    // Server-side issue — backoff + retry.
  }
  throw err;
}

この構成の理由

現時点でヘルパーがクライアントライブラリより優れている理由

  • Node 18+ ships native fetch — no runtime deps required
  • Same helper works inside Next.js route handlers, API routes, server actions and edge functions
  • Keep API keys in env; never import the helper from a 'use client' module or the bundler will leak them
  • Works with any queue/cron: BullMQ, Inngest, Trigger.dev, Vercel Cron, Cloudflare Queues

対象外の機能

Honest caveats

  • No official @photta/node SDK yet — REST is the only path today
  • No built-in webhook delivery; polling is the documented pattern (3–5s interval)
  • Bearer token lives in env; the API doesn't support OAuth client credentials yet

開発者からのよくある質問

Questions other developers ask

Photta 公式の Node.js SDK はありますか?+

まだありません。Photta のドキュメントでは、採用数に応じた SDK 開発を計画しています。Python はAPIユーザー10社、Node.js は20社が目安です。それまでは、cURL、Node ネイティブの fetch、Python の requests を使用した生の REST 連携が推奨されます。このページの20行のヘルパーは、主要なエンドポイントを利用するためのクライアントと同等の機能を持ちます。

どの Node.js バージョンがサポートされていますか?+

ネイティブ `fetch` をサポートする Node 18 以降です。Node 16 の場合は `node-fetch` でポリフィルするか、アップグレードしてください。コード自体はプレーンな ECMAScript 2020(async/await, テンプレートリテラル, 動的インポート)なので、その他のランタイム要件はありません。

Node からの認証方法は?+

すべてのリクエストに `Authorization: Bearer photta_live_xxx` を含めます。キーは本番用が `photta_live_`、サンドボックス用(提供開始後)が `photta_test_` で始まります。環境変数に保存し、`process.env.PHOTTA_API_KEY` で読み込んでください。現在、OAuth クライアント認証やセッションベースの認証はサポートしていません。

1.5–4 分の生成時間をどのように扱えばよいですか?+

試着エンドポイントは完全に非同期です。POST は即座に `status: 'processing'` と生成IDを返します。`status` が `completed` または `failed` になるまで、3–5秒ごとに `GET /tryon/apparel/:id` をポーリングしてください。ジョブがスタックしてリクエストが永久にハングするのを防ぐため、試行回数に上限(例:3秒間隔で120回)を設けることを推奨します。

Next.js 内で API を呼び出せますか?+

はい。ルートハンドラー (`app/**/route.ts`)、サーバーアクション (`'use server'`)、またはミドルウェアから呼び出せます。APIキーは必ずサーバー側に保持し、`'use client'` ファイルからヘルパーをインポートしないでください。Vercel の関数タイムアウトを超える長時間ジョブの場合は、ポーリングをキュー(Inngest, Trigger.dev, BullMQ)に委譲し、生成IDをブラウザに返してブラウザからステータスを確認させる構成にしてください。

API のエラーはどのように通知されますか?+

2xx 以外のレスポンスには、`type`, `code`, `message` およびサポート用のリクエストIDを含む JSON ボディが含まれます。典型的な例:400 invalid_request_error(`param` で不正なフィールドを指摘)、402 insufficient_credits(必要数と現在数を出力)、429 rate_limit_exceeded(`retry_after` 秒数と Retry-After ヘッダーを付与)。5xx エラーは指数バックオフによるリトライが推奨されます。

Node.js · バーチャル試着 API

アカウントを作成してAPIキーを取得

環境変数に `PHOTTA_API_KEY` を設定し、`Authorization: Bearer photta_live_xxx` を含めて `https://ai.photta.app/api/v1` を呼び出す小さな `phottaFetch()` ヘルパーを作成します。`/tryon/apparel` に商品画像URL、マネキンID、ポーズIDを POST し、`status === 'completed'` になるまで 3秒ごとに `/tryon/apparel/:id` をポーリングします(通常 1.5–4 分以内)。

Node.js 用バーチャル試着 API — Photta | Photta