ライセンス公開APIドキュメント

v1.0

ライセンス公開APIドキュメント

このドキュメントは、自社ソフトウェアに「支払い → 発行 → アクティベーション → 検証」の一連の流れを組み込みたい開発者(クライアントソフトウェア / 販売委託製品)向けです。各APIについて呼び出しタイミング・リクエストパラメータ・レスポンス項目・エラーコードを説明します。

1. 基本概念

概念 項目 / 用語 説明
ソフトウェア発行APIシークレット licenseApiSecret 製品で「ライセンスアクティベーション」を有効にすると自動生成されます。デベロッパーセンターの製品編集フォームで確認できます。ソフトウェアサーバーはこれでHMAC署名を計算し、プラットフォームはこれで署名を検証します。サーバー側にのみ保存し、クライアントに埋め込まないでください。
ライセンスコード licenseCode プラットフォームが発行する一意のコードです。ユーザーはこれを使ってソフトウェアをアクティベートします。
マシンコード machineCode クライアントソフトウェアが生成するデバイス識別子です(PCごとに一意。安定したマシンフィンガープリントをハッシュ化することを推奨、8文字以上)。
アクティベーショントークン activationToken アクティベーション / 発行時にプラットフォームが発行するトークンです。ソフトウェアは保存し、起動検証のたびに送信します。
注文ID clientOrderId ソフトウェア内決済の注文ID(クライアントまたはサーバーが生成)。プラットフォームは「製品 + 注文ID」で冪等化し、二重課金・二重発行を防ぎます。

2. 導入準備

  1. 製品公開時に「ライセンスアクティベーション」を有効にし、生成された**ソフトウェア発行APIシークレット(licenseApiSecret)**を保存します;
  2. 公開フォームでエディション一覧(例: BASIC/PRO/ULTIMATE)とアップグレード戦略(SAME_CODE = 既存コードのままアップグレード / NEW_CODE = 新コードを発行)を設定します;
  3. シークレットはソフトウェアサーバーに保存し、クライアントにはライセンスコードとアクティベーショントークンのみを持たせます。

3. API一覧

ベースパス: https://www.powersoftware.app/frontApi(ローカル / テスト環境ではデプロイドメインに置き換えてください)。

API 呼び出しタイミング 認証 署名
POST /license/software/generate ソフトウェア内決済成功直後 なし(署名検証) 必須
POST /license/software/upgrade 更新 / エディションアップグレードの決済成功直後 なし(署名検証) 必須
POST /license/activate ユーザーの初回アクティベーション / 別マシンへの変更 なし 不要
POST /license/verify ソフトウェア起動のたび なし 不要
POST /license/deactivate ユーザーが旧デバイスをバインド解除(マイページ) ログイン 不要

4. 署名ルール(generate / upgrade で必須)

署名対象文字列: 以下のフィールドをこの順番で改行(\n)区切りで連結します(省略可能なフィールドは空値を使用: edition は空文字、expiryDays は 0):

productId \n machineCode \n edition \n expiryDays \n clientOrderId \n licenseCode \n timestamp

署名: HMAC-SHA256(ソフトウェア発行APIシークレット licenseApiSecret, 署名対象文字列) を計算し、Base64URL エンコードして signature フィールドに入れます。

リプレイ防止: timestamp はミリ秒タイムスタンプです。プラットフォームはサーバー時刻との差が5分以内であることを要求し、超過すると signatureInvalid を返します。

Node.js の例:

const crypto = require("crypto");
const payload = [productId, machineCode, edition, expiryDays, clientOrderId, licenseCode, timestamp].join("\n");
const signature = crypto.createHmac("sha256", API_SECRET).update(payload).digest("base64url");

Python の例:

import hashlib, hmac, base64
payload = "\n".join([str(productId), machineCode, edition, str(expiryDays), clientOrderId, licenseCode, str(timestamp)])
signature = base64.urlsafe_b64encode(hmac.new(API_SECRET.encode(), payload.encode(), hashlib.sha256).digest()).decode().rstrip("=")

(Base64URL は標準の Base64 の +- に、/_ に置き換え、末尾の = パディングを除去したものです。)

5. API詳細

5.1 ライセンスコードの生成(ソフトウェア内決済後に呼び出し)

呼び出しタイミング: ユーザーがソフトウェア内で決済を完了した直後に、サーバーが1回呼び出し、返されたライセンスコードとアクティベーショントークンを保存します。同じ注文は1回だけ送信してください。冪等のため、繰り返し呼び出しても二重発行はされません。

POST /license/software/generate

リクエストパラメータ(JSON body):

パラメータ 必須 生成元 説明
productId number 必須 ソフトウェア内蔵 / サーバー設定 製品ID。プラットフォームで公開した製品と一致
machineCode string 必須 クライアント生成 現在のデバイスのマシンコード、8文字以上
edition string 任意 決済時にクライアントが選択 エディションID。製品のエディション一覧に含まれる必要あり。省略時は製品の最初のエディション
expiryDays number 任意 決済時にクライアントが選択 有効日数、0 = 無期限。範囲 0-3650
clientOrderId string 必須 クライアント / サーバー生成 ソフトウェア内決済の注文ID、1-64文字。冪等キー
timestamp number 必須 サーバー生成 ミリ秒タイムスタンプ
signature string 必須 サーバーで計算 HMAC署名、10文字以上

成功レスポンスの content 項目:

項目 説明
licenseId number ライセンスレコードID
licenseCode string ライセンスコード(ソフトウェアのライセンス情報に書き込む)
productId number 製品ID
edition string エディションID
machineId number バインド済みマシンのレコードID
activatedAt string アクティベーション時刻(ISO8601)
expiryTime string/null 有効期限(ISO8601)、null = 無期限
trialExpiryTime string/null 試用期限スナップショット(ISO8601)、null = 試用からのアップグレードではない
trialExpiryTime string/null 試用期限スナップショット(ISO8601)、null = 試用からのアップグレードではない
trialExpiryTime string/null 試用期限スナップショット(ISO8601)、null = 試用からのアップグレードではない
trialExpiryTime string/null 試用期限スナップショット(ISO8601)、null = 試用からのアップグレードではない
maxMachines number バインド可能なマシンの最大数
activationToken string アクティベーショントークン。起動検証用に保存

レスポンス例:

{
  "code": "SUCCESS",
  "requestId": "xxx",
  "success": true,
  "content": {
    "licenseId": 1001,
    "licenseCode": "AB12-CD34-EF56-GH78",
    "productId": 88,
    "edition": "PRO",
    "machineId": 2001,
    "activatedAt": "2026-08-05T10:00:00.000Z",
    "expiryTime": "2027-08-05T10:00:00.000Z",
    "trialExpiryTime": "2026-12-01T10:00:00.000Z",
    "trialExpiryTime": "2026-12-01T10:00:00.000Z",
    "trialExpiryTime": "2026-12-01T10:00:00.000Z",
    "trialExpiryTime": "2026-12-01T10:00:00.000Z",
    "maxMachines": 1,
    "activationToken": "eyJhbGciOiJIUzI1NiJ9..."
  }
}

このAPIのエラーコード: productIdRequiredmachineCodeInvalidorderIdRequiredproductNotFoundproductNotEnabledapiSecretMissingsignatureInvalidorderAlreadyUsed

5.2 エディションアップグレード / 更新(決済後に呼び出し)

呼び出しタイミング: ユーザーが更新またはエディションアップグレードの決済を完了した後に呼び出します。同じ注文は1回だけ送信してください。

POST /license/software/upgrade

リクエストパラメータ(JSON body):

パラメータ 必須 生成元 説明
productId number 必須 ソフトウェア内蔵 / サーバー設定 製品ID
licenseCode string 必須 ソフトウェアに保存 現在のライセンスコード、10文字以上
machineCode string 任意 クライアント生成 現在のマシンコード。新コード発行時のバインド移行や追加バインド時に指定
edition string 必須 決済時にクライアントが選択 対象エディションID
expiryDays number 任意 決済時にクライアントが選択 追加有効日数、0 = 無期限。範囲 0-3650
clientOrderId string 必須 クライアント / サーバー生成 今回の注文ID。冪等キー
timestamp number 必須 サーバー生成 ミリ秒タイムスタンプ
signature string 必須 サーバーで計算 HMAC署名

処理戦略(製品設定により決定):

  • SAME_CODE(既存コードのままアップグレード): ライセンスコードは変わらず、マシンのバインドも有効のまま、有効期限が延長されます(無期限は無期限のまま)。レスポンスは5.1の項目に加えて upgraded: true を含みます;
  • NEW_CODE(新コードを発行): 旧コードを失効させ、新コードを発行してマシンのバインドを移行します。レスポンスには追加で oldLicenseId が返り、licenseCode は新コードです。

成功レスポンスの content 項目: 5.1と同じで、さらに upgraded: true。NEW_CODE戦略では oldLicenseId(旧ライセンスレコードID。旧コードは失効済み)も返ります。

このAPIのエラーコード: productIdRequiredlicenseCodeRequiredorderIdRequiredproductNotFoundproductNotEnabledapiSecretMissingsignatureInvalidcodeNotFoundrevokedorderAlreadyUsededitionRequired

5.3 ライセンスのアクティベーション(初回アクティベーション / 別マシン)

呼び出しタイミング: ユーザーがライセンスコード(自助発行、運営発行など)を入手し、クライアントソフトウェアのアクティベーションページで入力してアクティベートするとき。別マシンに変更するときは新マシンで呼び出します。

POST /license/activate

リクエストパラメータ(JSON body):

パラメータ 必須 生成元 説明
licenseCode string 必須 ユーザー入力 ライセンスコード、10文字以上
machineCode string 必須 クライアント生成 現在のデバイスのマシンコード、8文字以上

成功レスポンスの content: 5.1と同じ(licenseId、licenseCode、productId、edition、machineId、activatedAt、expiryTime、maxMachines、activationToken)。

補足:

  • 1つのライセンスコードは複数のマシンにバインドでき、maxMachines(デフォルトは製品設定)が上限です;
  • 同じマシンを再アクティベートすると既存バインドを再利用し、アクティベーショントークンを再発行します(冪等);
  • アクティベーション失敗は IP + ライセンスコード単位でレート制限され、失敗が続くと tooManyAttempts を返します。

このAPIのエラーコード: codeNotFoundrevokedexpiredmachineLimittooManyAttempts

5.4 ライセンスの検証(ソフトウェア起動時)

呼び出しタイミング: ソフトウェアの起動のたび(または機能のロック解除前)に呼び出します。5.1 / 5.2 / 5.3 が返した activationToken を保存しておく必要があります。

POST /license/verify

リクエストパラメータ(JSON body):

パラメータ 必須 生成元 説明
licenseCode string 必須 ソフトウェアに保存 ライセンスコード、10文字以上
machineCode string 必須 クライアント生成 現在のデバイスのマシンコード、8文字以上
activationToken string 必須 プラットフォーム発行、ソフトウェアに保存 アクティベーショントークン、20文字以上

成功レスポンスの content 項目:

項目 説明
valid boolean 常に true(失敗はエラーコードで返る)
licenseId number ライセンスレコードID
productId number 製品ID
edition string 現在のエディションID
expiryTime string/null 有効期限(ISO8601)、null = 無期限
trialExpiryTime string/null 試用期限スナップショット(ISO8601)、null = 試用からのアップグレードではない
trialExpiryTime string/null 試用期限スナップショット(ISO8601)、null = 試用からのアップグレードではない
trialExpiryTime string/null 試用期限スナップショット(ISO8601)、null = 試用からのアップグレードではない
trialExpiryTime string/null 試用期限スナップショット(ISO8601)、null = 試用からのアップグレードではない

補足:

  • 検証結果は約60秒キャッシュされます。失効・バインド解除・アップグレードなどの書き込み操作はキャッシュを即時無効化するため、遅延の心配はありません;
  • ソフトウェアは expiryTime を確認し、期限切れ後は機能のロック解除を停止してください。
  • 試用からのアップグレードの場合は trialExpiryTime を猶予期間として利用できます:trialExpiryTime を過ぎるまで上位機能の解放を続けられます。
  • 試用からのアップグレードの場合は trialExpiryTime を猶予期間として利用できます:trialExpiryTime を過ぎるまで上位機能の解放を続けられます。
  • 試用からのアップグレードの場合は trialExpiryTime を猶予期間として利用できます:trialExpiryTime を過ぎるまで上位機能の解放を続けられます。
  • 試用からのアップグレードの場合は trialExpiryTime を猶予期間として利用できます:trialExpiryTime を過ぎるまで上位機能の解放を続けられます。

このAPIのエラーコード: tokenInvalidmachineNotActivatedinvalidOrRevokedexpiredtooManyAttempts

5.5 デバイスのバインド解除(機種変更前、ログイン必須)

呼び出しタイミング: ユーザーが「マイページ → マイライセンス」で旧デバイスのバインドを解除し、その後5.3で新デバイスをアクティベートします。

POST /license/deactivate

リクエストパラメータ(JSON body):

パラメータ 必須 生成元 説明
licenseCode string 必須 ユーザーのライセンス一覧 ライセンスコード、10文字以上
machineCode string 必須 ユーザーのライセンス一覧 解除するマシンコード、8文字以上

成功レスポンスの content: true

補足:

  • ライセンスの所有者(購入ユーザー、またはバインド済みマシンコードを登録したユーザー)のみ操作できます;
  • バインド解除の上限: デフォルトでは同じライセンスは30日以内に1回しか解除できません(運営コンソールで設定可能)。超過すると unbindQuotaExceeded を返します。

このAPIのエラーコード: noPermissionmachineNotBoundunbindQuotaExceeded

6. エラーコード

業務エラーは統一レスポンスで返ります(tip は人間が読めるメッセージ):

{
  "code": "BUSINESS_WARNING",
  "requestId": "xxx",
  "success": false,
  "errorMessage": "LICENSE_GENERATE_FAILED",
  "tip": "Signature verification failed"
}

パラメータ検証失敗の場合は code: "PARAM_VALIDATE_FAILED" で、具体的な項目メッセージが tip に入ります。

エラーコード 意味
productNotEnabled 製品でライセンスアクティベーションが有効になっていない
apiSecretMissing 製品にソフトウェア発行APIシークレット(licenseApiSecret)が設定されていない
signatureInvalid 署名検証失敗(シークレット不一致、署名対象文字列の順序誤り、タイムスタンプ超過)
machineCodeInvalid マシンコードが無効(8文字未満)
orderAlreadyUsed この注文では既にライセンスコードが発行されている(冪等の競合: 別マシンコードでの再送)
codeNotFound ライセンスコードが存在しない
revoked ライセンスコードは失効済みまたは使用不可
expired ライセンスコードは期限切れ
invalidOrRevoked 検証時にライセンスが無効または失効
machineNotActivated このマシンはアクティベートされていない
tokenInvalid アクティベーショントークンが無効
machineLimit ライセンスのバインド可能マシン数が上限に達した
machineNotBound このマシンはバインドされていない
noPermission このライセンスを操作する権限がない
unbindQuotaExceeded 30日以内に1回しか解除できません。後でもう一度お試しください
tooManyAttempts 試行回数が多すぎます。後でもう一度お試しください
productNotFound 製品が存在しない
editionRequired 対象エディションを選択してください

7. 典型的なフロー

  1. ソフトウェア内決済ループ: 決済成功 → software/generate(ライセンスコード + アクティベーショントークンを返す)→ ソフトウェアが保存 → 起動のたびに verify → 機能のロック解除。更新 / アップグレード → software/upgrade
  2. 自助発行 / 運営発行: デベロッパーセンターまたは運営コンソールでライセンスコードを生成 → ユーザーがコードを入手 → クライアントで activate しデバイスをバインドしてトークンを取得 → 起動時に verify
  3. 機種変更: マイページの deactivate で旧デバイスを解除 → 新デバイスで activateverify
  4. アップグレード戦略の違い: SAME_CODE はコードが変わらない。NEW_CODE は新コードを発行(旧コードは失効、マシンバインドは自動移行)。

8. 注意事項

  • シークレットはサーバー側のみ: 署名はソフトウェアサーバーでのみ行ってください。クライアントがシークレットを入手するとライセンス体系は無効になります;
  • マシンコードの安定性: 安定したマシンフィンガープリントをハッシュ化することを推奨します。OS再インストールでマシンコードが変わった場合は、先にバインド解除してから再アクティベートしてください;
  • 冪等: clientOrderId はグローバルに一意(例: タイムスタンプ + 乱数)にしてください。重複リクエストでも二重発行されません;
  • キャッシュ: verify の結果は約60秒キャッシュされ、書き込み操作で即時無効化されます;
  • レート制限: アクティベーション / 検証の失敗はレート制限されます。クライアントはエラー表示と再試行間隔を適切に設計してください;
  • プラットフォームの判定を基準に: 有効期限・エディション・マシン数の上限はプラットフォームの判定を基準とし、ソフトウェア側で勝手に緩めないでください。

6. トライアル取得と購入ページ

「後払い」クライアント製品は、無料ダウンロード後に POST /license/trial/claim で試用ライセンスを取得します(productUniqueCode / machineCode、製品+マシンで冪等)。 試用終了後はライセンス版の購入が必要です。購入ページ: https://www.powersoftware.app/product/license/purchase?productUniqueCode={productUniqueCode}&machineCode={machineCode}。 決済後、正式ライセンスが発行されメールで送信されます。SDK 参照:ps-help/v3/doc/授权SDK规范_v3.md

7. 公式 SDK(Node / Python / Java)

3 言語の公式 SDK と仕様(日本語/英語):

https://github.com/mizhanchengxi/powersoftware-license-sdk

8. アップグレードポリシー識別子(licenseUpgradeMode)

POST /license/activatePOST /license/verifyPOST /license/trial/claim の 3 つのインターフェースの成功レスポンス content に、製品レベルのアップグレードポリシー設定を付加して返します:

フィールド 説明
licenseUpgradeMode string SAME_CODE=コード不変更(アップグレード/更新後もライセンスキーは変わらない);NEW_CODE=コード再バインド(アップグレード/更新時に旧コードを失効させ新コードを発行)

クライアントでの用途:

  • 「ライセンスキー入力欄」を表示するかどうかの判定に使用:SAME_CODE ではライセンスキーが変わらないため、ユーザーへの再入力を促す必要なし;NEW_CODE ではアップグレード/更新時に新コードが発行されるため、インターフェースが返す新しい licenseCode でローカル保存済みのキーを上書きすること;
  • verify は起動のたびに最新設定を返すため、クライアントは常に同期可能。

補足:

  • 製品レベルの設定(開発者が公開フォームでアップグレードポリシーを設定)。未設定の場合は SAME_CODE として扱う;
  • verify の結果は約 60 秒キャッシュされるため、プラットフォーム側の設定変更は最大 60 秒で反映;
  • software/upgrade はポリシーに従って実際の旧コードまたは新コードを返すため、このフィールドに依存しない。

9. 試用期限スナップショット(trialExpiryTime)

POST /license/activatePOST /license/verifyPOST /license/trial/claim の 3 つのインターフェースの成功レスポンス content に、試用期限スナップショットを付加して返します:

フィールド 説明
trialExpiryTime string | null 元の試用ライセンスの有効期限(ISO 8601);null = 試用からのアップグレードではない(純粋な新規購入・開発者発行コード・試用未転換など)

生成ルール:

  • 試用の申し込み時に書き込まれ、試用ライセンスの expiryTime と同値;
  • 試用後の購入(同コード・アップグレード/新コード再発行)時に、プラットフォームは試用コードの元の有効期限を取得しこのフィールドに固定する。購入後の expiryTime は購入エディションの有効期限に変わるが、本フィールドは変更されない;
  • 期限切れ試用からの転換でも固定される(過去の日時),クライアントは「猶予なし」を判定可能;
  • 以降の有償アップグレード/更新(同コード・新コード)でも本フィールドは保持される。

クライアントでの用途(推奨):トライアルファースト製品は試用期間中すべての機能が利用可能だが、下位エディションを購入すると上位機能はエディション判定により即時ロックされる。クライアントは trialExpiryTime を読み取り、移行ポリシーを自行決定できる。例:現在時刻が trialExpiryTime より前の間は当該上位機能の猶予を続け、時刻到達後にロックして差額アップグレードへ誘導する。使用するかどうか・猶予の方式はクライアントの裁量で、プラットフォームは強制しない。

補足:トライアル申し込み時、当該マシンが当該製品の下で非試用ライセンスを既に保持している場合(試用からの転換・新規購入・開発者発行コードなど、つまり購入済み)、インターフェースはエラーコード trialAlreadyPurchased を返し、追加の試用ライセンスは発行されない。取り消し(返金)済みのライセンスは購入済みとはみなさない。