البدء السريع مع REST API في Shager: من مفتاح جديد إلى منشور متتبَّع على 40 حسابًا في سبعة استدعاءات

جولة عملية في REST API الخاص بـ Shager بـ curl وTypeScript: المصادقة، ومساحات العمل، والحسابات، والوسائط، ومسودات لكل حساب، والجدولة، والحالة، والنقرات.

يعمل REST API الخاص بـ Shager على العنوان https://app.shager.ai/api/v1، ويصادق عبر Authorization: Bearer shgr_live_...، ويُعيد كل نتيجة بالشكل { "data": ... } وكل خطأ بالشكل { "error": { "code", "message" } }. تتكون عملية توزيع كاملة من سبعة استدعاءات: التحقق من المفتاح، واختيار مساحة عمل، وسرد حساباتها، ورفع الوسائط، وإنشاء مسودة بنص لكل حساب، وجدولتها، ثم قراءة الحالة والنقرات. والمواصفة المقروءة آليًا هي مستند OpenAPI 3.1.

كل ما يلي يعمل كما هو بمجرد ضبط متغيرَي بيئة. والعمليات نفسها متاحة أدواتٍ في MCP بالأسماء ذاتها، فما تتعلمه هنا ينطبق أيضًا على Claude Code وCodex وCursor.

ماذا تحتاج قبل الاستدعاء الأول؟

مفتاحًا. إما أن ينشئه شخص على https://app.shager.ai/dashboard/agents بالصلاحيات التي تحتاج إليها، وإما أن ينشئ وكيلك بيئة اختبار عبر التسجيل الذاتي. وتعمل الصلاحيات على النحو التالي:

الصلاحية ما تسمح به
read whoami، وسرد مساحات العمل والحسابات والمجموعات والمنشورات، وقراءة منشور، والتحليلات
write إنشاء مساحات العمل والمجموعات والوسائط ومسودات المنشورات وروابط الربط وطلبات الموافقة، والإلغاء
publish الجدولة، بما في ذلك create_post مع schedule_at
export SHAGER_API_KEY="shgr_live_your_key_here"
export API="https://app.shager.ai/api/v1"
طلب curl ينشئ منشورًا عبر REST API الخاصة بـ Shager: النص، ومجموعة الحسابات، والرابط المُتتبَّع، وموعد النشر.
العمليات نفسها التي يوفرها خادم 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، فالجدولة وروابط الربط محظورة إلى أن يتولى إنسان ملكية المفتاح. وإذا غابت publish عن scopes، فبإمكانك بناء مسودات لكن لا يمكنك جدولتها. معرفة ذلك مسبقًا تجنّبك لاحقًا خطأ 403 محيّرًا.

الاستدعاء 2: اختر مساحة عمل أو أنشئ واحدة

مساحة العمل تمثل عادةً عميلًا واحدًا أو علامة تجارية واحدة.

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 أن المنشورات يجب أن يوافق عليها العميل قبل جدولتها، وهو إعداد افتراضي جيد للعملاء الجدد.

صدّر المعرّف من الاستجابة كي تعمل الأوامر التالية:

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. المجموعات هي طريقتك لمخاطبة أربعين حسابًا دون سرد أربعين معرّفًا؛ مرّر group_ids إلى create_post فيُضمَّن كل حساب نشط في المجموعة.

إن لم تكن في مساحة العمل حسابات بعد، فأنشئ رابط ربط عبر POST /workspaces/{workspace_id}/connect-links وأرسله إلى صاحب الحسابات. سيربط بنفسه حسابات Facebook أو Instagram أو YouTube أو X أو LinkedIn أو TikTok، من دون تسجيل الدخول إلى Shager.

مخطط: موجز، ثم مسودة لكل حساب، ثم موافقة العميل، ثم نشر موزّع على فترات، ثم تقرير نقرات لكل حساب.
خمس مراحل ثابتة. الموافقة على كل منشور اختيارية لكل عميل، أما النشر فيتطلب مالكًا بشريًا وصلاحية نشر منفصلة للمفتاح.

الاستدعاء 4: ارفع الوسائط من رابط

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. وفي الريلز وShorts والقصص، مرّر width وheight وduration_ms إن كنت تعرفها. بذلك يتحقق Shager من قواعد الصيغة في كل شبكة قبل جدولة المنشور، بدلًا من أن يفشل عند الإرسال.

الاستدعاء 5: أنشئ مسودة بنص لكل حساب

هذا هو الاستدعاء الأهم، وهذه صيغته بلغة TypeScript مع fetch عادية، ومعها دالة مساعدة صغيرة ستعيد استخدامها:

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 حيث تدعمها الشبكة، وفي غير ذلك يُحسم الاختيار بين SHORT وREEL لكل شبكة على حدة. ولا تؤثر youtube_title وyoutube_privacy إلا في حسابات YouTube.
  3. يُنتج cta_url رابطًا قصيرًا ومجموعة وسوم UTM مستقلة لكل حساب، مع utm_content يحدد الحساب. وعلى ذلك تقوم نسبة العملاء المحتملين إلى كل حساب.
  4. يضبط stagger_seconds توقفًا عشوائيًا بين الحسابات على الشبكة نفسها. القيمة الافتراضية [30, 90].

من دون schedule_at تكون النتيجة مسودة. احتفظ بمعرّفها للاستدعاءات التالية عبر export POST_ID="the_post_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 من كل وجهة وفق قواعد شبكتها. وإن كان أي حساب سيرفض المنشور، يصلك خطأ 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 صفًا لكل وجهة يتضمن 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 معرّف خاطئ لمساحة العمل أو المنشور أو الحساب أعد السرد؛ المعرّفات خاصة بكل مساحة عمل
409 not_scheduled إلغاء منشور غير مجدول اقرأ حالة المنشور أولًا
422 rejected فشلت إحدى قواعد الشبكة اعرض الرسالة؛ فهي تسمّي المشكلة
429 rate_limited تجاوز 120 طلبًا في الدقيقة لكل مفتاح تمهّل ثم أعد المحاولة

نادرًا ما يصطدم عميل مصمم جيدًا بحد المعدل. استدعاء create_post واحد يغطي مئات الحسابات، فلا حاجة إلى استدعاء لكل حساب.

أسئلة شائعة

هل توجد SDK؟

ليس واحدة مخصصة. يعمل مستند OpenAPI 3.1 مع المولّدات القياسية إن أردت عملاء بأنواع محددة، والـ API صغير بما يكفي لأن تكون دالة مساعدة كالتي أعلاه كل ما تحتاج إليه عادةً. وأداة سطر أوامر لـ Shager في الطريق.

هل REST وMCP متطابقان فعلًا؟

نعم. كل أداة في MCP تقابل عملية REST واحدة بالاسم والمدخلات والصلاحيات وحد المعدل وتسجيل التدقيق نفسها. استخدم REST من السكربتات والخدمات، وMCP من عملاء الوكلاء. القائمة الكاملة للأدوات في صفحة الوكلاء.

كيف أنشر نصًا مختلفًا على Facebook وYouTube في المنشور نفسه؟

استخدم per_channel مع معرّف كل حساب ونصه، وyoutube_title لعنوان YouTube. كائن منشور واحد ووجهات كثيرة، لكلٍّ منها نصها وصيغتها وتعليقها الأول إن احتجت إليه.

الخطوة التالية

حين يعمل هذا التسلسل يدويًا بلا أخطاء، غلّفه في شيء يستطيع الوكيل تكراره. يشرح مقال بناء مهارة Claude لـ Shager كيف تجمع هذه الاستدعاءات والقواعد المحيطة بها في مهارة قابلة لإعادة الاستخدام.

جرّبه على حساباتك.

مجانًا خلال فترة الإطلاق، دون بطاقة. اربط حساباتك، واكتب مرة واحدة، وShager ينشر ويقيس.