mcpField
S
salla-api-core

salla-api-core

github.com/sallaapp開発290 回インストール6 日前に更新
リポジトリ

salla-api-core について

salla-api-coreは、Salla Admin APIで商店リソースやアプリ設定を扱う開発者向けのスキルです。OAuthリクエスト、ページネーション、エラーとレート制限への対応を説明し、各エンドポイントのOpenAPIスキーマに基づく呼び出しを案内します。

主な機能

  1. 01BearerトークンによるHTTPSリクエスト
  2. 02リソースコレクションのページネーション
  3. 03APIエラーと429レート制限への対応
  4. 04アプリ設定の読み取り、統合、更新
  5. 05エンドポイントのOpenAPIスキーマによる検証

活用シーン

  1. 01Salla商店APIクライアントの実装
  2. 02ページ分割されたリソースの取得
  3. 03レート制限や入力検証失敗への対応
  4. 04項目を失わずにアプリ設定を更新

MCP 対応

このスキルは、商店のaccess_tokenを使うSalla Admin APIの実行時呼び出しを扱い、Partners MCPの操作とは区別しています。リソース情報の確認先としてPartners MCPのドキュメントやツールにも触れています。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/sallaapp/salla-partners-agent-kit --skill salla-api-core

インストール後、Claude Code で/salla-api-coreを入力して読み込まれたか確認します。

同梱ファイルreferences/api-resources.md

詳細

Salla Admin API — コアフロー

ほかのすべての Salla スキルの基盤です。認証、リソースの呼び出し、ページネーション、エラーとレート制限への対処、安全なアプリ設定の読み書きを行います。手順を順番に進め、次へ進む前に各ゲートを完了してください。これはマーチャントの access_token(salla-app-auth で取得)を使うランタイムコードであり、Partners MCP のアクションではありません。

ベース URL: https://api.salla.dev/admin/v2(以下のすべてのパスはこの URL からの相対パスです)。 ドキュメント(はじめに):https://docs.salla.dev/421117m0.md

HTTPS のみ — 通常の HTTP は拒否されます。すべての呼び出しには Authorization: Bearer <ACCESS_TOKEN> を含めます(OAuth 2.0)。TLS により通信中のデータが保護されます (ドキュメント:https://docs.salla.dev/421121m0.md、https://docs.salla.dev/421118m0.md)。

横断的なルール(ベース URL、認証、ステータスコード、エラー/ページネーションの形式、レート制限、バージョニング、多言語対応)は、公式ドキュメントから引用した確定情報です。リソースごとのパス、フィールド、スコープ、エンベロープは例示です。利用する前に、最新のリソースドキュメント(references/api-resources.md を参照)または Partners MCP(salla_apps/salla_reference)で確認してください。トークンの仕組み(保存、更新、リフレッシュトークンの単回使用ルール、リフレッシュ用ミューテックス)は salla-app-auth で扱います。

クローズドループ — スキーマ駆動の呼び出し(推測ではなく検証)

リソースごとの呼び出しはすべて、記憶ではなく、エンドポイント独自の OpenAPI スキーマに基づいて作成します。各エンドポイントの docs.salla.dev/<id>.md ページには、完全な OpenAPI 3.x 仕様が ```yaml ブロック内に記載されています(リクエスト/レスポンスのスキーマ、フィールドの型、列挙値、必須フィールド)。このブロックが信頼できる情報源です。次のループを実行してください。

  1. 検索:salla-docs(または references/api-resources.md)からエンドポイントのドキュメントページを見つけ、埋め込みの openapi: YAML ブロックを読みます。
  2. 作成:スキーマに合わせてリクエストを作成します(必須フィールド、型、列挙値)。
  3. 呼び出しと検証:スキーマに照らしてレスポンスを検証します。不一致があれば、リクエストを修正して再試行します(検索 → 作成 → 検証 → 修正)。

推測よりもドキュメントの OpenAPI ブロックを優先してください。ドキュメントが不明瞭な場合は、代替の情報源として Partners MCP(salla_reference)を利用します。

ステップ 0 — 確認

  1. どのリソース/エンドポイントを呼び出しますか?(注文、商品、顧客、設定など)
  2. 有効なマーチャントの access_token はありますか?(なければ → salla-app-auth)
  3. 取得するのは単一のレコードですか、それともコレクションですか?(コレクションの場合 → ページネーションを行います。ステップ 3)

ステップ 1 — 認証とマーチャントの特定

すべてのリクエストは、Authorization ヘッダーのアクセストークンで認証します。

Authorization: Bearer <access_token>
Accept: application/json
Content-Type: application/json   # for POST/PUT/PATCH

安定したマーチャントキーを一度取得し、キャッシュします。

GET https://accounts.salla.sa/oauth2/user/info
Authorization: Bearer <access_token>

merchant.id(トップレベル。user/info には data エンベロープがありません)は、安定した内部キーです。一度キャッシュし、以降のリクエストで再利用します。

公式の401ケース5つ

トークン/認可の失敗は、code と message を含む error オブジェクトとともに 401 を返します。Responses のドキュメント(https://docs.salla.dev/421123m0.md)では、ケースがちょうど5つ定義されています。

#ケースerror.message(代表例)対応
1ユーザーが削除済みThe User is not exists.マーチャントがいなくなっています。呼び出しを停止し、再インストールを待ちます。
2ユーザーが非アクティブحسابك غير مفعل(アカウントがアクティブではありません)呼び出しを停止し、再アクティブ化/再インストールを待ちます。
3リフレッシュトークンの再利用error: "invalid_grant" — アクセストークンとリフレッシュトークンの両方を無効化しますマーチャントはアプリを再インストールする必要があります。salla-app-auth で処理します。
4スコープが許可されていないThe access token should have access to one of those scopes: products.read_writeアプリにスコープを追加します。トークンではこのエンドポイントにアクセスできません。
5トークンが無効/期限切れThe access token is invalid(期限切れ、アプリのアンインストール、または不正な値)トークンをリフレッシュします(salla-app-auth)。リフレッシュできない場合は再認可します。

ケース3は、OAuth のそのままの形式 { "error": "invalid_grant", ... }({ status, success, error } の エンベロープではありません)を返し、アクセストークンも無効にします。単回使用のリフレッシュトークンを並行して再利用すると、完全な再インストールが必要になります。これを防ぐリフレッシュ用ミューテックスは salla-app-auth にあります。

ログ記録には error.message を読み取りますが、動作はケースに基づいて決定します。1~3では停止して再インストール/再アクティブ化を待ち、4ではスコープを修正し、5ではリフレッシュしてから再試行します。

ゲート:「GET /oauth2/user/info が200を返し、merchant.id(トップレベル。data.merchant.id ではありません)をキャッシュしましたか?」


ステップ2 — リクエストを送信する

API は URI のバージョンで管理されます。ベース URL の /admin/v2 がバージョンです。Salla がこれを更新するのは破壊的変更(レスポンス形式の変更、型の変更、API の一部の削除)がある場合のみです。破壊的でない追加は現行バージョンにそのまま反映されます(ドキュメント:https://docs.salla.dev/421126m0.md)。

一般的なリソースのエンドポイント:

リソースメソッドエンドポイントドキュメント
注文GET/ordershttps://docs.salla.dev/5394146e0.md
商品GET/productshttps://docs.salla.dev/5394168e0.md
顧客GET/customershttps://docs.salla.dev/841780f0.md

すべてのリソースグループについて、それぞれのランディングドキュメントは references/api-resources.md(「適切なドキュメントを見つける」ための一覧)を参照してください。リソースごとのパス/フィールド/スコープはこのページではなく、各ドキュメントに記載されています。

**多言語対応(任意):**一部のエンドポイントではレスポンスをローカライズできます。希望する言語を指定するには Accept-Language: <iso_code> を送信します(本文の言語を宣言するには Content-Language を使用します)。iso_code の値は Languages エンドポイントから取得します。デフォルトは ar です(ドキュメント:https://docs.salla.dev/421122m0.md)。

本文を含む2xxレスポンスは data をラップします(204には本文がありません。下記を参照してください)。

{ "status": 200, "success": true, "data": {} }
コード意味
200OK — リクエストが成功しました
201Created — リソースが挿入/更新されました
202Accepted — リソースが削除されました
204No Content — 成功しました。本文はありません

最小限のリクエストヘルパー(TypeScript):

const BASE = "https://api.salla.dev/admin/v2";

async function sallaRequest<T>(
  path: string,
  accessToken: string,
  options: RequestInit = {},
): Promise<T> {
  const method = (options.method ?? "GET").toUpperCase();
  const res = await fetch(`${BASE}${path}`, {
    ...options,
    headers: {
      Authorization: `Bearer ${accessToken}`,
      Accept: "application/json",
      // Content-Type only when sending a body
      ...(method === "GET" || method === "DELETE"
        ? {}
        : { "Content-Type": "application/json" }),
      ...options.headers,
    },
  });

  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw Object.assign(new Error(err?.error?.message ?? res.statusText), {
      status: res.status,
      body: err,
    });
  }

  if (res.status === 204) return undefined as T;
  return res.json() as Promise<T>;
}

ゲート:「単純な GET(例:/orders)が { status, success, data } のエンベロープを返しますか?」


ステップ 3 — コレクションをページネーションする

コレクションエンドポイントは次のパラメーターを受け付けます(ドキュメント:https://docs.salla.dev/421124m0.md)。

パラメーターデフォルト最大備考
page1—1 から始まる
per_page1560最大は 60
GET /orders?page=2&per_page=40

レスポンスの形式:

{
  "status": 200,
  "success": true,
  "data": [
    /* records */
  ],
  "pagination": {
    "count": 40,
    "total": 120,
    "perPage": 40,
    "currentPage": 2,
    "totalPages": 3,
    "links": {}
  }
}

すべてのページを反復処理するには、currentPage < totalPages の間ループし、page をインクリメントします。

確認:「currentPage/totalPages を使って、コレクションのすべてのページを順に取得できますか?」


ステップ 4 — エラーとレート制限への対応

エラーの形式(単一フィールドと複数フィールドで同じ形式です。fields はフィールド → メッセージです。 ドキュメント:https://docs.salla.dev/421123m0.md):

{
  "status": 422,
  "success": false,
  "error": {
    "code": "error",
    "message": "alert.invalid_fields",
    "fields": { "first_name": ["الاسم الاول للعميل مطلوب"] }
  }
}

4xx のバリデーションエラーでは、fields 内の各項目が field → [messages…] となります。複数フィールドのエラーでは、キーが増えるだけです。error.fields を読み取り、フィールドごとのメッセージを表示してください。

ステータススラッグ意味
400bad_requestパラメーター、フィールド、またはフィルターが無効です
401unauthorizedトークンが無効または期限切れ、スコープが不足しています
403forbiddenアクセスが拒否されたか、一時的にブロックされています
404not_foundリソースまたはパスが見つかりません
405method_not_allowedHTTP メソッドがサポートされていません
406not_acceptable受け入れ可能な形式ではありません
410goneリソースは利用できなくなりました
422validation_failed必須フィールドが不足しているか、無効です
429too_many_requestsレート制限を超過しました
500server_error内部サーバーエラー — 後でもう一度お試しください
503service_unavailable一時的な過負荷またはメンテナンス中です
レート制限(公式 — ドキュメント:https://docs.salla.dev/421125m0.md)

制限はストアごとに、ストアのプランに応じて適用され、リーキーバケットアルゴリズムで制御されます。

プラン最大リクエスト数ウィンドウ超過時の漏出レート
Plus1201 分1 リクエスト/秒
Pro3601 分1 リクエスト/秒
Special7201 分1 リクエスト/秒

1 分あたりの予算を使い切った後も、ウィンドウがリセットされるまで1 リクエスト/秒(漏出レート)で送信できます。Customers エンドポイントには、さらに厳しい独自の上限があります。10 分あたり 500 リクエストです — 顧客関連の処理が多いジョブは、それに応じてペースを調整してください。

制限を超過すると、429 too_many_requests が返されます。継続的な過剰利用や通常と異なるパターンがあると、一時的にアクセスが制限される場合があります(403)。

すべてのレスポンスに含まれるヘッダー:

ヘッダー意味
X-RateLimit-Limitこのプランで 1 分あたりに許可される呼び出し数
X-RateLimit-Remaining現在のウィンドウで残っている呼び出し数
Retry-After再試行までに待機する秒数(429 の場合に含まれます)
X-RateLimit-Resetウィンドウがリセットされる UTC のエポック秒

実際のヘッダーを読み取ってバックオフを制御してください。上記のプラン別数値は、計画の基準となる公式記載の最大値です。

if (response.status === 429) {
  // Fetch Headers: use .get(), not bracket access
  const retryAfter = parseInt(response.headers.get("retry-after") ?? "60", 10);
  await sleep(retryAfter * 1000);
  // retry the request
}

確認:「クライアントは error.message/error.fields を読み取り、Retry-After を使って 429 の場合にバックオフしますか?」


ステップ 5 — アプリ設定の読み取りと書き込み(読み取り・変更・書き込み)

GET  /apps/{appId}/settings   # fetch current settings
POST /apps/{appId}/settings   # replace the ENTIRE settings object

POST はマージではなく、完全な置き換えです。 リクエスト本文に含まれないキーはすべて null に設定されます。 必ず最初に読み取り、マージしてから、オブジェクト全体を書き込みます。

// 1. Fetch current settings
const { data: current } = await api.get(`/apps/${appId}/settings`);
// 2. Merge your change
const updated = { ...current, new_key: "value" };
// 3. POST the full merged object
await api.post(`/apps/${appId}/settings`, updated);

Partners Portal で入力した設定(または Partners MCP の salla_settings ツールで定義した設定。salla-app-settings を参照)は、App Functions 内で context.settings として利用できるため、そこで API を呼び出す必要はありません。

確認事項:「設定の更新では、読み取り → マージ → オブジェクト全体の POST(キーの削除なし)が行われていますか?」


クイックリファレンスドキュメントへのリンク

トピックURL
はじめにhttps://docs.salla.dev/421117m0.md
認証(OAuth 2.0)https://docs.salla.dev/421118m0.md
セキュリティhttps://docs.salla.dev/421121m0.md
レスポンスとエラーhttps://docs.salla.dev/421123m0.md
ページネーションhttps://docs.salla.dev/421124m0.md
レート制限https://docs.salla.dev/421125m0.md
バージョン管理https://docs.salla.dev/421126m0.md
多言語対応https://docs.salla.dev/421122m0.md
リソース一覧(適切なドキュメントを探す)references/api-resources.md
アプリ設定ガイドsalla-app-settings スキル(references/form-builder.md)

コメント