期間限定年間メンバーシップで30% オフさらに GPT Image、MiniMax H3 などが無制限
新登場 AI Chat · 毎日無料お試し回数を付与
今すぐアップグレード
Pixmind

PixMind API入門:Node.jsで画像生成を始める

タスクIDの保存からポーリング、重複課金につながる再送の防止まで

目次

画像生成リクエストが受け付けられても、画像が完成したとは限りません。アプリケーションではタスクIDを保持し、同じタスクの状態を確認する必要があります。また、リクエストの失敗や中断に対処する際、意図せず別のジョブを開始しないようにしなければなりません。

このチュートリアルでは、その一連の処理を行う小さなサーバー側のNode.jsクライアントを作成します。submitresume を別々のコマンドにし、一方はタスクを作成し、もう一方は既存タスクの確認だけを行います。まず確認するのは、ホームページのバナーからコピーしたモデル名ではなく、APIでサポートされているモデルIDです。

ここで扱うのは、テキストからの画像生成です。参照ファイルのアップロード、ブラウザー画面の実装、モデル品質の測定は行いません。検証には、ローカルでの29件のモックテストと、2026年9月4日に実施した、実行範囲を限定した本番環境での画像生成タスク1件を用いました。そのタスクでは画像1枚が返され、APIの課金記録には120ポイントの引き落としが記録されました。これは特定の日に行った1件の連携確認であり、速度ベンチマーク、すべての条件に当てはまる料金、別のアカウントでの利用可否を保証するものではありません。

カバー画像は2026年9月4日に撮影したモデルカタログのスクリーンショットです。撮影時点の参考画像として扱ってください。現在の料金や利用可否を保証するものではありません。

重要なポイント

  • APIキーはサーバー上に保管し、ブラウザー向けのバンドルや公開リポジトリには含めないでください。
  • 画像タスクでは、受け付け時のレスポンスから数値の data.taskId を読み取り、後続の問い合わせに備えて保存します。
  • 保存したタスクを ready または failed になるまでポーリングします。data.images から画像URLを取得するのは、成功を確認した後だけです。
  • クライアントのタイムアウトは、リモートのタスクが失敗した、あるいはキャンセルされたことを意味しません。タスクIDがあれば問い合わせを再開し、状況を確認せずに作成リクエストを繰り返さないでください。

このガイドの内容

始める前に

Node.js、APIキー、API課金の設定済みアカウントを用意し、非公開のターミナルまたはサーバー環境で作業してください。付属のサンプルは組み込みの fetch とJavaScriptモジュールを使用するため、外部パッケージのインストールは不要です。NodeのグローバルAPIドキュメントには、このクライアントが個々のリクエストの時間制限に使用する fetchAbortSignal.timeout の説明があります。ローカルでの検証環境はWindowsとNode.js v22.22.1 です。これはテスト環境の記録であり、他のすべてのバージョンで動作確認済みという意味ではありません。

ファイルの編集、環境変数の設定、JSONの読み取りに慣れていることを前提とします。先に、インストールされているランタイムを確認してください。

node --version

このコマンドは、インストール済みのバージョンを表示します。生成APIへの通信は行いません。後半に掲載するクライアントのソースコード全体を、作業フォルダー内の examples/pixmind-image.mjs として保存し、その作業フォルダーから各コマンドを実行してください。

テスト用のプロンプトには、顧客データや機密情報を含まない、問題のない内容を選びます。このチュートリアルではスタジオ背景に置いた陶器のコーヒーカップを使うため、参照ファイルのアップロードは不要です。送信前に、選んだモデルの現在のAPI料金を確認してください。Studioのクレジット、サブスクリプション、API課金を相互に使い回せると考えてはいけません。適用されるAPIの提供内容はモデルカタログで確認できます。

対話形式で画像を作成したいだけなら、Image Agentガイドでその手順を紹介しています。ここで作るクライアントは、モデルIDを明示的に指定し、レスポンスを自ら処理するアプリケーション向けです。

モデルの選択とAPIキーの設定

APIでサポートされているモデルIDと、そのモデルで利用できるパラメーターを使用してください。この例では、APIクイックスタートの画像リクエストに合わせて、nano-banana-proaspectRatio: "1:1"resolution: "1K" を指定します。2026年9月4日に行った認証付きの GET /models と本番テストでは、テストアカウントでこの組み合わせを確認しました。実際に実行する前に、ご自身のアカウントでの利用可否とパラメーターの対応状況を再確認してください。モデル名の文字列だけを変更しても、リクエストの他の部分が引き続き有効であるとは限りません。

APIコンソールでキーを作成し、サーバープロセスに PIXMIND_API_KEY として渡します。利用できる場合は、非公開のシークレット管理の仕組みを使ってください。以下はプレースホルダーを使った環境変数の設定例であり、有効な認証情報ではありません。

PowerShellの場合:

$env:PIXMIND_API_KEY = "REPLACE_WITH_YOUR_PRIVATE_API_KEY"
$env:PIXMIND_MODEL = "nano-banana-pro"
$env:PIXMIND_PROMPT = "A ceramic coffee cup on a plain studio background, soft side lighting, no text"

Bashの場合:

export PIXMIND_API_KEY="REPLACE_WITH_YOUR_PRIVATE_API_KEY"
export PIXMIND_MODEL="nano-banana-pro"
export PIXMIND_PROMPT="A ceramic coffee cup on a plain studio background, soft side lighting, no text"

これらの代入は、現在のシェルと、そこから起動するプロセスを設定するものです。タスクは作成しません。実際のシークレットを入力するときは、シェルの履歴や録画への露出に注意し、ソース管理にコミットしないでください。開発用と本番用のキーの分離や、漏えい後のキーローテーションについては、認証ガイドに従ってください。

このチュートリアルで使用するベースURLは次のとおりです。

https://aihub-admin.aimix.pro/api-platform/v1

このベースURLに /generations または /tasks/{taskId} を追加します。/v1 を重複して追加しないでください。モデルの一覧は GET /models で取得できますが、パラメーターを選ぶ前にモデルごとの機能を確認するなら、カタログの方が便利です。

cURLで最初の画像生成リクエストを送信する

cURLによるリクエストは、Node.jsの submit コマンドの代替手段です。事前に必ず実行するセットアップ手順ではありません。どちらも生成リクエストを送信するため、両方を実行すると課金対象のタスクが2件作成される可能性があります。cURLで送信した場合は、その後、返されたタスクIDを指定してNode.jsの resume コマンドを使用してください。

この例はBashの構文です。PowerShellでは、Bashの行継続構文をそのままターミナルに貼り付けず、後述するNode.jsクライアントを使用してください。

curl --connect-timeout 10 --max-time 30 \
  --request POST \
  'https://aihub-admin.aimix.pro/api-platform/v1/generations' \
  --header "Authorization: Bearer $PIXMIND_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
    "model": "nano-banana-pro",
    "type": "image",
    "prompt": "A ceramic coffee cup on a plain studio background, soft side lighting, no text",
    "aspectRatio": "1:1",
    "resolution": "1K"
  }'

このcURLのリクエストボディ内にあるプロンプトとパラメーターは、直接記述した固定値です。PIXMIND_PROMPT を変更しても、このJSONは変わりません。その環境変数を読み取るのはNode.jsクライアントです。この違いを理解すると、送信するリクエストの内容と、その周囲にあるシェルの設定を区別できます。

以下は、受け付け時のレスポンスを説明用に簡略化した例です。IDはプレースホルダーで、本番テストのIDではありません。12345 を問い合わせ対象にしないでください。

{
  "code": 1000,
  "message": "success",
  "data": {
    "id": "img_12345",
    "taskId": 12345
  }
}

本番テストで確認したメディア関連のレスポンスでは、成功時のデータが codemessagedatatimestamp を持つオブジェクトに格納されていました。説明用の例ではタイムスタンプなどのフィールドを省略しています。このワークフローで成功と判断するには、HTTPレスポンスの成功と、アプリケーションレベルの有効なレスポンスの両方が必要です。読み取るのは data.id ではなく、data.taskId です。前者には img_12345 のような接頭辞付きの文字列が入ることがありますが、タスク照会のパスでは数値IDを使います。

数値IDはすぐに保存してください。IDを受け取る前にリクエストがタイムアウトした場合は、いったん停止し、アカウントのタスク記録またはサポートを通じて送信結果を確認します。何が起きたかを調べる代わりにPOSTを繰り返すのは、安全な方法ではありません。

タスクのポーリングで画像URLを取得する

既存のタスクが終了状態に達するまで問い合わせます。非同期タスクのドキュメントでは、pendingprocessingreadyfailed が説明されています。このポーリング処理を終了するのは、最後の2つだけです。

Submit once
    |
Save numeric taskId
    |
GET /tasks/{taskId} <--- wait, then query again
    |                            ^
    +--- pending / processing ---+
    |
    +--- ready  ---> read images, stop
    |
    +--- failed ---> report failure, stop

Bashで手動照会する場合は、プレースホルダーのIDをご自身のIDに置き換えてください。

TASK_ID="REPLACE_WITH_YOUR_NUMERIC_TASK_ID"
curl --connect-timeout 10 --max-time 30 \
  "https://aihub-admin.aimix.pro/api-platform/v1/tasks/$TASK_ID" \
  --header "Authorization: Bearer $PIXMIND_API_KEY"

現在のメディアレスポンス仕様では、必要な各フィールドの役割が異なります。

フィールド このクライアントでの役割
data.taskId 既存タスクの照会に使う数値の識別子
data.status 待機を続けるか、結果を読み取るか、失敗として停止するかの判断に使う状態
data.images ready になった後に使用する、生成画像のURL配列
data.videoUrl 動画の出力フィールド。画像結果の配列ではない

ready のレスポンスであっても、有効な画像URLがなければ、アプリケーションにとって画像生成の成功とはいえません。調査できるように、タスクIDとともにこの不整合を報告してください。サンプルURLで代用したり、画像をダウンロードしたと報告したりしてはいけません。

このクライアントは返された画像URLを表示します。画像ファイルの取得や保存は行いません。アプリケーションで長期保存が必要なら、別の手順として設計し、関連するアセットの保持条件と利用規約を確認してください。URLが存在するだけで、永続的な保存が保証されているとは判断できません。

Node.jsの画像生成サンプルを実行する

新しいタスクを1件作成するには submit を、既存のタスクには resume を使用します。引数なしでスクリプトを実行すると、使い方を表示するだけでAPIは呼び出しません。この既定の動作により、通常の再起動やCLIの簡単な確認で、新しいジョブが作成されるのを防ぎます。

以下のソースコード全体を examples/pixmind-image.mjs として保存してください。

Node.jsのソースコード全体:pixmind-image.mjs
import { pathToFileURL } from 'node:url';

const BASE_URL = 'https://aihub-admin.aimix.pro/api-platform/v1';
const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

export class ApiError extends Error {
  constructor(message, { status = 0, transient = false, retryAfterMs = 0 } = {}) {
    super(message);
    Object.assign(this, { status, transient, retryAfterMs });
  }
}

export function parseTaskId(value) {
  if (!/^\d+$/.test(String(value))) throw new Error('Use a numeric taskId, not img_...');
  const id = Number(value);
  if (!Number.isSafeInteger(id) || id <= 0) throw new Error('Invalid taskId');
  return id;
}

export function retryAfter(value, now) {
  if (!value) return 0;
  if (/^\d+(\.\d+)?$/.test(value)) return Number(value) * 1000;
  const date = Date.parse(value);
  return Number.isFinite(date) ? Math.max(0, date - now) : 0;
}

export function createClient({
  apiKey,
  fetchImpl = fetch,
  now = Date.now,
  wait = sleep,
  random = Math.random,
  requestTimeoutMs = 30_000,
  pollTimeoutMs = 300_000,
  maxConsecutiveErrors = 5,
} = {}) {
  if (typeof apiKey !== 'string' || !apiKey.trim()) throw new Error('Set PIXMIND_API_KEY');

  async function request(path, method, payload, timeoutMs = requestTimeoutMs) {
    let response;
    let body;
    try {
      response = await fetchImpl(`${BASE_URL}${path}`, {
        method,
        redirect: 'error',
        headers: {
          Authorization: `Bearer ${apiKey}`,
          ...(payload ? { 'Content-Type': 'application/json' } : {}),
        },
        ...(payload ? { body: JSON.stringify(payload) } : {}),
        signal: AbortSignal.timeout(Math.max(1, Math.ceil(timeoutMs))),
      });
      // Read the body inside the timeout/network error boundary as well.
      body = await response.text();
    } catch {
      throw new ApiError('Network error or request timeout', { transient: true });
    }
    let envelope;
    try { envelope = JSON.parse(body); } catch { /* handle below */ }
    const transient = response.status === 429 || response.status >= 500;
    if (!response.ok) {
      // Do not echo arbitrary server bodies, prompts, credentials, or output URLs.
      throw new ApiError(`HTTP ${response.status}; inspect the account and request`, {
        status: response.status,
        transient,
        retryAfterMs: retryAfter(response.headers.get('retry-after'), now()),
      });
    }
    if (!envelope || typeof envelope !== 'object') {
      throw new ApiError('Expected a JSON API response');
    }
    if (envelope.code !== 1000 || !envelope.data) {
      throw new ApiError('API returned an unsuccessful or incomplete envelope');
    }
    return envelope.data;
  }

  async function submit({ model = 'nano-banana-pro', prompt } = {}) {
    if (typeof model !== 'string' || !model.trim()) throw new Error('A model is required');
    if (typeof prompt !== 'string' || !prompt.trim()) throw new Error('A prompt is required');
    try {
      const data = await request('/generations', 'POST', {
        model, type: 'image', prompt, aspectRatio: '1:1', resolution: '1K',
      });
      // The public media contract returns a number, not the prefixed display ID.
      if (typeof data.taskId !== 'number') throw new Error('Missing numeric taskId');
      return parseTaskId(data.taskId);
    } catch (error) {
      // A timeout or malformed response does not prove that creation failed.
      throw new Error(`Submission not confirmed: ${error.message}. No automatic retry was made. Check task records before submitting again.`);
    }
  }

  async function poll(taskId) {
    const id = parseTaskId(taskId);
    const deadline = now() + pollTimeoutMs;
    let attempts = 0;
    let errors = 0;
    const timedOut = () => new Error(`Stopped waiting for task ${id}; it may still be running. Resume this ID later.`);
    while (now() < deadline) {
      let retryFloor = 0;
      let task;
      try {
        task = await request(`/tasks/${id}`, 'GET', undefined,
          Math.min(requestTimeoutMs, deadline - now()));
        errors = 0;
      } catch (error) {
        if (now() >= deadline) throw timedOut();
        if (!(error instanceof ApiError) || !error.transient) throw error;
        errors += 1;
        if (errors >= maxConsecutiveErrors) {
          throw new Error(`Stopped after ${errors} consecutive query errors for task ${id}; resume this ID later.`);
        }
        retryFloor = error.retryAfterMs;
      }
      if (now() >= deadline) throw timedOut();
      if (task) {
        if (task.taskId !== id) throw new Error('Task response ID does not match the requested task');
        if (task.status === 'failed') throw new Error(`Task ${id} failed; inspect its record before creating another task.`);
        if (task.status === 'ready') {
          if (!Array.isArray(task.images) || task.images.length === 0 ||
              !task.images.every(url => {
                try { return ['https:', 'http:'].includes(new URL(url).protocol); }
                catch { return false; }
              })) throw new Error(`Task ${id} is ready but has no valid image URLs`);
          return task.images;
        }
        if (!['pending', 'processing'].includes(task.status)) {
          throw new Error(`Task ${id} returned an unrecognized status; inspect its record.`);
        }
      }
      // Client policy, not a PixMind latency guarantee or server-side retry feature.
      const ceiling = Math.min(10_000, 1_000 * 2 ** Math.min(attempts++, 4));
      const delay = Math.max(retryFloor, ceiling * (0.5 + 0.5 * random()));
      const remaining = deadline - now();
      if (delay >= remaining) {
        // Never poll earlier than Retry-After just to fit the local deadline.
        await wait(Math.max(0, remaining));
        throw timedOut();
      }
      await wait(delay);
    }
    throw timedOut();
  }

  return { submit, poll };
}

export async function main(args = process.argv.slice(2), env = process.env, deps = {}) {
  const log = deps.log ?? console.log;
  const [mode, rawId] = args;
  if (!mode) {
    log('Usage: node examples/pixmind-image.mjs submit | resume TASK_ID');
    return;
  }
  if (!((mode === 'submit' && args.length === 1) || (mode === 'resume' && args.length === 2))) {
    throw new Error('Use submit, or resume followed by a numeric taskId');
  }
  const resumeId = mode === 'resume' ? parseTaskId(rawId) : undefined;
  const client = createClient({ ...deps, apiKey: env.PIXMIND_API_KEY });
  const id = resumeId ?? await client.submit({
    model: env.PIXMIND_MODEL || 'nano-banana-pro',
    prompt: env.PIXMIND_PROMPT || 'A studio photograph of an unbranded ceramic coffee cup on a plain background',
  });
  // Save this line in your application record before relying on the polling process.
  log(`TASK_ID=${id}`);
  log(`Resume without a new generation: node examples/pixmind-image.mjs resume ${id}`);
  const images = await client.poll(id);
  log(JSON.stringify({ taskId: id, images }, null, 2));
}

if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
  main().catch(error => { console.error(error.message); process.exitCode = 1; });
}

まず、何も送信せずにコマンドの使い方を確認します。

node examples/pixmind-image.mjs

キー、モデルのパラメーター、想定される料金を確認したら、タスクを1件作成します。

node examples/pixmind-image.mjs submit

作成に成功すると、クライアントは画像の完成を待つ前に、すぐに TASK_ID を表示します。実際の値を非公開の場所に控えてください。この例ではファイルやデータベースに永続化しないため、出力を保存せずにターミナルを閉じると、処理再開に必要なIDが分からなくなる可能性があります。

タスクへの問い合わせを続けるには、12345 を保存した値に置き換えます。

node examples/pixmind-image.mjs resume 12345

このコマンドが行うのは、タスクへのGETリクエストだけです。新しいプロンプトを読み取って別の画像を作成することはありません。正常に終了した場合は、ご自身のタスクの出力URLが表示されるはずです。ここでは、架空の本番出力をベンチマークとして掲載していません。

この例では、HTTPリクエストごとの制限を30秒、ポーリング全体の期限を5分に設定しています。GETの再試行には、ジッター付きの指数バックオフ、ローカルでのバックオフ上限10秒、該当する場合は有効な Retry-After レスポンスヘッダーを使用します。サーバーがそれより長い待機時間を指定した場合は、その時間を優先します。ローカルの期限内に待機しきれなければ、指定時間より早く問い合わせることなく停止します。一時的なGETエラーが5回連続すると、その試行を終了します。つまり、連続するエラーに対して再試行するのは4回までです。これらはクライアントの設定値であり、サービスレベル契約でも、すべての画像が5分以内に完成するという約束でもありません。

アプリケーションに合った全体の待機方針を選んでください。長時間実行されるジョブは、ターミナルのセッションやWebリクエストが終わった後も継続する場合があります。デプロイ済みのサービスでは、自前のジョブ記録と一緒にタスクIDを保存し、ブラウザーに別のステータス確認用エンドポイントを提供しましょう。ユーザーに1本の接続を開いたまま待たせる必要はありません。

有料ジョブを重複させずにエラーへ対処する

タスクが作成されたか分からない状態と、ステータス照会の失敗は、区別して扱います。タスク照会のGETは繰り返しても別の生成処理を作成しません。一方、作成用のPOSTでレスポンスを受け取れなかった場合、処理はすでに始まっている可能性があります。そのため、この例ではPOSTを自動再送しません。

発生した状況 次の対応
HTTP 400 リクエストの形式、モデルID、対応パラメーターを確認してから、再試行するかを判断する。
HTTP 401 または 403 認証とアクセス権を確認する。デバッグ中もキーをログに出力しない。
タスク照会でHTTP 404 保存した数値IDと、そのタスクを所有するアカウントを確認する。他人のタスクIDで代用しない。
タスクのGETでHTTP 429 有効な Retry-After ヘッダーと、クライアントに設定した上限付きの再試行方針に従って待機する。
タスクのGETでネットワークエラーまたは一時的なサーバーエラー バックオフを挟んで同じ照会を再試行し、設定した上限に達したら停止する。
タスクのステータスが failed 問い合わせを停止してタスクの失敗を報告する。新たな生成を行うかは、別途判断する。
作成時のタイムアウト、不正なJSON、または taskId の欠落 作成結果は不明として扱う。再送信する前にタスク記録を確認する。

すべてのエラーが同じレスポンス形式を返すとは考えないでください。9月4日の本番確認では、認証なしの GET /models はHTTP 401 と、codemessage だけを含むレスポンスを返しました。一方、認証付きで成功したメディア関連のレスポンスには、datatimestamp も含まれていました。このため、このチュートリアルでは、すべてのレスポンスに requestIdretryable フラグ、料金フィールドがあるとは保証していません。上記の他のエラーケースはクライアント側の対処を説明したものであり、各ケースを本番環境で再現したという意味ではありません。HTTPステータスと、存在する場合は機密情報を除去したアプリケーションメッセージを保持してください。不正なボディはエラーとして扱い、JSON.parse の内部で処理が落ちたままにならないようにします。

ポーリングのタイムアウトは、クライアントが待機をやめたという意味であり、リモートのタスクがキャンセルされたという意味ではありません。IDを保持し、後で再開してください。未知のステータスも成功の証拠にはなりません。このクライアントは停止し、確認のためにその状態を報告します。switch文で値を扱っていなかったからといって、そのまま「完了」と判断してはいけません。

トラブルシューティングのために、タスクID、モデルID、操作、HTTPステータス、おおよその時刻を残します。認証ヘッダーや、非公開のプロンプトを含むリクエストボディ全体は記録しないでください。診断用のレスポンスボディや出力URLを共有する前に、機密情報が含まれていないか確認します。

動画・チャットに応用する場合の違い

動画でも送信後にポーリングする考え方は使えますが、リクエストの検証と結果の読み取りは動画専用に実装する必要があります。画像用ボディのフィールドをそのまま流用せず、選択した動画モデルが必要とする入力メディア、長さ、解像度、音声オプションを確認してください。完成した動画の取得に使うのは data.images ではなく、data.videoUrl です。

Video Agentガイドでは、対話形式の制作ワークフローを説明しています。生成を自動化する前に、どのようなショットが必要かを整理するうえで役立ちます。ただし、Agentに機能があることは、同名のAPIパラメーターが存在する証拠にはなりません。

チャットは別の連携方式です。ドキュメントに記載された /chat/completions はOpenAI互換のルートで、チャットレスポンスを返します。ストリーミングを指定した場合はストリームを返します。そのレスポンスを、画像クライアントの data.taskId パーサーに渡してはいけません。ベースURLが同じでも、すべてのエンドポイントのレスポンス構造が同じとは限りません。

画像生成の処理を検証できるまでは、クライアントの役割をそこに限定してください。動画用アダプターやチャットクライアントは、それぞれのレスポンス形式を検証するテストとともに別途追加します。返されたオブジェクトが画像タスク、動画タスク、チャットメッセージのどれなのかを1つの関数で推測するより、分離した方が動作を把握しやすくなります。

API連携を検証し、次のステップを決める

ローカルのモックテストなら、API残高を消費せずにクライアントの動作を確認できます。付属のテストスイートは、記載したWindowsとNode.jsの環境で29件すべてに合格しました。検証対象には、POSTを1回だけ行う送信処理、GETのみの再開処理、不正なレスポンス、タスクの最終的な失敗、期限、再試行上限が含まれます。付属のテストファイルクライアントのソースコードと同じ場所に保存し、チュートリアルのフォルダーからテストスイートを実行してください。

node --test examples/pixmind-image.test.mjs

モックテストでは、本番環境での利用可否や課金は確認できません。これとは別に、2026年9月4日、同じクライアントを使って実行範囲を限定した確認を行い、以下の内容を記録しました。

テスト項目 確認した結果
リクエスト nano-banana-protype: "image"aspectRatio: "1:1"resolution: "1K" を使用した POST /generations 1回
プロンプト A studio photograph of an unbranded ceramic coffee cup on a plain background
再開用の識別情報 ポーリング前に数値のタスクID 64114 を保存。これは検証記録の参照用であり、読者が問い合わせるためのIDではない
完了 同じタスクに対してGETを8回実行。最終ステータスは ready で、data.images にURLが1件含まれていた
出力の確認 返された画像は1,024 × 1,024ピクセルで読み込め、無地の背景に陶器のカップが写っていることを目視で確認した
課金 APIの料金レスポンスはこの設定に対して120ポイントを提示し、タスクに紐づくAPI利用台帳には120ポイントの引き落としが記録されていた

この確認では、既存のプロジェクトAPIキーを1つと、機密情報を含まないプロンプトを使用しました。参照ファイルのアップロードも、作成リクエストの自動再試行も行っていません。利用台帳の記録はタスクIDと照合しており、Studioの残高表示から推測したものではありません。実環境でテストしたのは、この1つの設定と、画像生成が成功する処理だけです。動画、チャット、失敗時の課金、返金、繰り返し実行した際の信頼性は検証していません。この過去の課金額を継続的な提示価格とみなさず、ご自身で送信する前に料金を再確認してください。

この例を実際のユーザー向けワークフローに組み込む前に、次の点を確認します。

  • キーがサーバー上に留まり、クライアントのバンドル、スクリーンショット、公開ログに含まれていない。
  • 選んだモデルとすべてのパラメーターが、現在のAPIでサポートされている。
  • 送信が受け付けられた後に、再開に使える数値のタスクIDを保持できる。
  • resume は、一時的な照会エラーの後も含め、作成用のPOSTを行わない。
  • タスクの失敗、空の結果、ローカルでのタイムアウトが、それぞれ異なる診断結果として扱われる。
  • 作成レスポンスを受け取れなくても、自動で2回目の送信を行わない。

ご自身で実行範囲を限定した実環境の確認を行う場合は、アカウント、モデル、承認済みの費用範囲、機密情報を除去したリクエスト、タスクID、終了時のレスポンス、実際の課金記録を残してください。URLの存在確認とは別に、出力そのものも確認します。新たな送信ごとに有料の処理が発生する可能性を考慮せず、「スモークテスト」を繰り返さないでください。

準備ができたら、APIキーを作成し、送信方法を1つ選びます。キュー、アップロード、バッチ処理を追加する前に、保存したタスクを使うワークフローを土台にしてください。次のステップが、生成したアセットを制作物のレビュー工程に組み込むことなら、Canvasを使った商品広告の制作ワークフローが、人の操作を中心とした別の例として参考になります。ただし、CanvasプロジェクトをこのAPIから実行できると約束するものではありません。

編集責任: このチュートリアルの組織としての著者名はPixMind Editorial Teamです。根拠としているのは、公式ドキュメント、プロジェクトのメディアコントローラー実装、ローカルでの29件のモックテスト、前述した本番確認1件であり、すべて2026年9月4日にレビューしました。機密情報を除去したタスク記録と課金記録は、編集上の検証のために保管しています。個々のエンジニアの資格や経歴、モデル品質の比較結果、性能ベンチマークを主張するものではありません。


Wan 3.0 動画完全ガイド:入力、音声、料金、API

继续浏览中,生成器即将加载...