Shager REST API クイックスタート:新しいキーから40アカウントへの計測付き投稿まで、7回の呼び出しで
curlとTypeScriptでShagerのREST APIを実践解説。認証、ワークスペース、チャンネル、メディア、下書き、予約、状態確認、クリック。

Shager の REST API は https://app.shager.ai/api/v1 にあり、Authorization: Bearer shgr_live_... で認証します。結果はすべて { "data": ... }、エラーはすべて { "error": { "code", "message" } } の形で返ります。配信を一通り行うのに必要な呼び出しは7回です。キーを確認し、ワークスペースを選び、そのチャンネルを一覧し、メディアをアップロードし、アカウントごとのキャプション付きで下書きを作り、予約し、最後に状態とクリックを確認します。機械可読な仕様は OpenAPI 3.1 ドキュメントにあります。
以下のコードは、環境変数を2つ設定すれば書いてあるとおりに動きます。同じ操作は同じ名前の MCP ツールとしても用意されているので、ここで覚えたことは Claude Code、Codex、Cursor でもそのまま使えます。
最初の呼び出しの前に必要なもの
必要なのはキーです。人が https://app.shager.ai/dashboard/agents で必要なスコープを付けて作成するか、エージェントが自己登録でサンドボックスを作成します。スコープは次のとおりです。
| スコープ | できること |
|---|---|
read |
whoami、ワークスペース・チャンネル・グループ・投稿の一覧、投稿の参照、分析 |
write |
ワークスペース、グループ、メディア、下書き投稿、接続リンク、承認リクエストの作成、取り消し |
publish |
予約(schedule_at 付きの create_post を含む) |
export SHAGER_API_KEY="shgr_live_your_key_here"
export API="https://app.shager.ai/api/v1"

呼び出し1:自分は誰か
curl -s "$API/me" -H "Authorization: Bearer $SHAGER_API_KEY"
{ "data": { "organization_id": "...", "organization": "Northwind Agency", "sandbox": false, "scopes": ["read", "write"] } }
sandbox が true の場合、人がキーを引き継ぐまで予約と接続リンクは使えません。scopes に publish がなければ、下書きは作れても予約はできません。最初にこれを把握しておけば、後でわけのわからない 403 に悩まされずに済みます。
呼び出し2:ワークスペースを選ぶか作成する
ワークスペースは通常、1つのクライアントまたはブランドにあたります。
curl -s "$API/workspaces" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s -X POST "$API/workspaces" \
-H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
-d '{"name": "Summit Physio", "timezone": "Europe/London", "approval_required": true}'
作成時には必ず timezone(IANA の名前)を設定してください。予約時刻はオフセット付きで保存され、Shager はワークスペースのタイムゾーンを使って人に時刻を表示します。approval_required: true にすると、投稿はクライアントの承認を得てからでないと予約できません。新しいクライアントには、これをデフォルトにしておくのがおすすめです。
以降のコマンドが動くように、レスポンスの id を環境変数に設定します。
export WS="the_workspace_id"
呼び出し3:チャンネルとグループを一覧する
curl -s "$API/workspaces/$WS/channels" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/groups" -H "Authorization: Bearer $SHAGER_API_KEY"
各チャンネルは id、network、name、handle、status、対応している formats、そして connected_by_client とともに返ります。グループは id、name、channel_ids を返します。グループを使えば、40個の id を並べなくても40のアカウントを指定できます。create_post に group_ids を渡すと、そのグループ内の有効なチャンネルがすべて含まれます。
ワークスペースにまだチャンネルがない場合は、POST /workspaces/{workspace_id}/connect-links で接続リンクを作成し、アカウントの持ち主に送ります。持ち主は Shager にログインすることなく、Facebook、Instagram、YouTube、X、LinkedIn、TikTok を自分で接続できます。

呼び出し4:URL からメディアをアップロードする
curl -s -X POST "$API/workspaces/$WS/media" \
-H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
-d '{
"url": "https://cdn.summitphysio.example/video/knee-mobility.mp4",
"file_name": "knee-mobility.mp4",
"width": 1080, "height": 1920, "duration_ms": 42000
}'
Shager はサーバー側でファイルをダウンロードし、id、kind、mime_type、size_bytes を返します。リール、ショート、ストーリーズの場合、わかっていれば width、height、duration_ms を渡してください。そうすれば Shager が、送信時に失敗するのではなく、投稿の予約前に各 SNS の形式ルールをチェックできます。
呼び出し5:アカウントごとのキャプション付きで下書きを作る
ここが肝心の呼び出しです。素の fetch を使った TypeScript のコードで、繰り返し使える小さなヘルパーも含めています。
const API = "https://app.shager.ai/api/v1";
async function shager<T>(method: string, path: string, body?: unknown): Promise<T> {
const res = await fetch(`${API}${path}`, {
method,
headers: {
Authorization: `Bearer ${process.env.SHAGER_API_KEY}`,
"Content-Type": "application/json",
},
body: body ? JSON.stringify(body) : undefined,
});
const json = await res.json();
if (!res.ok) {
const err = new Error(`${res.status} ${json.error.code}: ${json.error.message}`);
(err as any).status = res.status;
throw err;
}
return json.data as T;
}
const WS = process.env.SHAGER_WORKSPACE_ID!;
const mediaId = process.env.SHAGER_MEDIA_ID!; // the id returned by call 4
const channels = await shager<Array<{ id: string; name: string; network: string; status: string }>>(
"GET", `/workspaces/${WS}/channels`,
);
const post = await shager<{ id: string; status: string }>("POST", `/workspaces/${WS}/posts`, {
label: "Knee mobility, week 42",
caption: "Three minutes a day for stiffer knees. Full routine in the video.",
channel_ids: channels.map((c) => c.id),
media_ids: [mediaId],
format: "REEL",
youtube_title: "3-minute knee mobility routine",
youtube_privacy: "public",
per_channel: channels.map((c) => ({
channel_id: c.id,
caption: `${c.name}: three minutes a day for stiffer knees. Our physios show the routine.`,
})),
cta_url: "https://summitphysio.example/book",
cta_text: "Book an assessment",
campaign: "knee-mobility-oct",
first_comment: "Book an assessment: https://summitphysio.example/book",
stagger_seconds: [45, 120],
});
console.log(post.id, post.status); // DRAFT
各フィールドで得られるものは次のとおりです。
per_channelは、アカウントごとに専用のキャプションを与えます。実際にはエージェントがこれを書きます。上のテンプレートはそのステップの仮置きで、理由は大規模投稿でスパム判定を避ける方法で解説しています。formatは、その SNS が対応していれば適用され、そうでなければSHORTとREELのどちらにするかが SNS ごとに判断されます。youtube_titleとyoutube_privacyは YouTube のチャンネルにだけ影響します。cta_urlからは、アカウントごとに別々の短縮リンクと UTM のセットが作られ、utm_contentでアカウントを識別できます。アカウント単位のリード計測はこの仕組みの上に成り立っています。stagger_secondsは、同じ SNS のアカウント間にランダムな待ち時間を設定します。デフォルトは[30, 90]です。
schedule_at を付けなければ、結果は下書きになります。次の呼び出しのために、export POST_ID="the_post_id" で id を控えておきましょう。
呼び出し6:承認または予約
ワークスペースが承認を必須にしている場合は、クライアントに承認を依頼します。レスポンスには approval_url が含まれ、承認者はログインせずにこれを開けます。
curl -s -X POST "$API/workspaces/$WS/posts/$POST_ID/approval" \
-H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
-d '{"reviewer_name": "Dana Ellis", "reviewer_email": "dana@summitphysio.example", "send_email": true}'
承認されたら(または承認が不要なら)予約します。これには publish スコープが必要で、schedule_at はオフセット付きの ISO 8601 でなければなりません。
curl -s -X POST "$API/workspaces/$WS/posts/$POST_ID/schedule" \
-H "Authorization: Bearer $SHAGER_API_KEY" -H "Content-Type: application/json" \
-d '{"schedule_at": "2026-10-20T08:30:00+01:00"}'
この時点で Shager は、すべての投稿先を各 SNS のルールに照らして検証します。どれかのアカウントが投稿を拒否しそうな場合は、理由とともに 422 rejected が返り、何もキューに入りません。
呼び出し7:状態とクリックを確認する
curl -s "$API/workspaces/$WS/posts/$POST_ID" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/posts?status=SCHEDULED&limit=50" -H "Authorization: Bearer $SHAGER_API_KEY"
curl -s "$API/workspaces/$WS/analytics?from=2026-10-01T00:00:00Z&to=2026-10-31T23:59:59Z" \
-H "Authorization: Bearer $SHAGER_API_KEY"
get_post は投稿先ごとに1行を返し、state、dispatch_at、published_at、公開された投稿の url、そしてエラーがあれば error を含みます。分析では total_clicks、by_account、by_post が返り、Shager の計測リンクのクリックを、ボットのトラフィックを除いて集計します。公開が始まっていない予約済みの投稿を取り消すには、POST /workspaces/{workspace_id}/posts/{post_id}/cancel を使います。
コードで処理すべきエラー
| ステータスとコード | 意味 | 対処 |
|---|---|---|
401 unauthorized |
ヘッダーがない、または形式が不正 | Authorization: Bearer shgr_... を送る |
403 forbidden |
キーに必要なスコープがない | 下書きにとどめるか、人に publish を依頼する |
403 sandbox_unclaimed |
引き継がれていない自己登録キー | 引き継ぎ用リンクを人に伝える |
404 not_found |
ワークスペース、投稿、チャンネルの id が違う | 一覧を取り直す。id はワークスペースごと |
409 not_scheduled |
予約されていない投稿を取り消そうとした | 先に投稿の状態を確認する |
422 rejected |
SNS のルールに違反した | メッセージを表示する。問題点が書かれている |
429 rate_limited |
キーごとの毎分120リクエストを超えた | 間隔を空けてリトライする |
うまく設計されたクライアントなら、レート制限に引っかかることはまずありません。1回の create_post で数百のアカウントをカバーできるので、アカウントごとに呼び出す必要はないはずです。
よくある質問
SDK はありますか?
専用の SDK はありません。型付きのクライアントが欲しければ、OpenAPI 3.1 ドキュメントを一般的なジェネレーターで使えます。API は小さいので、たいていは上のようなヘルパーがあれば十分です。Shager の CLI は近日提供予定です。
REST と MCP は本当に同じですか?
はい。各 MCP ツールは1つの REST 操作に対応しており、名前、入力、スコープ、レート制限、監査ログもすべて同じです。スクリプトやサービスからは REST を、エージェントのクライアントからは MCP を使ってください。ツールの一覧はエージェント向けページにあります。
1つの投稿で、Facebook と YouTube に別々のテキストを投稿するには?
per_channel で各チャンネルの id とキャプションを指定し、YouTube のタイトルには youtube_title を使います。1つの投稿オブジェクトに多数の投稿先があり、必要に応じてそれぞれに専用のキャプション、形式、最初のコメントを持たせられます。
次のステップ
この一連の流れが手作業で問題なく動くようになったら、エージェントが繰り返し実行できる形にまとめましょう。Shager 用の Claude スキルを作るでは、これらの呼び出しとそれにまつわるルールを、再利用できるスキルにまとめる方法を紹介しています。


