ライセンス公開APIドキュメント
v1.0
ライセンス公開APIドキュメント
このドキュメントは、自社ソフトウェアに「支払い → 発行 → アクティベーション → 検証」の一連の流れを組み込みたい開発者(クライアントソフトウェア / 販売委託製品)向けです。各APIについて呼び出しタイミング・リクエストパラメータ・レスポンス項目・エラーコードを説明します。
1. 基本概念
| 概念 | 項目 / 用語 | 説明 |
|---|---|---|
| ソフトウェア発行APIシークレット | licenseApiSecret |
製品で「ライセンスアクティベーション」を有効にすると自動生成されます。デベロッパーセンターの製品編集フォームで確認できます。ソフトウェアサーバーはこれでHMAC署名を計算し、プラットフォームはこれで署名を検証します。サーバー側にのみ保存し、クライアントに埋め込まないでください。 |
| ライセンスコード | licenseCode |
プラットフォームが発行する一意のコードです。ユーザーはこれを使ってソフトウェアをアクティベートします。 |
| マシンコード | machineCode |
クライアントソフトウェアが生成するデバイス識別子です(PCごとに一意。安定したマシンフィンガープリントをハッシュ化することを推奨、8文字以上)。 |
| アクティベーショントークン | activationToken |
アクティベーション / 発行時にプラットフォームが発行するトークンです。ソフトウェアは保存し、起動検証のたびに送信します。 |
| 注文ID | clientOrderId |
ソフトウェア内決済の注文ID(クライアントまたはサーバーが生成)。プラットフォームは「製品 + 注文ID」で冪等化し、二重課金・二重発行を防ぎます。 |
2. 導入準備
- 製品公開時に「ライセンスアクティベーション」を有効にし、生成された**ソフトウェア発行APIシークレット(licenseApiSecret)**を保存します;
- 公開フォームでエディション一覧(例: BASIC/PRO/ULTIMATE)とアップグレード戦略(SAME_CODE = 既存コードのままアップグレード / NEW_CODE = 新コードを発行)を設定します;
- シークレットはソフトウェアサーバーに保存し、クライアントにはライセンスコードとアクティベーショントークンのみを持たせます。
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 = 無期限 |
| 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",
"maxMachines": 1,
"activationToken": "eyJhbGciOiJIUzI1NiJ9..."
}
}
このAPIのエラーコード: productIdRequired、machineCodeInvalid、orderIdRequired、productNotFound、productNotEnabled、apiSecretMissing、signatureInvalid、orderAlreadyUsed。
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のエラーコード: productIdRequired、licenseCodeRequired、orderIdRequired、productNotFound、productNotEnabled、apiSecretMissing、signatureInvalid、codeNotFound、revoked、orderAlreadyUsed、editionRequired。
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のエラーコード: codeNotFound、revoked、expired、machineLimit、tooManyAttempts。
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 = 無期限 |
補足:
- 検証結果は約60秒キャッシュされます。失効・バインド解除・アップグレードなどの書き込み操作はキャッシュを即時無効化するため、遅延の心配はありません;
- ソフトウェアは
expiryTimeを確認し、期限切れ後は機能のロック解除を停止してください。
このAPIのエラーコード: tokenInvalid、machineNotActivated、invalidOrRevoked、expired、tooManyAttempts。
5.5 デバイスのバインド解除(機種変更前、ログイン必須)
呼び出しタイミング: ユーザーが「マイページ → マイライセンス」で旧デバイスのバインドを解除し、その後5.3で新デバイスをアクティベートします。
POST /license/deactivate
リクエストパラメータ(JSON body):
| パラメータ | 型 | 必須 | 生成元 | 説明 |
|---|---|---|---|---|
| licenseCode | string | 必須 | ユーザーのライセンス一覧 | ライセンスコード、10文字以上 |
| machineCode | string | 必須 | ユーザーのライセンス一覧 | 解除するマシンコード、8文字以上 |
成功レスポンスの content: true。
補足:
- ライセンスの所有者(購入ユーザー、またはバインド済みマシンコードを登録したユーザー)のみ操作できます;
- バインド解除の上限: デフォルトでは同じライセンスは30日以内に1回しか解除できません(運営コンソールで設定可能)。超過すると
unbindQuotaExceededを返します。
このAPIのエラーコード: noPermission、machineNotBound、unbindQuotaExceeded。
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. 典型的なフロー
- ソフトウェア内決済ループ: 決済成功 →
software/generate(ライセンスコード + アクティベーショントークンを返す)→ ソフトウェアが保存 → 起動のたびにverify→ 機能のロック解除。更新 / アップグレード →software/upgrade; - 自助発行 / 運営発行: デベロッパーセンターまたは運営コンソールでライセンスコードを生成 → ユーザーがコードを入手 → クライアントで
activateしデバイスをバインドしてトークンを取得 → 起動時にverify; - 機種変更: マイページの
deactivateで旧デバイスを解除 → 新デバイスでactivate→verify; - アップグレード戦略の違い: SAME_CODE はコードが変わらない。NEW_CODE は新コードを発行(旧コードは失効、マシンバインドは自動移行)。
8. 注意事項
- シークレットはサーバー側のみ: 署名はソフトウェアサーバーでのみ行ってください。クライアントがシークレットを入手するとライセンス体系は無効になります;
- マシンコードの安定性: 安定したマシンフィンガープリントをハッシュ化することを推奨します。OS再インストールでマシンコードが変わった場合は、先にバインド解除してから再アクティベートしてください;
- 冪等:
clientOrderIdはグローバルに一意(例: タイムスタンプ + 乱数)にしてください。重複リクエストでも二重発行されません; - キャッシュ:
verifyの結果は約60秒キャッシュされ、書き込み操作で即時無効化されます; - レート制限: アクティベーション / 検証の失敗はレート制限されます。クライアントはエラー表示と再試行間隔を適切に設計してください;
- プラットフォームの判定を基準に: 有効期限・エディション・マシン数の上限はプラットフォームの判定を基準とし、ソフトウェア側で勝手に緩めないでください。