技術ドキュメント

目次

認証フロー(HMAC + JWT)

概要

VTO API Serviceは、HMAC署名とJWTトークンを組み合わせた2段階の認証フローを採用しています。 まずサーバー側でHMAC署名を生成し、トークンエンドポイントからJWTを取得。その後、JWTを用いてWidgetを認証し、 VTOやステータス取得を行います。

ステップ1: HMAC署名の生成(サーバー側)

// 署名対象文字列: api_key|origin|timestamp(パイプ区切り)
message   = "api_XXXX-XXXX-XXXX-XXXX|https://your-ec-site.com|1710345600"
signature = hmac_sha256(message, shared_secret)

// PHP例:
$message   = $apiKey . '|' . $origin . '|' . $timestamp;
$signature = hash_hmac('sha256', $message, $sharedSecret);

パラメータ:

  • api_key: マイページで取得したAPIキー(api_XXXX-XXXX-XXXX-XXXX)
  • origin: ECサイトのオリジン(例: https://your-ec-site.com)
  • timestamp: 現在のUnixタイムスタンプ(秒)※ ±5分以内
  • shared_secret: マイページで確認できるシークレットキー

ステップ2: JWTトークンの取得

POST /API/api/token.php
Content-Type: application/json

{
    "api_key": "api_XXXX-XXXX-XXXX-XXXX",
    "origin": "https://your-ec-site.com",
    "timestamp": 1710345600,
    "signature": "hmac_sha256_hex_string"
}

レスポンス:

{
    "success": true,
    "data": {
        "widget_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
        "expires_in": 3600
    }
}

ステップ3: Widgetの初期化

取得した widget_token は Widget JS が自動で使用します。
お客様サーバーにプロキシPHPを設置し、Widget JS の tokenEndpoint に指定してください。

<script src="https://asp.kitemir.jp/API_SERVICES/widget/vto-widget.js"></script>
<link rel="stylesheet" href="https://asp.kitemir.jp/API_SERVICES/widget/vto-widget.css">
<script>
VtoWidget.init({
    tokenEndpoint: '/api/widget_token.php',  // お客様サーバーのプロキシPHP
    apiBase: 'https://asp.kitemir.jp/API_SERVICES'
});
</script>

<!-- 商品ページに試着ボタンを設置 -->
<button onclick="VtoWidget.open({
    garmentUrl: 'https://your-ec-site.com/images/product.webp',
    category: 'tops',
    productName: 'エレガントブラウス',
    productPrice: 12000,
    onAddToCart: function() { addToMyCart(123); }
})">試着してみる</button>

APIエンドポイント一覧

POST /API/api/token.php

概要: HMAC署名からJWTトークンを取得します

認証: HMAC署名

レート制限: 1IP/分あたり30リクエスト

POST /API/api/tryon.php

概要: バーチャル試着を実行します(非同期)

認証: Bearer JWT(widget_token)

Content-Type: multipart/form-data または application/json

パラメータ:

  • person_image (file/base64): ユーザーの身体写真(JPEG/PNG)
  • garment_url (string): 試着用服画像のURL(https://〜)
  • category (string): tops / bottoms / one-pieces / auto

注意: garment_url はURLを指定します(ファイルアップロードではありません)。サーバー側で画像をダウンロードして FASHN AI に送信します。

GET /API/api/status.php?tryon_id=xxx

概要: VTO実行のステータスを確認(ポーリング用)

認証: Bearer JWT

推奨ポーリング間隔: 2〜3秒

ステータス値:

  • queued: キュー待機中
  • processing: 処理中
  • completed: 完了(result_url / designer_comment 付き)
  • failed: 失敗(error_message 付き)

GET /API/api/verify.php?key=api_XXXX

概要: ライセンスキーの有効性確認(初期設定用・CORS対応)

認証: 不要(ライセンスキーのみ検証)

用途: 初期セットアップ画面でのキー検証

リクエスト・レスポンス例

例1: トークン取得(サーバー側プロキシから呼び出し)

リクエスト:

curl -X POST https://asp.kitemir.jp/API/api/token.php \
  -H "Content-Type: application/json" \
  -d '{
    "api_key": "api_1234-5678-9abc-def0",
    "origin": "https://your-ec-site.com",
    "timestamp": 1710345600,
    "signature": "a1b2c3d4e5f6..."
  }'

レスポンス(成功):

{
    "success": true,
    "data": {
        "widget_token": "eyJhbGciOiJIUzI1NiIs...",
        "expires_in": 3600
    }
}

例2: VTO実行

multipart/form-data 方式:

curl -X POST https://asp.kitemir.jp/API/api/tryon.php \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -F "person_image=@person.jpg" \
  -F "garment_url=https://your-ec-site.com/images/dress.webp" \
  -F "category=one-pieces"

JSON方式(base64):

curl -X POST https://asp.kitemir.jp/API/api/tryon.php \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{
    "person_image": "/9j/4AAQSkZJRg...(base64)",
    "garment_url": "https://your-ec-site.com/images/dress.webp",
    "category": "one-pieces"
  }'

レスポンス(成功):

{
    "success": true,
    "data": {
        "tryon_id": "pred_abc123def456",
        "status": "processing"
    }
}

例3: VTOステータス確認(完了時)

リクエスト:

curl -X GET "https://asp.kitemir.jp/API/api/status.php?tryon_id=vto_1710345678_abc123" \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

レスポンス(完了):

{
    "success": true,
    "data": {
        "status": "completed",
        "result_url": "https://cdn.fashn.ai/results/tryon_123456.jpg",
        "designer_comment": "このワンピースはあなたの優雅さを引き出しており、非常に素敵です。深い色合いは肌のトーンを美しく見せ、シルエットは体を的確にサポートしています。特に首周りのデザインは顔立ちを柔らかく見せています。",
        "cost_usd": 0.075
    }
}

カート連携(onAddToCart)

概要

VTO Widgetでは、試着結果画面に「カートに追加する」ボタンが表示されます。 このボタンがクリックされたときに実行される処理を onAddToCart コールバック関数で自由に定義できます。 お客様のECサイトのカートシステムに合わせて、AJAX送信やフォーム操作などを記述してください。

設定方法

onAddToCart は2つの場所で設定できます。

方法1: VtoWidget.open() で商品ごとに指定(推奨)

商品ページごとに異なるカート処理を定義できます。

<button onclick="VtoWidget.open({
    garmentUrl: 'https://your-site.com/images/blouse.webp',
    category: 'tops',
    productName: 'エレガントブラウス',
    productPrice: 12000,
    onAddToCart: function() {
        // ここに自社カートへの追加処理を記述
        addToMyCart(商品ID, サイズ, カラー);
    }
})">試着してみる</button>

方法2: VtoWidget.init() でグローバルに指定

全商品共通のカート処理を初期化時に設定します。open() で個別指定した場合はそちらが優先されます。

VtoWidget.init({
    tokenEndpoint: '/api/widget_token.php',
    apiBase: 'https://asp.kitemir.jp/API_SERVICES',
    onAddToCart: function() {
        // グローバルのカート追加処理
        alert('カートに追加しました');
    }
});

実装例

例1: fetch APIでカートに追加(AJAX)

onAddToCart: function() {
    fetch('/api/cart', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            product_id: 123,
            quantity: 1,
            size: 'M',
            color: 'ベージュ'
        })
    })
    .then(res => res.json())
    .then(data => {
        if (data.success) {
            // カートアイコンの数量を更新
            document.getElementById('cart-count').textContent = data.cart_count;
            alert('カートに追加しました');
        }
    });
}

例2: フォーム送信でカートに追加

onAddToCart: function() {
    var form = document.getElementById('cart-form');
    form.submit();
}

例3: 商品IDを動的に渡す(PHPと組み合わせ)

<?php foreach ($products as $product): ?>
<button onclick="VtoWidget.open({
    garmentUrl: '<?= $product['tryon_image_url'] ?>',
    category: '<?= $product['tryon_category'] ?>',
    productName: '<?= htmlspecialchars($product['name']) ?>',
    productPrice: <?= $product['price'] ?>,
    onAddToCart: function() {
        addToCart(<?= $product['id'] ?>);
    }
})">試着してみる</button>
<?php endforeach; ?>

ポイント: onAddToCart が実行された後、Widget は自動的に閉じます。 カート追加処理が非同期(AJAX)の場合でも、Widgetは即座に閉じるため、処理完了の通知はお客様のUI側で行ってください。

カラー連動(garmentUrls 使用時)

garmentUrls を使用して複数色を登録している場合、 onAddToCart コールバックの第1引数に、 ユーザーが選択中の色名(color フィールドの値)が自動で渡されます。

VtoWidget.open({
    garmentUrls: [
        { url: '/tryon/dress-ivory.webp', color: 'アイボリー' },
        { url: '/tryon/dress-black.webp', color: 'ブラック' }
    ],
    category: 'one-pieces',
    productName: 'ワンピース',
    productPrice: 8800,
    onAddToCart: function(selectedColor) {
        // selectedColor = 'ブラック'(ユーザーが選んだ色)
        fetch('/api/cart', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({
                product_id: 456,
                color: selectedColor,  // ← Widgetから受け取った色名
                quantity: 1
            })
        });
    }
});

単色(garmentUrl のみ)の場合、第1引数は null になります。

複数色対応(garmentUrls)

概要

同じ商品の色違い(最大7色)をWidget内で切り替えて試着できます。 garmentUrls 配列パラメータを使用すると、 試着服エリアに左右の矢印が表示され、ユーザーが色を選んでから試着を実行できます。

従来の garmentUrl(単一URL)も引き続きサポートしています。 garmentUrls が指定されていない場合は、矢印は表示されず従来通りの動作になります。

使用例

<button onclick="VtoWidget.open({
    garmentUrls: [
        { url: 'https://your-site.com/tryon/blouse-beige.webp', color: 'ベージュ' },
        { url: 'https://your-site.com/tryon/blouse-navy.webp',  color: 'ネイビー' },
        { url: 'https://your-site.com/tryon/blouse-black.webp', color: 'ブラック' },
        { url: 'https://your-site.com/tryon/blouse-wine.webp',  color: 'ワインレッド' }
    ],
    category: 'tops',
    productName: 'クルーネックセーター',
    productPrice: 12000,
    onAddToCart: function() { addToCart(); }
})">試着してみる</button>

パラメータ仕様

garmentUrls (Array) — 最大7件

  • url (String, 必須): 試着画像の絶対URL(https://〜)
  • color (String, 任意): 色名(「ベージュ」等)Widget内に表示
  • label (String, 任意): 表示ラベル(colorの代替)

動作仕様

  • 配列が2件以上 → 左右矢印+カラードット+色名ラベルが表示される
  • 配列が1件 → 矢印なし(単色と同じ挙動)
  • 配列が8件以上 → 先頭7件に切り詰め
  • 「試着する」ボタン押下時 → 現在表示中の色の画像でVTOが実行される
  • APIエンドポイントへの変更は不要(Widget内で選択色のURLを送信)

PHPで動的に構築する例

<?php
// 商品の色ごとに試着画像URLを配列化
$garmentUrls = [];
foreach ($product['colors'] as $color) {
    $garmentUrls[] = [
        'url'   => 'https://your-site.com/tryon/' . $product['sku'] . '-' . $color['slug'] . '.webp',
        'color' => $color['name'],
    ];
}
?>

<button onclick="VtoWidget.open({
    garmentUrls: <?= json_encode($garmentUrls, JSON_UNESCAPED_UNICODE) ?>,
    category: '<?= $product['vto_category'] ?>',
    productName: '<?= htmlspecialchars($product['name']) ?>',
    productPrice: <?= $product['price'] ?>,
    onAddToCart: function() { addToCart(<?= $product['id'] ?>); }
})">試着してみる</button>

画像の推奨仕様: 白背景・正面平置きのJPEGまたはWebP形式。推奨サイズ 1024×1024px以下。 モデル着用写真も使用可能ですが、白背景の平置き画像の方がVTO精度が高くなります。

後方互換性: 従来の garmentUrl(単一URL文字列)は引き続きサポートされます。 garmentUrls が指定されていない場合は、矢印は表示されず従来通りの動作です。 既存の実装を変更する必要はありません。

エラーコード参照

コード エラー名 説明
400 Bad Request リクエストパラメータが不正です
401 Unauthorized 認証に失敗しました(署名・トークン無効)
403 Forbidden ライセンスが無効またはプランが非アクティブ
402 Payment Required 月間VTO上限に達しました(プランのアップグレードが必要)
500 Internal Server Error サーバーエラー(お問い合わせください)
503 Service Unavailable VTOサービスが一時的に利用不可

💡 ヒント: すべてのエラーレスポンスは JSON形式で {"success": false, "error": "...", "code": 400} の形式で返されます。