salla-api-core について
salla-api-coreは、Salla Admin APIで商店リソースやアプリ設定を扱う開発者向けのスキルです。OAuthリクエスト、ページネーション、エラーとレート制限への対応を説明し、各エンドポイントのOpenAPIスキーマに基づく呼び出しを案内します。
主な機能
- 01BearerトークンによるHTTPSリクエスト
- 02リソースコレクションのページネーション
- 03APIエラーと429レート制限への対応
- 04アプリ設定の読み取り、統合、更新
- 05エンドポイントのOpenAPIスキーマによる検証
活用シーン
- 01Salla商店APIクライアントの実装
- 02ページ分割されたリソースの取得
- 03レート制限や入力検証失敗への対応
- 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 ブロック内に記載されています(リクエスト/レスポンスのスキーマ、フィールドの型、列挙値、必須フィールド)。このブロックが信頼できる情報源です。次のループを実行してください。
- 検索:salla-docs(または
references/api-resources.md)からエンドポイントのドキュメントページを見つけ、埋め込みのopenapi:YAML ブロックを読みます。 - 作成:スキーマに合わせてリクエストを作成します(必須フィールド、型、列挙値)。
- 呼び出しと検証:スキーマに照らしてレスポンスを検証します。不一致があれば、リクエストを修正して再試行します(検索 → 作成 → 検証 → 修正)。
推測よりもドキュメントの OpenAPI ブロックを優先してください。ドキュメントが不明瞭な場合は、代替の情報源として Partners MCP(salla_reference)を利用します。
ステップ 0 — 確認
- どのリソース/エンドポイントを呼び出しますか?(注文、商品、顧客、設定など)
- 有効なマーチャントの
access_tokenはありますか?(なければ → salla-app-auth) - 取得するのは単一のレコードですか、それともコレクションですか?(コレクションの場合 → ページネーションを行います。ステップ 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 | /orders | https://docs.salla.dev/5394146e0.md |
| 商品 | GET | /products | https://docs.salla.dev/5394168e0.md |
| 顧客 | GET | /customers | https://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": {} }
| コード | 意味 |
|---|---|
| 200 | OK — リクエストが成功しました |
| 201 | Created — リソースが挿入/更新されました |
| 202 | Accepted — リソースが削除されました |
| 204 | No 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)。
| パラメーター | デフォルト | 最大 | 備考 |
|---|---|---|---|
page | 1 | — | 1 から始まる |
per_page | 15 | 60 | 最大は 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 を読み取り、フィールドごとのメッセージを表示してください。
| ステータス | スラッグ | 意味 |
|---|---|---|
| 400 | bad_request | パラメーター、フィールド、またはフィルターが無効です |
| 401 | unauthorized | トークンが無効または期限切れ、スコープが不足しています |
| 403 | forbidden | アクセスが拒否されたか、一時的にブロックされています |
| 404 | not_found | リソースまたはパスが見つかりません |
| 405 | method_not_allowed | HTTP メソッドがサポートされていません |
| 406 | not_acceptable | 受け入れ可能な形式ではありません |
| 410 | gone | リソースは利用できなくなりました |
| 422 | validation_failed | 必須フィールドが不足しているか、無効です |
| 429 | too_many_requests | レート制限を超過しました |
| 500 | server_error | 内部サーバーエラー — 後でもう一度お試しください |
| 503 | service_unavailable | 一時的な過負荷またはメンテナンス中です |
レート制限(公式 — ドキュメント:https://docs.salla.dev/421125m0.md)
制限はストアごとに、ストアのプランに応じて適用され、リーキーバケットアルゴリズムで制御されます。
| プラン | 最大リクエスト数 | ウィンドウ | 超過時の漏出レート |
|---|---|---|---|
| Plus | 120 | 1 分 | 1 リクエスト/秒 |
| Pro | 360 | 1 分 | 1 リクエスト/秒 |
| Special | 720 | 1 分 | 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) |