管理API・Stripe連携ガイド
販売者自身の決済サーバーから、MQLAuthの利用者を作成・通常化・延長・失効できます。 APIキーは販売者単位で、その販売者が所有するEA・インジケーターだけを操作できます。
各項目を管理画面のどこで見るか
APIに渡す値は、すべて管理画面から確認できます。
ユーザー管理(ユーザーID・口座番号・EA名)
サイドバーの「ユーザー管理」を開きます。

| APIの項目 | 画面での場所 |
|---|---|
userId | ユーザー名の下に「ユーザーID: 44798」と表示されます |
accountNumber | 「口座番号」列。クリックでコピーできます |
applicationName | 「EA・インジケーター」列のラベル |
一覧右上の「CSV」ボタンで、表示中の利用者を一括で書き出せます。 先頭列が userId なので、既存の購入者をまとめて自社システムへ取り込むときに使えます。
EA・インジケーター(EA名)
サイドバーの「EA・インジケーター」でも applicationName を確認できます。カードの見出しがその名前です。

値の渡し方の注意
accountNumberは数値で送ります。"12345678"のように文字列にすると400になりますapplicationNameの前後の空白は自動で取り除かれます。大文字・小文字の違いも区別しませんuserIdは画面に表示されますが、作成APIの応答に含まれる値を保存するのが確実です
APIキーを発行する
管理画面のサイドバー、またはアカウント設定の「APIキー」を開き、名前を入力して「発行する」を押します。 平文のキーは発行直後の画面で一度だけ表示されます。サーバーのシークレット管理機能に保存してください。 紛失した場合は新しいキーを発行し、連携先を更新して古いキーを失効させます。失効は直ちに反映されます。 EAのソースコード、ブラウザー、公開リポジトリにキーを含めないでください。
すべてのリクエストに次のヘッダーを付けます。APIの基点は https://mql-auth.com/api/v1/manager/users です。
Authorization: Bearer <発行したmqak_で始まるキー>
Content-Type: application/json
Idempotency-Key: <この操作を一意に識別する値>POSTには Idempotency-Key を付けてください(最大200文字、省略も可能)。同じ販売者の別キーへのローテーション後も再送を識別します。 同じキー・同じ送信先・同じボディの再送は、保存したHTTPステータスとJSONをそのまま返し、操作を再実行しません。 別ボディまたは別送信先への使い回しは422になります。JSONの空白やプロパティ順序も含め、送信バイト列を再利用してください。 エラー応答も保存されるため、入力やプランを修正して新しい操作を行う場合は新しいキーを使います。
日時は 2026-10-18T23:59:59+09:00 または 2026-10-18T14:59:59Z のようにオフセットを必ず付けます。 オフセットのない日付は400です。サーバーでローカル時刻へ変換し、本番では日本時間として扱います。
利用者を作成する
POST /api/v1/manager/users
{
"applicationName": "SampleEA",
"accountNumber": 12345678,
"userName": "購入者",
"email": "customer@example.com",
"userPeriod": "2026-10-18T23:59:59+09:00",
"isTestUser": false,
"memo": "外部決済から登録"
}applicationName・正の整数の accountNumber・userName・userPeriod は必須です。 email・memo は省略可能、isTestUser は省略するとfalseです。 同じEA・口座番号に有効な体験版があれば通常化し、体験版使用済み記録を残します。 その場合は購入者の名前・メールを適用し、購入期限が既存の通常期限より後であれば期限を更新します。 通常の作成では既存画面と同じ重複判定・ユーザー上限・体験版期限上限が適用されます。
成功時はHTTP 200で次の形式を返します。userId を自社DBとStripeのsubscription metadataに保存してください。 口座番号は利用者自身が変更できるため、以後の操作には userId を使います。
{
"userId": 123,
"applicationName": "SampleEA",
"accountNumber": 12345678,
"userName": "購入者",
"email": "customer@example.com",
"userPeriod": "2026-10-18T23:59:59.0000000+09:00",
"isTestUser": false
}通常化・延長・失効
| 操作 | POSTのパス | ボディ |
|---|---|---|
| 体験版を通常化 | /api/v1/manager/users/123/promote | {} または空 |
| 指定期限まで延長(推奨) | /api/v1/manager/users/123/extend | {"until":"2026-11-18T23:59:59+09:00"} |
| 月数で延長 | /api/v1/manager/users/123/extend | {"months":1} または {"months":12} |
| 指定日時で失効 | /api/v1/manager/users/123/expire | {"at":"2026-10-18T23:59:59+09:00"} |
| 今すぐ失効 | /api/v1/manager/users/123/expire | {} または空 |
通常化は新しい通常ユーザーの userId を返します。同じEA・口座に通常ユーザーが既にある場合も200で既存ユーザーを返します。 通常化後は返された userId に保存値を更新してください。
until は期限を後退させません。現在の期限以下なら変更せず200を返します。 until と months が両方ある場合は until を優先します。 months は期限内なら現在の期限から、期限切れなら現在時刻から加算します。再送による二重加算を防ぐため必ず冪等キーを使ってください。 体験版には販売者に設定された体験版期限上限が適用されます。
expire は指定した利用者と同じEA・口座番号に属する未失効行すべて(体験版を含む)を at に設定します。 既に期限切れの行は変更しません。応答は {"user":{...上記の利用者情報...},"expiredCount":2} です。 指定したIDの行が期限切れでも、同じ組の有効な別行があれば対象になります。削除APIはありません。
既存利用者を検索する
GET /api/v1/manager/users?applicationName=SampleEA&accountNumber=12345678&email=customer%40example.com
各条件は省略でき、指定した条件をすべて満たす利用者を {"users":[...]} で返します。 期限切れ・体験版も含みます。Password・Memo・Messageは応答に含まれません。 移行時に検索して userId を保存し、以後の延長・失効はIDで指定してください。 まとめて取り込むなら、ユーザー管理画面の「CSV」ボタンでも同じ情報を書き出せます(先頭列が userId)。 再購読も保存済みの userId を使って延長します。有効な体験版がない場合の作成は、既存の通常ユーザーとメール・口座・EA・パスワードが完全一致すると400、異なる場合は別行を作るため、再購読のたびに作成APIを呼ばないでください。
EA・インジケーターの情報を取得する
GET /api/v1/manager/applications
所有しているEA・インジケーターの一覧を返します。?applicationName=SampleEA で1件に絞れます。
{"applications": [{
"applicationId": 1166,
"applicationName": "SampleEA",
"version": "1.02",
"downloadUrl": "https://example.com/SampleEA.zip",
"autoAddUser": true,
"message": "メンテナンスのお知らせ",
"messageViewStart": "2026-09-20T00:00:00+09:00",
"messageViewEnd": "2026-09-27T00:00:00+09:00",
"userCount": 9,
"trialCount": 3
}]}| 項目 | 内容 |
|---|---|
applicationId | 更新APIで指定するID |
version / downloadUrl | アップデート通知に使う最新バージョンとダウンロード先 |
autoAddUser | 体験版の自動作成が有効かどうか(読み取り専用) |
message / messageViewStart / messageViewEnd | 一斉メッセージと表示期間。未設定なら空文字とnull |
userCount / trialCount | 通常ユーザー数と体験版ユーザー数 |
バージョン・ダウンロードURL・一斉メッセージを更新する
PATCH /api/v1/manager/applications/{applicationId}
{
"version": "1.03",
"downloadUrl": "https://example.com/SampleEA_103.zip",
"message": "v1.03を公開しました。ダウンロードしてご利用ください。",
"messageViewStart": "2026-09-20T00:00:00+09:00",
"messageViewEnd": "2026-09-27T00:00:00+09:00"
}送ったプロパティだけが変わります。 version だけ送れば、一斉メッセージやダウンロードURLはそのままです。 更新後の状態を、取得APIと同じ形で返します。
messageに空文字を送ると一斉メッセージを停止しますmessageViewStart/messageViewEndは日時のオフセットが必要ですapplicationNameとautoAddUserは変更できません(送ると400)。 EA名はソースコードに書き込んで配布しているため、変更すると配布済みのEA・インジケーターの 認証が通らなくなります。体験版の自動作成も、配布済みの動作が外部から変わってしまうため 除いています。どちらも管理画面からは従来どおり変更できます
ビルドから配布までを自動化している場合、公開処理の最後にこのAPIを呼ぶと、 バージョンの更新漏れがなくなります。
利用者へ個別メッセージを送る
PATCH /api/v1/manager/users/{userId}/message
{
"message": "お支払いの確認が取れませんでした。サポートまでご連絡ください。",
"messageViewStart": "2026-09-20T00:00:00+09:00",
"messageViewEnd": "2026-09-27T00:00:00+09:00"
}指定した利用者のチャートにだけ表示されます。利用期限・口座番号などほかの項目は変わりません。 空文字を送ると消去します。
決済が失敗した契約者へ案内を出す、といった用途に使えます。
エラーと再試行
{"error":{"code":"manager_plan_restricted","message":"販売者のプラン制限により操作できません。プランを確認してください。"}}| HTTP | code | 対応 |
|---|---|---|
| 400 / 413 | invalid_request | 入力形式・必須項目・ボディサイズ(64KiBまで)を確認 |
| 401 | invalid_api_key | キーの設定・失効状態を確認 |
| 403 | manager_plan_restricted | 販売者のプラン期限・プラン制限を確認し、販売者にアラート |
| 403 | user_cap_reached | 登録上限を確認し、販売者にアラート |
| 404 | not_found | IDまたはEA名を確認。他販売者の利用者も404 |
| 422 | idempotency_conflict | 冪等キーの使い回しを修正 |
| 429 | rate_limit_exceeded | Retry-After(60秒)後に同じ要求を再送 |
既存管理画面と同じプラン制限を使います。Free枠内では操作できます。期限切れの通常ユーザー・体験版は通常ユーザー上限に数えません。 403を放置すると「購入者は支払ったのに利用できない」状態になるため、必ず運用担当へ通知してください。 Webhookの受信側は、署名検証したイベントを永続キューへ保存できた時点でStripeへ2xxを返し、MQLAuthへの送信はワーカーで行います。 403になった処理は運用担当がプラン修正後に再開します。この際、保存済み403の再生を避けるため、例えば event.id:extend:retry1 のように新しい冪等キーを採番・保存して再実行してください。Stripeの同一イベント再送だけでは403は解消しません。 キー単位で60秒間に120回までです。429・通信失敗・5xxでは同じ冪等キーとボディを使って間隔を空けて再送します。
Stripe連携の手順
Webhookは自社のサーバーで受信し、Stripeの署名を検証してから永続キューに保存します。 イベントが欠落・重複・順序逆転しても再処理できるよう、subscription単位で処理順序を管理してください。 Stripeの署名検証と配送・再送の扱いは Stripe公式Webhookガイド を参照してください。
| Stripeイベント | 推奨するMQLAuth操作 |
|---|---|
checkout.session.completed | 支払い完了を確認し create。返された userId をsubscription metadataへ保存 |
invoice.paid | extend の until に支払い済み対象期間の current_period_end を送信 |
invoice.payment_failed | MQLAuthへは何もしない。Stripe Smart Retriesに任せる |
customer.subscription.deleted | expire の at に支払い済み期間の current_period_end を送信。即時失効にしない |
決済イベントの意味とSmart Retriesは Stripe公式のsubscription Webhook説明 で確認できます。 Checkout完了でも非同期決済が未払いのことがあるため、支払い確定前に有料利用権を作らないでください。
current_period_end はUnix秒から new Date(periodEnd * 1000).toISOString() で変換します。 Stripe APIバージョン2025-03-31.basil以降では、期間はsubscription直下ではなく**対象subscription itemの current_period_end**です。 複数商品の契約では、対象EAに対応するitemを選びます。Stripeの変更説明
次は署名検証・支払い確認・対象item特定を済ませたワーカー内の処理例です。 paidPeriodEnd は支払い済みの期間を表すUnix秒で、自社DBに保存した値です。 初回送信前にパス・ボディ文字列・冪等キーを保存し、再試行時はその値を使ってください。
async function callMqlAuth(path, serializedBody, idempotencyKey) {
const response = await fetch(`https://mql-auth.com/api/v1/manager/users${path}`, {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.MQLAUTH_API_KEY}`,
'Content-Type': 'application/json',
'Idempotency-Key': idempotencyKey,
},
body: serializedBody,
})
const result = await response.json()
if (!response.ok) {
// キュー側で429/5xx/通信失敗を再試行。403は販売者へ通知する。
throw Object.assign(new Error(result.error?.message), {
status: response.status, code: result.error?.code,
})
}
return result
}
// checkout.session.completed: この要求内容を永続化してから実行
const body = JSON.stringify({
applicationName: 'SampleEA', accountNumber, userName, email,
userPeriod: new Date(paidPeriodEnd * 1000).toISOString(), isTestUser: false,
})
const user = await callMqlAuth('', body, `${event.id}:create`)
await stripe.subscriptions.update(subscriptionId, {
metadata: { mqlauth_user_id: String(user.userId) },
})
// metadataの更新失敗時も、保存したcreate要求を再送すれば同じuserIdを回収できる。
// invoice.paid: 保存済みuserIdを使用
await callMqlAuth(`/${userId}/extend`, JSON.stringify({
until: new Date(paidPeriodEnd * 1000).toISOString(),
}), `${event.id}:extend`)
// customer.subscription.deleted: 支払い済み期間を残す
await callMqlAuth(`/${userId}/expire`, JSON.stringify({
at: new Date(paidPeriodEnd * 1000).toISOString(),
}), `${event.id}:expire`)invoice.paid が初回作成より先に届いた場合は、作成とmetadata保存が完了するまでキューで待ちます。 古い解約イベントで新しい購入を失効させないよう、外部側でも契約世代と支払い状態を照合してください。 猶予期間を設ける場合は、送信する期限にあらかじめ織り込みます。MQLAuthは自動で猶予を加えません。