> ## Documentation Index
> Fetch the complete documentation index at: https://docs.legitmark.com/llms.txt
> Use this file to discover all available pages before exploring further.

# プライベート CDN

> メディアが公開されないエンタープライズ組織向けの、署名付きアップロードおよび読み取り URL。

エンタープライズ組織では、認証用の写真と証明書を公開 CDN の外に置くことができます。アップロードはプライベートバケットに保存され、読み取りは CloudFront の署名付き URL を返します。公開シェアページには写真は表示されません。

サービスリクエストの作成・読み取り・提出は、これまでと同じパートナー API です。変わるのはアップロード経路とメディア URL の形だけです。

組織が公開 CDN を利用している場合は、通常の [ワークフロー](/ja/partner/workflow) のアップロード経路（`GET /intent`）を使用してください。

## 必要なスコープ

API キーには `sr:v2:create` と `sr:v2:read` に加えて `media:v2:private-read` が必要です。組織でプライベートメディアが有効になると、Legitmark がこのスコープを付与します。

以下のすべての呼び出しで同じ `leo_` キーを送信してください。

```javascript theme={null}
const headers = {
  'Authorization': 'Bearer leo_xxxxxxxxx',
  'Content-Type': 'application/json'
};
```

`media:v2:private-read` がない場合、プライベート CDN 組織では `GET /api/v2/sr/{sr_uuid}` の `media_url` は空配列、`certificate_url` は null になります。

## 統合ステップ

公開パートナー API と同じ流れです。違いは 2 点です。`/intent` を呼ばないこと、すべてのメディア URL を短命として扱うことです。

<Steps>
  <Step title="サービスリクエストを作成">
    通常のボディで `POST /api/v2/sr?sides=true&item=true` を `leo_` キー付きで呼び出します。`sides=true&item=true` を付けると、必須 / 任意の写真リストがレスポンスに含まれるため、アップロード前に再度取得する必要はありません。

    **API リファレンス：** [`POST /api/v2/sr`](/api-reference#tag/Service-Requests/operation/createServiceRequest)
  </Step>

  <Step title="写真をアップロード">
    すべてのサイドに対して `POST /api/media/signed-urls/{sr_uuid}` を 1 回呼び、返ってきた `signed_url` に画像を `PUT` します。`GET /intent` は呼び出さないでください。
  </Step>

  <Step title="写真を読み取る">
    同じキーで `GET /api/v2/sr/{sr_uuid}?item=true&sides=true` を呼び出します。`media_url`（`summary=true` の場合は `summary.thumbnail` も）は、約 15 分間有効な署名付きプライベート CDN リンクです。
  </Step>

  <Step title="証明書を読み取る">
    最新の Get Full SR の `certificate_url` を使います。`Access Denied` または `403` が返ったら再取得してください。ダッシュボードの **Download certificate** からも再発行できます。
  </Step>
</Steps>

## 写真のアップロード

`GET https://asset.legitmark.com/intent`（および開発・ステージングのアセットホスト）は呼び出さないでください。この経路は公開バケットに書き込み、プライベート組織のアップロードをルーティングできません。

すべてのサイドのアップロード URL を 1 回の呼び出しで取得し、各 URL に画像バイトを `PUT` します。

**API リファレンス：** [`POST /api/media/signed-urls/{sr_uuid}`](/api-reference#tag/Media-Management/operation/generateBatchSignedUrls)

<CodeGroup>
  ```javascript HTTP theme={null}
  const sides = requiredSides.map((side) => ({
    uuid: side.uuid,
    filename: `${side.uuid}.jpg`,
    content_type: 'image/jpeg'
  }));

  const signedResponse = await fetch(
    `https://api.legitmark.com/api/media/signed-urls/${srUuid}`,
    {
      method: 'POST',
      headers,
      body: JSON.stringify({
        sides,
        expires_in: 900
      })
    }
  );
  const { urls } = await signedResponse.json();

  for (const side of requiredSides) {
    const { signed_url } = urls[side.uuid];
    await fetch(signed_url, {
      method: 'PUT',
      body: imageFiles[side.uuid],
      headers: { 'Content-Type': 'image/jpeg' }
    });
  }
  ```

  ```bash cURL theme={null}
  curl -X POST "https://api.legitmark.com/api/media/signed-urls/SR_UUID" \
    -H "Authorization: Bearer leo_xxxxxxxxx" \
    -H "Content-Type: application/json" \
    -d '{
      "sides": [
        {
          "uuid": "SIDE_UUID",
          "filename": "SIDE_UUID.jpg",
          "content_type": "image/jpeg"
        }
      ],
      "expires_in": 900
    }'

  curl -X PUT "SIGNED_URL_FROM_ABOVE" \
    -H "Content-Type: image/jpeg" \
    --data-binary @photo.jpg
  ```
</CodeGroup>

**リクエストボディ**

| フィールド        | 型       | 必須  | 説明                                                                                                                   |
| ------------ | ------- | --- | -------------------------------------------------------------------------------------------------------------------- |
| `sides`      | array   | はい  | 写真ごとに 1 件。各要素には `uuid`（サイド UUID）と `filename`（`{side_uuid}.jpg`）が必要です。`content_type` は任意です（`image/jpeg`、`image/png`）。 |
| `expires_in` | integer | いいえ | アップロード URL の有効期限（秒）。デフォルトは `900`（15 分）。                                                                              |

**レスポンス**

```json theme={null}
{
  "success": true,
  "message": "Batch signed URLs generated successfully.",
  "urls": {
    "ec883c70-f896-47c9-81b6-8d6ff0b5856a": {
      "signed_url": "https://s3.us-east-1.amazonaws.com/...",
      "expires_at": "2026-09-01T08:15:00.000Z",
      "is_multipart": false
    }
  },
  "metadata": {
    "total_urls": 1,
    "failed_urls": 0,
    "sr_uuid": "8e61c991-553a-4a58-9eb6-561b64c11908",
    "expires_in": 900
  }
}
```

<Warning>
  `signed_url` への `PUT` に `Authorization` ヘッダーを送信しないでください。URL はすでに署名されているため、`Authorization` ヘッダーがあると S3 は `400` で拒否します。API キーで認証されるのは `POST /api/media/signed-urls/{sr_uuid}` のみです。
</Warning>

<Note>
  TypeScript SDK は現在も `GET /intent` を使用します。プライベート CDN の組織は、SDK が更新されるまで HTTP で `POST /api/media/signed-urls/{sr_uuid}` を呼び出してください。
</Note>

### ブラウザからのアップロード（CORS）

倉庫アプリや Web アプリがブラウザから画像を `PUT` する場合、S3 がそのページのオリジンを許可している必要があります。アップロードオリジンをすべて Legitmark に共有してください（完全一致のオリジンと `https://*.example.com` ワイルドカード）。組織で既に許可されているオリジンはそのまま使えます。`PUT` で CORS エラーが出た場合は新しいオリジンの追加が必要です。`/intent` にフォールバックしないでください。

## 写真の読み取り

同じ API キーでサービスリクエストを取得します。`media_url` はプライベート CDN ホスト上の CloudFront 署名付きリンクです。

**API リファレンス：** [`GET /api/v2/sr/{sr_uuid}`](/api-reference#tag/Service-Requests/operation/getServiceRequestV2)

<CodeGroup>
  ```javascript HTTP theme={null}
  const response = await fetch(
    `https://api.legitmark.com/api/v2/sr/${srUuid}?item=true&sides=true`,
    { headers }
  );
  const { sr } = await response.json();

  for (const side of sr.sides.required) {
    const latest = side.media_url.find((media) => media.is_latest);
    if (latest) {
      console.log(`${side.name}: ${latest.url}`);
    }
  }
  ```

  ```bash cURL theme={null}
  curl "https://api.legitmark.com/api/v2/sr/SR_UUID?item=true&sides=true" \
    -H "Authorization: Bearer leo_xxxxxxxxx"
  ```
</CodeGroup>

署名付き読み取り URL は次の形です（クエリ値は省略しています）。

```
https://staging-{org}-private-cdn.legitmark.com/org/{org_uuid}/sr/{sr_uuid}/{side_uuid}.jpg?Expires=1787907356&Key-Pair-Id=...&Signature=...
```

* `Expires`、`Key-Pair-Id`、`Signature` を URL から外さないでください。クエリ文字列を削除すると `403` になります。
* `summary=true` のときの `summary.thumbnail` も同じ方法で署名されます。
* 以前のテストで使った公開の `cdn.legitmark.com` リンクでは、これらの写真は配信されません。

## 証明書

最新の `GET /api/v2/sr/{sr_uuid}` の `certificate_url` は、同じプライベートホスト上の署名付き PDF リンクです。その URL を使用してください。`Access Denied` または `403` が返った場合は署名の期限切れです。もう一度 `GET` して新しい URL を使ってください。

ダッシュボード（`https://app.legitmark.com` または開発・ステージングのアプリホスト）の **Download certificate** からも新しいリンクを再発行できます。

以前保存した証明書リンクを再利用しないでください。

## URL の有効期限

署名付き読み取り URL は発行時点から **15 分** 有効です（`expires_in` のデフォルトは `900` 秒）。

* 署名付き URL をデータベースに保存したり、キャッシュしたりしないでください。
* 署名付き URL を恒久的な共有リンクとしてログや転送に使わないでください。URL を持っている人は期限までオブジェクトを取得できます。
* 写真や証明書を表示・ダウンロードするたびに、`GET /api/v2/sr/{sr_uuid}` を再実行してください。
* 期限切れまたは署名なしの URL は `403` を返します。これは想定どおりの動作です。新しい URL を取得してください。

Webhook のペイロードにメディア URL は含まれません。`state_change` を受け取ったら、写真や証明書が必要な場合は SR を取得してください。

## 公開シェアページ

公開シェアページには、プライベート CDN 組織の写真は表示されません。これは意図した動作です。写真と証明書は、API キー付きのパートナー API 経由でのみ利用できます。

| 環境     | シェアページ                                                |
| ------ | ----------------------------------------------------- |
| 開発     | `https://dev.app.legitmark.com/view?sr={sr_uuid}`     |
| ステージング | `https://staging.app.legitmark.com/view?sr={sr_uuid}` |
| 本番     | `https://app.legitmark.com/view?sr={sr_uuid}`         |

## 環境

| 環境     | API ホスト                             | プライベート CDN ホストの例                                  |
| ------ | ----------------------------------- | ------------------------------------------------- |
| 開発     | `https://dev.api.legitmark.com`     | `https://dev-{org}-private-cdn.legitmark.com`     |
| ステージング | `https://staging.api.legitmark.com` | `https://staging-{org}-private-cdn.legitmark.com` |
| 本番     | `https://api.legitmark.com`         | `https://{org}-private-cdn.legitmark.com`         |

`{org}` は Legitmark が組織向けにプロビジョニングしたホスト名に置き換えてください。CDN ホストを自分で組み立てず、API が返す URL を使用してください。

## 画像要件

公開ワークフローと同じです。

* **形式：** JPG/JPEG/PNG
* **サイズ：** 最小 600 x 600 ピクセル
* **ファイルサイズ：** 画像あたり最大 5 MB
* **品質：** 鮮明で、十分な照明、ピントが合った画像
