API Reference
OPS/iO Portrait API
このページはエンドポイント実装と同じスキーマ定義から自動描画されています。(最終描画: 2026年8月24日)
開発者クイックスタート
数分で最初のリクエストを送れます。開発者ダッシュボードで開発者登録し、API キーを発行してください。
ベース URL: https://io.order-photo.com/api
curl -X POST https://io.order-photo.com/api/v1/generations \
-H "Authorization: Bearer ops_sk_..." \
-H "Content-Type: application/json" \
-d '{ "profile_id": "b6a4f6de-0000-0000-0000-000000000001", "style_preset_id": "a1f0c9aa-0000-0000-0000-000000000003", "framing": "bust-up", "aspect_ratio": "3:4", "count": 1, "quality": "high" }'1. 開発者ダッシュボード(/developers)で開発者登録し、決済方法を登録して API を有効化します(従量課金サブスクリプションが作成されます)。2. 「API キー」ページでキーを発行します(ops_sk_... — 表示は発行時の 1 回だけ)。3. 上のクイックスタートを実行します。Teams 契約組織は組織ダッシュボードの「設定 → API 連携」からも同じ操作ができます。
認証
すべてのリクエストに Authorization ヘッダで API キーを渡します。キーは組織単位で発行され、漏洩時はダッシュボードから即座に失効できます。
Authorization: Bearer ops_sk_...料金
基本料なしの純従量制です。課金は成功したものにのみ発生します — 失敗したビルドや失敗した生成には課金されません。
| 項目 | 単価(税込) | 課金タイミング |
|---|---|---|
| プロファイル作成(PAA 構築) | ¥1,100 / 件 | 構築成功時のみ(失敗は無課金) |
| 画像生成 | ¥300 / 枚 | 生成完了時、納品枚数分のみ |
想定外の課金を防ぐため、月間生成枚数の上限(hard cap、既定 1,000 枚)を組織ごとに設定できます。上限到達後のリクエストは 402 hard_cap_reached で拒否されます。
レート制限
読み取り系 120 リクエスト/分・書き込み系(プロファイル作成・生成)20 リクエスト/分(API キー単位)。超過時は 429 と Retry-After ヘッダを返します。
非同期処理モデル
プロファイル構築と画像生成は非同期ジョブです(生成は平均 2〜3 分)。完了の受け取りは 2 通り: (1) GET エンドポイントのポーリング(推奨間隔 5 秒以上)、(2) Webhook(下記)。
Webhook
POST /v1/webhook-endpoints で配信先を登録すると、イベント発生時に JSON が POST されます。配信は最大 5 回(指数バックオフ)リトライされます。ペイロードには機微情報を含めないため、詳細は id を使って API から取得してください。
イベント種別
profile.ready/profile.failedgeneration.completed/generation.failed
署名の検証
各配信には X-Opsio-Signature ヘッダ(t=<unix秒>,v1=<HMAC-SHA256 hex>)が付きます。登録時に 1 回だけ返される secret(whsec_...)で次のように検証します。
import { createHmac, timingSafeEqual } from "crypto";
function verify(secret, rawBody, signatureHeader) {
const m = signatureHeader?.match(/^t=(\d+),v1=([0-9a-f]{64})$/);
if (!m) return false;
const [, t, v1] = m;
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; // replay guard
const expected = createHmac("sha256", secret)
.update(`${t}.${rawBody}`, "utf8")
.digest("hex");
const a = Buffer.from(expected, "hex");
const b = Buffer.from(v1, "hex");
return a.length === b.length && timingSafeEqual(a, b);
}MCP サーバー
OPS/iO はリモート MCP(Model Context Protocol)サーバーを提供しています。Claude などの AI エージェントからツールとして直接この API を操作できます(Streamable HTTP・認証は同じ API キー)。課金・レート制限・月間上限は API と共通です。
https://io.order-photo.com/api/mcp接続方法
Claude Code から接続する場合:
claude mcp add --transport http opsio https://io.order-photo.com/api/mcp \
--header "Authorization: Bearer ops_sk_..."claude.ai / Claude Desktop の場合は「カスタムコネクタ」に上記 URL を追加し、Authorization ヘッダに API キーを設定します。
提供ツール
各ツールは対応する API エンドポイントの薄いラッパーです(仕様・エラー・課金は各エンドポイントの項を参照)。
| ツール | 対応エンドポイント | 内容 |
|---|---|---|
list_styles | GET /v1/styles | スタイルカタログ取得 |
create_profile | POST /v1/profiles | プロファイル(PAA)作成 |
get_profile | GET /v1/profiles/{id} | プロファイルの状態取得 |
list_profiles | GET /v1/profiles | プロファイル一覧 |
create_generation | POST /v1/generations | ポートレート生成 |
get_generation | GET /v1/generations/{id} | 生成の状態・結果取得 |
list_generations | GET /v1/generations | 生成一覧 |
get_usage | GET /v1/usage | 当月の使用量取得 |
エラーコード
エラーは常に次の封筒で返ります。message は英語です。
{
"error": {
"code": "hard_cap_reached",
"message": "...",
"doc_url": "https://io.order-photo.com/docs/api#errors-hard_cap_reached"
}
}| code | HTTP | 内容 |
|---|---|---|
unauthorized | 401 | API キーが無効か、失効しています。 |
forbidden_scope | 403 | この API キーには要求された操作のスコープがありません。 |
api_disabled | 403 | この組織では API が有効化されていません。ダッシュボードの設定から有効化してください。 |
invalid_request | 400 | リクエストボディまたはクエリパラメータが不正です。 |
not_found | 404 | 指定されたリソースが見つかりません。 |
profile_not_ready | 409 | プロファイルの構築が完了していません。status が ready になってから生成してください。 |
hard_cap_reached | 402 | 当月の生成上限(hard cap)に達しました。上限はダッシュボードから変更できます。 |
rate_limited | 429 | レート制限を超過しました。Retry-After ヘッダの秒数だけ待って再試行してください。 |
photo_fetch_failed | 422 | photos[].url からの画像取得に失敗しました。公開 HTTPS URL を指定してください。 |
enqueue_failed | 503 | ジョブの投入に失敗しました。消費分は返還済みです。時間をおいて再試行してください。 |
internal_error | 500 | サーバー内部エラーが発生しました。 |
エンドポイント
プロファイル
POST/v1/profilesスコープ: profiles:write
プロファイル(PAA)を作成
ソース写真からパーソナル AI アセット(PAA)を構築します。写真は公開 HTTPS URL で渡し、サーバー側で取得・保存します。構築は非同期で、完了すると status が ready になり、Webhook(profile.ready)でも通知されます。face_only モードは顔 4 アングル(face_front / face_front_smile / face_left45 / face_right45)、full モードは 12 アングルすべてが必要です。課金(¥1,100)は構築成功時のみ発生します。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
display_name | body | string | ✓ | プロファイル表示名(30文字以内) |
capture_mode | body | "full" | "face_only" | — | face_only は顔4アングル、full は12アングル必須 |
photos | body | object[] | ✓ | 必須アングルぶんのソース写真 |
photos[].angle | body | "front" | "left45" | "right45" | "back" | "face_front" | "face_front_smile" | "face_front_up" | "face_left45" | "face_right45" | "face_left90" | "face_right90" | "face_oblique" | ✓ | 写真のアングル |
photos[].url | body | string | ✓ | 公開 HTTPS URL |
リクエスト例
curl -X POST https://io.order-photo.com/api/v1/profiles \
-H "Authorization: Bearer ops_sk_..." \
-H "Content-Type: application/json" \
-d '{ "display_name": "Sato Hanako", "capture_mode": "face_only", "photos": [ { "angle": "face_front", "url": "https://example.com/photos/front.jpg" }, { "angle": "face_front_smile", "url": "https://example.com/photos/smile.jpg" }, { "angle": "face_left45", "url": "https://example.com/photos/left45.jpg" }, { "angle": "face_right45", "url": "https://example.com/photos/right45.jpg" } ] }'レスポンス例
{
"id": "b6a4f6de-0000-0000-0000-000000000001",
"status": "pending",
"display_name": "Sato Hanako",
"capture_mode": "face_only",
"progress_pct": 0,
"created_at": "2026-08-12T00:00:00Z",
"updated_at": "2026-08-12T00:00:00Z"
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403) · api_disabled (403) · invalid_request (400) · photo_fetch_failed (422) · enqueue_failed (503)
GET/v1/profilesスコープ: read
プロファイル一覧
この組織の API 経由で作成されたプロファイルを新しい順に返します。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
limit | query | integer (1–100) | — | 取得件数 |
before | query | string | — | カーソル(ISO 日時) |
リクエスト例
curl -X GET https://io.order-photo.com/api/v1/profiles \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"data": [
{
"id": "b6a4f6de-0000-0000-0000-000000000001",
"status": "ready",
"display_name": "Sato Hanako",
"capture_mode": "face_only",
"created_at": "2026-08-12T00:00:00Z"
}
],
"has_more": false
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403)
GET/v1/profiles/{id}スコープ: read
プロファイルの状態取得
プロファイルの構築状態をポーリングします。status: pending → generating → ready / failed。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
id | path | uuid | ✓ | — |
リクエスト例
curl -X GET https://io.order-photo.com/api/v1/profiles/<id> \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"id": "b6a4f6de-0000-0000-0000-000000000001",
"status": "ready",
"display_name": "Sato Hanako",
"capture_mode": "face_only",
"progress_pct": 100,
"created_at": "2026-08-12T00:00:00Z",
"updated_at": "2026-08-12T00:05:00Z"
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403) · not_found (404)
DELETE/v1/profiles/{id}スコープ: profiles:write
プロファイルを削除
プロファイルと、そこから生成された画像・ソース写真をすべて削除します。取り消せません。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
id | path | uuid | ✓ | — |
リクエスト例
curl -X DELETE https://io.order-photo.com/api/v1/profiles/<id> \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"deleted": true
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403) · not_found (404)
生成
POST/v1/generationsスコープ: generations:write
ポートレートを生成
ready 状態のプロファイルからポートレートを生成します。非同期処理で、完了は GET /v1/generations/{id} のポーリングか Webhook(generation.completed)で受け取ります。課金(¥300/枚)は完了した枚数分のみ発生します。1 生成あたり平均 2〜3 分かかります。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
profile_id | body | uuid | ✓ | ready 状態のプロファイル id |
style_preset_id | body | uuid | null | — | スタイルプリセット id |
scene_id | body | uuid | null | — | シーン id(任意) |
framing | body | "full" | "knee-up" | "half" | "bust-up" | "face-up" | null | — | face-up only |
aspect_ratio | body | "1:1" | "3:4" | "4:5" | "9:16" | "4:3" | "3:2" | "16:9" | null | — | アスペクト比 |
count | body | integer (1–4) | — | 生成枚数(1〜4) |
quality | body | "medium" | "high" | — | high は 2K 解像度 |
リクエスト例
curl -X POST https://io.order-photo.com/api/v1/generations \
-H "Authorization: Bearer ops_sk_..." \
-H "Content-Type: application/json" \
-d '{ "profile_id": "b6a4f6de-0000-0000-0000-000000000001", "style_preset_id": "a1f0c9aa-0000-0000-0000-000000000003", "framing": "bust-up", "aspect_ratio": "3:4", "count": 1, "quality": "high" }'レスポンス例
{
"id": "e2d81f77-0000-0000-0000-000000000002",
"status": "processing",
"profile_id": "b6a4f6de-0000-0000-0000-000000000001",
"count": 1,
"created_at": "2026-08-12T00:10:00Z"
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403) · api_disabled (403) · invalid_request (400) · not_found (404) · profile_not_ready (409) · hard_cap_reached (402) · enqueue_failed (503)
GET/v1/generationsスコープ: read
生成一覧
この組織の API 経由の生成を新しい順に返します。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
limit | query | integer (1–100) | — | 取得件数 |
before | query | string | — | カーソル(ISO 日時) |
リクエスト例
curl -X GET https://io.order-photo.com/api/v1/generations \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"data": [
{
"id": "e2d81f77-0000-0000-0000-000000000002",
"status": "completed",
"profile_id": "b6a4f6de-0000-0000-0000-000000000001",
"images": [
{
"url": "https://…(1時間有効の署名URL)",
"expires_in": 3600
}
],
"created_at": "2026-08-12T00:10:00Z",
"completed_at": "2026-08-12T00:12:30Z"
}
],
"has_more": false
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403)
GET/v1/generations/{id}スコープ: read
生成の状態・結果取得
生成の状態をポーリングします。completed になると images に署名付き URL(1 時間有効)が入ります。URL の期限が切れたら同じエンドポイントを再取得してください。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
id | path | uuid | ✓ | — |
リクエスト例
curl -X GET https://io.order-photo.com/api/v1/generations/<id> \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"id": "e2d81f77-0000-0000-0000-000000000002",
"status": "completed",
"profile_id": "b6a4f6de-0000-0000-0000-000000000001",
"progress_pct": 100,
"images": [
{
"url": "https://…(1時間有効の署名URL)",
"expires_in": 3600
}
],
"created_at": "2026-08-12T00:10:00Z",
"completed_at": "2026-08-12T00:12:30Z"
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403) · not_found (404)
カタログ・使用量
GET/v1/stylesスコープ: read
スタイルカタログ取得
生成に指定できるスタイルプリセットの一覧を返します。各スタイルの id を POST /v1/generations の style_preset_id に渡します。
リクエスト例
curl -X GET https://io.order-photo.com/api/v1/styles \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"data": [
{
"id": "a1f0c9aa-0000-0000-0000-000000000003",
"name": "ビジネス・スタジオ",
"category": "business",
"follow_pose": false
}
]
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403)
GET/v1/usageスコープ: read
当月の使用量取得
当月の API 使用量(生成消費枚数・hard cap 残量)と概算金額を返します。
リクエスト例
curl -X GET https://io.order-photo.com/api/v1/usage \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"period_images_used": 42,
"period_profiles_built": 3,
"hard_cap_images": 1000,
"hard_cap_remaining": 958,
"estimated_charges_jpy": 15900,
"unit_prices": {
"profile_jpy": 1100,
"image_jpy": 300
}
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403)
Webhook 配信先
POST/v1/webhook-endpointsスコープ: webhooks:manage
Webhook 配信先を登録
イベント配信先 URL を登録します。レスポンスの secret(whsec_...)は署名検証に使います — この時だけ平文で返され、以後取得できません。配信は X-Opsio-Signature ヘッダ(HMAC-SHA256)で署名されます。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
url | body | string | ✓ | 配信先 URL(HTTPS のみ) |
events | body | "profile.ready" | "profile.failed" | "generation.completed" | "generation.failed"[] | — | 購読イベント(省略時は全イベント) |
リクエスト例
curl -X POST https://io.order-photo.com/api/v1/webhook-endpoints \
-H "Authorization: Bearer ops_sk_..." \
-H "Content-Type: application/json" \
-d '{ "url": "https://example.com/webhooks/opsio", "events": [ "generation.completed", "generation.failed" ] }'レスポンス例
{
"id": "c3b2a1d0-0000-0000-0000-000000000004",
"url": "https://example.com/webhooks/opsio",
"events": [
"generation.completed",
"generation.failed"
],
"secret": "whsec_(この時だけ表示)",
"active": true
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403) · invalid_request (400)
GET/v1/webhook-endpointsスコープ: read
Webhook 配信先一覧
登録済みの配信先を返します。secret は含まれません。
リクエスト例
curl -X GET https://io.order-photo.com/api/v1/webhook-endpoints \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"data": [
{
"id": "c3b2a1d0-0000-0000-0000-000000000004",
"url": "https://example.com/webhooks/opsio",
"events": [
"generation.completed",
"generation.failed"
],
"active": true
}
]
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403)
DELETE/v1/webhook-endpoints/{id}スコープ: webhooks:manage
Webhook 配信先を削除
配信先を削除します。以後この URL への配信は行われません。
パラメータ
| 名前 | 位置 | 型 | 必須 | 説明 |
|---|---|---|---|---|
id | path | uuid | ✓ | — |
リクエスト例
curl -X DELETE https://io.order-photo.com/api/v1/webhook-endpoints/<id> \
-H "Authorization: Bearer ops_sk_..."レスポンス例
{
"deleted": true
}エラー: unauthorized (401) · rate_limited (429) · internal_error (500) · forbidden_scope (403) · not_found (404)
メタ
GET/v1/openapi.json
OpenAPI 3.1 仕様書
この API の OpenAPI 3.1 仕様を返します。認証不要。仕様はレジストリからリクエスト時に生成されるため常に最新です。
リクエスト例
curl https://io.order-photo.com/api/v1/openapi.jsonレスポンス例
{
"openapi": "3.1.0",
"info": {
"title": "OPS/iO Portrait API"
}
}OpenAPI 仕様
機械可読な OpenAPI 3.1 仕様を配布しています。Postman やコード生成ツールにそのまま読み込めます(認証不要・常に最新)。
GET https://io.order-photo.com/api/v1/openapi.json