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"
Shager の REST API で投稿を作成する curl リクエスト:キャプション、アカウントグループ、計測リンク、公開日時。
MCP サーバーと同じ操作を、OpenAPI のドキュメント付きで利用できます。

呼び出し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 を自分で接続できます。

図:ブリーフ、アカウントごとの下書き、クライアントの承認、時間差での公開、アカウントごとのクリックレポート。
5つの固定ステップです。投稿ごとの承認はクライアント単位で任意ですが、公開には人間のオーナーと、キーへの別個の公開権限が必要です。

呼び出し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

各フィールドで得られるものは次のとおりです。

  1. per_channel は、アカウントごとに専用のキャプションを与えます。実際にはエージェントがこれを書きます。上のテンプレートはそのステップの仮置きで、理由は大規模投稿でスパム判定を避ける方法で解説しています。
  2. format は、その SNS が対応していれば適用され、そうでなければ SHORT と REEL のどちらにするかが SNS ごとに判断されます。youtube_title と youtube_privacy は YouTube のチャンネルにだけ影響します。
  3. cta_url からは、アカウントごとに別々の短縮リンクと UTM のセットが作られ、utm_content でアカウントを識別できます。アカウント単位のリード計測はこの仕組みの上に成り立っています。
  4. 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 スキルを作るでは、これらの呼び出しとそれにまつわるルールを、再利用できるスキルにまとめる方法を紹介しています。

ご自身のアカウントでお試しください。

ローンチ期間中は無料、カード登録不要。接続して一度書くだけで、Shagerが公開して計測します。