Stepeee Stepeee منصة الذكاء الاصطناعي المؤتمتة بالكامل

طريقة الاتصال

1

تحقق من مفتاح API الخاص بك

يمكنك التحقق منه من القائمة أعلى اليسار > الإعدادات > الحساب > مفاتيح API.

2

أضفه إلى ترويسة الطلب

أضف مفتاح API الصادر إلى ترويسة Authorization بصيغة Bearer.

3

أرسل طلبًا إلى رابط URL الأساسي

أرسل الطلبات إلى رابط URL الأساسي أدناه متبوعًا بمسار نقطة النهاية.

لكل حساب مفتاح API واحد. عند تغيير المفتاح يتوقف المفتاح القديم عن العمل فورًا. احتفظ بمفتاحك بعيدًا عن الآخرين.

رابط URL الأساسي

https://stepeee.com/public-api/v1

مثال على الطلب

curl "https://stepeee.com/public-api/v1/projects" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;

صيغة الاستجابة والأخطاء

تُعاد جميع الاستجابات بصيغة الغلاف التالية.

عند النجاح

{ "data": ... }

عند حدوث خطأ

{ "error": { "code": "...", "message": "...", "details": { ... } } }

رموز الحالة

الحالةالمعنى
401مفتاح API مفقود أو غير صحيح أو أُلغي
403ليست لديك صلاحية لهذا الطلب (مثل استدعاء نقطة نهاية تتطلب خطة Pro أو أعلى بمفتاح API لحساب أدنى من خطة Pro، أو طلب عضو من الفريق بدور موظف لسجل استخدام Token الخاص بالفريق)
404المورد غير موجود (يشمل ذلك أيضًا حالات عدم وجود صلاحية الوصول)
405لا يمكن استخدام طريقة HTTP هذه مع هذا المسار
409لا يمكن تنفيذ هذه العملية في الحالة الحالية (مثل حذف محتوى تعمل أتمتته، أو أن طلبًا بالـ Idempotency-Key نفسه لا يزال قيد المعالجة). استخدم error.code لمعرفة السبب
422المعاملات غير صحيحة أو لا يمكن قبول الطلب. عند validation_error يحتوي error.details على سبب كل معامل
429تم تجاوز حد المعدل
500حدث خطأ غير متوقع
503تعذّر بدء العملية (مثل فشل بدء تشغيل الأتمتة). يُرجى إعادة المحاولة لاحقًا

المواصفات المشتركة

ما يمكنك الوصول إليه وتغييره

يمكنك قراءة وتغيير ما يراه مالك مفتاح API في التطبيق نفسه. فإضافةً إلى مشاريعك، يستطيع مالك الفريق والمشرفون في خطة Team قراءة جميع مشاريع الفريق وتغييرها، ويستطيع الموظفون قراءة المشاريع التي مُنحت لهم صلاحيتها وتغييرها. وتُعيد الموارد الواقعة خارج هذا النطاق 404 كما لو لم تكن موجودة.

البيانات المحذوفة

لا تُعاد المشاريع والمفاهيم والعناوين والمحتوى والمواد المحذوفة، بما في ذلك الفترة التي تسبق حذفها نهائيًا. وعند حذف عنوان أو مفهوم لا يُعاد المحتوى التابع له أيضًا.

تقسيم الصفحات

تستخدم القوائم page (بدءًا من 1) وper_page (من 1 إلى 100، والافتراضي 20) لتحديد النطاق المُعاد. ويحتوي meta على العدد الإجمالي (total) والصفحة الحالية (current_page) وعدد العناصر في الصفحة (per_page) والصفحة الأخيرة (last_page).

التاريخ والوقت

جميع التواريخ والأوقات في الاستجابات بتوقيت UTC وبصيغة ISO 8601 (مثل 2026-10-21T09:30:00Z). وتقبل المعاملات from / to تاريخًا (2026-10-21) أو تاريخًا ووقتًا (2026-10-21T09:30:00) أو تاريخًا ووقتًا مع فرق التوقيت (2026-10-21T18:30:00+09:00)، وتُعامَل القيم التي لا تحتوي على فرق التوقيت على أنها بتوقيت UTC. ويشمل from تلك اللحظة نفسها، وعند تمرير تاريخ فقط إلى to يُشمل اليوم كله حتى 23:59:59.

المعرّفات

تُحدَّد الموارد بمعرّفات عامة من حروف وأرقام مثل project_unique وvariation_unique. ولا تتغير المعرّفات.

روابط الملفات

تُعاد روابط الصور والفيديو والصوت بالشكل {url, expires_at}. تستخدم الملفات الخاصة روابط موقّعة تتوقف عن العمل بعد expires_at (بعد ساعة من إصدارها). ولمواصلة استخدام الملف نزّله واحفظه قبل انتهاء صلاحيته، أو استدعِ API مجددًا للحصول على رابط جديد. أما الملفات المضبوطة على العام فتستخدم روابط لا تنتهي صلاحيتها، وتكون قيمة expires_at هي null.

أنواع القيم

تُعاد قيم مثل status وplatform بوصفها سلاسل بأحرف إنجليزية صغيرة كما هي مذكورة في هذه الصفحة. وقد تُضاف قيم جديدة مع إضافة الميزات، لذا احرص على ألا يتوقف برنامجك عند استلام قيمة لا يعرفها.

المبالغ

المبالغ أعداد صحيحة بأصغر وحدة للعملة (السنت لـ USD والين لـ JPY). وتكون العملة في currency برمز ISO 4217 بأحرف صغيرة (usd وjpy وغيرهما).

طلبات الكتابة (خطة Pro)

باستخدام طرق غير GET يمكنك تنفيذ عمليات مثل إضافة العناوين وحذف المحتوى وبدء الأتمتة والموافقة على المنشورات وتسجيل Webhook. وتُنفَّذ كل عملية بالمعالجة نفسها التي تجري عند تنفيذها في التطبيق، وتنطبق عليها القواعد نفسها. ولا تتاح طلبات الكتابة إلا عندما يكون مالك مفتاح API على خطة Pro أو أعلى، وإلا فتُعاد 403 plan_required. ويحصل أعضاء الفريق على 403 team_plan_lost إذا لم يعد مالك الفريق على خطة Team. غير أن إيقاف الأتمتة، وعرض نقاط Webhook وحذفها، وعرض المنشورات التي تنتظر المراجعة متاحة في أي خطة (لتتمكن من إيقاف الأتمتة والإشعارات الجارية حتى بعد تغيير خطتك). يُعيد الإنشاء 201، وتُعيد بقية العمليات 200.

Idempotency-Key

لكي تتمكن من إعادة العملية بأمان إذا انقطع الاتصال ولم تتلقَّ الاستجابة، تقبل بعض نقاط الكتابة الترويسة Idempotency-Key (النقاط التي تقبلها تذكرها في جدول معاملاتها، وهي إلزامية عند بدء الأتمتة). استخدم سلسلة فريدة تُنشئها لكل عملية (مثل UUID، من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة). إذا أعدت إرسال المحتوى نفسه (الطريقة والمسار والجسم) بالمفتاح نفسه فلن تُنفَّذ العملية مرة أخرى، بل تُعاد الاستجابة الأولى كما هي مع الترويسة Idempotent-Replayed: true. وتبقى المفاتيح صالحة لمدة 24 ساعة لكل مالك مفتاح API. وإرسال محتوى مختلف بالمفتاح نفسه يُعيد 422 idempotency_key_reused، وإذا كان الطلب الأول لا يزال قيد المعالجة فتُعاد 409 idempotency_request_in_progress. ولا تُحفظ استجابات 5xx، لذا يمكنك إعادة المحاولة بالمفتاح نفسه. وفي النقاط التي تكون فيها الترويسة إلزامية، يُعيد غيابها 422 idempotency_key_required، وتُعيد الصيغة غير الصحيحة 422 idempotency_key_invalid.

حد المعدل

يمكنك إرسال ما يصل إلى 120 طلبًا في الدقيقة لكل مفتاح API (وتخضع طلبات الكتابة إضافةً إلى ذلك لحد معدل الكتابة الموضح أدناه). ويمكنك معرفة X-RateLimit-Limit (الحد) وX-RateLimit-Remaining (المتبقي) من ترويسات الاستجابة. وعند تجاوز الحد تُعاد 429، ويحتوي Retry-After على عدد الثواني حتى يمكنك إعادة المحاولة.

حد معدل الكتابة

تقتصر طلبات الكتابة (الطرق غير GET) على 30 طلبًا في الدقيقة لكل مفتاح API، إضافةً إلى حد 120 طلبًا في الدقيقة. وعند تجاوزه تُعاد 429 rate_limited، ويحتوي Retry-After على عدد الثواني حتى يمكنك إعادة المحاولة. وفي طلبات الكتابة تعرض ترويستا الاستجابة X-RateLimit-Limit وX-RateLimit-Remaining قيم الحد الذي تبقّى فيه عدد أقل من الطلبات من بين الحدين.

رموز الأخطاء

عند حدوث خطأ يحتوي error.code على نوع الخطأ، ويحتوي error.message على وصف باللغة الإنجليزية. الرموز التي قد تُعيدها أي نقطة نهاية مذكورة أدناه. أما الرموز الخاصة بنقطة نهاية معينة (مثل title_limit_reached) فمذكورة في جدول أخطاء تلك النقطة. استخدم error.code في برنامجك للتمييز بين الأخطاء.

الرمزالمعنى
unauthorizedمفتاح API مفقود أو غير صحيح أو أُلغي (401)
forbiddenليست لديك صلاحية (403)
plan_requiredالعملية تتطلب خطة Pro أو أعلى (403)
team_plan_lostلم يعد مالك الفريق على خطة Team، لذا لا يستطيع أعضاء الفريق الكتابة (403)
not_foundالمورد غير موجود أو خارج نطاق ما يمكنك الوصول إليه (404)
method_not_allowedلا يمكن استخدام طريقة HTTP هذه مع هذا المسار (405)
conflictلا يمكن تنفيذ هذه العملية في الحالة الحالية (409)
idempotency_request_in_progressطلب بالـ Idempotency-Key نفسه لا يزال قيد المعالجة (409)
validation_errorالمعاملات غير صحيحة (422)
idempotency_key_requiredالترويسة Idempotency-Key مفقودة في نقطة نهاية تكون فيها إلزامية (422)
idempotency_key_invalidقيمة Idempotency-Key ليست من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة (422)
idempotency_key_reusedاستُخدم الـ Idempotency-Key نفسه لطلب بمحتوى مختلف (422)
rate_limitedتم تجاوز حد المعدل (429)
internal_errorحدث خطأ غير متوقع (500)

مثال على 422

{
  "error": {
    "code": "validation_error",
    "message": "The per page field must not be greater than 100.",
    "details": {
      "per_page": ["The per page field must not be greater than 100."]
    }
  }
}

الحساب

معلومات حساب مالك مفتاح API. يمكنك الحصول على الخطة ورصيد Token والاستخدام والتخزين والمدفوعات وحالة برنامج الإحالة.

GET › /me

معلومات الحساب

يحصل على الملف الشخصي لمالك مفتاح API وخطته وحدود الخطة والفريق الذي ينتمي إليه.

حقول الاستجابة
الحقلالنوعالوصف
user_unique string معرّف المستخدم
nickname string | null الاسم المستعار
email string البريد الإلكتروني المستخدم لتسجيل الدخول
plan string الخطة. free / vault / plus / pro / team
limits object حدود الخطة الحالية. null تعني بلا حد
limits.projects integer | null عدد المشاريع التي يمكنك إنشاؤها
limits.moviemode_variations_per_title integer | null عدد عناصر المحتوى لكل عنوان فيديو
limits.blogmode_variations_per_title integer | null عدد عناصر المحتوى لكل عنوان مدونة
limits.carouselmode_variations_per_title integer | null عدد عناصر المحتوى لكل عنوان كاروسيل
limits.postmode_variations_per_concept integer | null عدد عناصر المحتوى لكل مفهوم منشورات
limits.team boolean هل ميزات الفريق متاحة
limits.script_duration_max integer أقصى طول لنص الفيديو (بالثواني)
limits.reading_time_max integer أقصى وقت قراءة لمقالة المدونة (بالدقائق)
limits.reading_time_max_fulltext integer أقصى وقت قراءة لمقالة المدونة عند قراءة النص كاملًا بصوت مسموع (بالدقائق)
limits.slide_count_max integer أقصى عدد لشرائح الكاروسيل
limits.cta_enabled boolean هل عبارة الحث على اتخاذ إجراء (CTA) متاحة، مثل الشريحة الأخيرة التي تدعو إلى إجراء
limits.thread_enabled boolean هل السلاسل والمنشورات المصحوبة بصور متاحة للمنشورات
limits.schedule_title_variation_max integer عدد العناوين وعناصر المحتوى التي يمكن تحديدها دفعة واحدة عند إنشاء العناصر المجدولة
limits.schedule_variation_create_max integer عدد عناصر المحتوى التي يمكن إنشاؤها دفعة واحدة عند إنشاء العناصر المجدولة
language string | null لغة عرض التطبيق
timezone string المنطقة الزمنية المضبوطة (بصيغة IANA، مثل Asia/Tokyo)
team object | null الفريق الذي تنتمي إليه. null إذا لم تكن على خطة Team أو لم تنتمِ إلى فريق
team.team_unique string معرّف الفريق
team.role string دورك في الفريق. owner (المالك) / admin (المشرف) / staff (الموظف)
created_at string تاريخ إنشاء الحساب
مثال على الطلب
curl "https://stepeee.com/public-api/v1/me" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "user_unique": "aB3dE5gH7j",
    "nickname": "Alice",
    "email": "alice@example.com",
    "plan": "pro",
    "limits": {
      "projects": 3,
      "moviemode_variations_per_title": null,
      "blogmode_variations_per_title": null,
      "carouselmode_variations_per_title": null,
      "postmode_variations_per_concept": null,
      "team": false,
      "script_duration_max": 1800,
      "reading_time_max": 15,
      "reading_time_max_fulltext": 4,
      "slide_count_max": 20,
      "cta_enabled": true,
      "thread_enabled": true,
      "schedule_title_variation_max": 50,
      "schedule_variation_create_max": 5
    },
    "language": "ja",
    "timezone": "Asia/Tokyo",
    "team": null,
    "created_at": "2026-09-01T10:20:30Z"
  }
}
GET › /me/subscription

الاشتراك

يحصل على حالة خطتك الحالية وفترة الفوترة وأي إلغاء مجدول وأي تغيير مجدول للخطة. ويحصل أعضاء الفريق على اشتراك مالك الفريق.

حقول الاستجابة
الحقلالنوعالوصف
plan string الخطة. free / vault / plus / pro / team
status string حالة الاشتراك. active (نشط) / past_due (متأخر الدفع) / trialing (فترة تجريبية) / none (لا توجد خطة مدفوعة)
managed_by_team boolean هل تستخدم الخطة من خلال اشتراك مالك الفريق. عند true تكون حقول الفترة والإلغاء هي قيم اشتراك المالك
current_period_start string | null بداية فترة الفوترة الحالية
current_period_end string | null نهاية فترة الفوترة الحالية (تاريخ الفوترة التالي)
cancel_at_period_end boolean هل الاشتراك مجدول للإلغاء في نهاية فترة الفوترة الحالية
cancel_at string | null موعد إلغاء الاشتراك
canceled_at string | null موعد طلب الإلغاء
scheduled_change object | null تغيير الخطة المجدول (null إن لم يوجد)
scheduled_change.plan string الخطة بعد التغيير
scheduled_change.effective_at string | null موعد سريان التغيير
مثال على الطلب
curl "https://stepeee.com/public-api/v1/me/subscription" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/subscription",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/subscription", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/subscription")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/subscription"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/subscription");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "plan": "pro",
    "status": "active",
    "managed_by_team": false,
    "current_period_start": "2026-10-01T00:00:00Z",
    "current_period_end": "2026-11-01T00:00:00Z",
    "cancel_at_period_end": false,
    "cancel_at": null,
    "canceled_at": null,
    "scheduled_change": {
      "plan": "plus",
      "effective_at": "2026-11-01T00:00:00Z"
    }
  }
}
GET › /me/tokens

رصيد Token

يحصل على رصيد Token المتاح لك. وفي الفريق يُعيد الرصيد المشترك للفريق والحصة المخصصة لك.

حقول الاستجابة
الحقلالنوعالوصف
balance integer الرصيد
reserved integer الكمية المحجوزة للمهام قيد التشغيل
available integer الكمية التي يمكنك استخدامها الآن (الرصيد مطروحًا منه الكمية المحجوزة)
wallet string personal (رصيدك الخاص) / team (الرصيد المشترك للفريق)
team_quota object | null حصتك التي حددها مالك الفريق. null عند استخدام رصيدك الخاص ولمالك الفريق
team_quota.unlimited boolean هل الحصة بلا حد
team_quota.view_only boolean هل يمكنك العرض فقط دون استخدام Token
team_quota.budget integer | null الحد لكل فترة (null تعني بلا حد، و0 تعني العرض فقط)
team_quota.used integer الكمية المستخدمة في الفترة الحالية
team_quota.available integer | null الكمية المتبقية في الفترة الحالية (null إذا كانت بلا حد)
team_quota.period string | null فترة الحد. day / week / month (null عند عدم وجود حد)
team_quota.next_reset_at string | null موعد إعادة تعيين الاستخدام
auto_purchase.enabled boolean هل الشراء التلقائي عند انخفاض الرصيد مفعّل
auto_purchase.plan string | null باقة Token التي تُشترى تلقائيًا (مثل token_100). null عند التعطيل
auto_purchase.threshold integer يتم الشراء تلقائيًا عندما ينخفض الرصيد عن هذه القيمة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/me/tokens" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/tokens",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/tokens", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/tokens")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/tokens"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/tokens");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "balance": 90000,
    "reserved": 1200,
    "available": 88800,
    "wallet": "team",
    "team_quota": {
      "unlimited": false,
      "view_only": false,
      "budget": 10000,
      "used": 2500,
      "available": 7500,
      "period": "week",
      "next_reset_at": "2026-10-26T00:00:00Z"
    },
    "auto_purchase": {
      "enabled": true,
      "plan": "token_100",
      "threshold": 5000
    }
  }
}
GET › /me/token-usage

استخدام Token

يحصل على استخدام Token والإضافات يوميًا أو شهريًا. يُجمَع الاستخدام يومًا بيوم، ويظهر اليوم السابق نحو الساعة 2:45 بتوقيت UTC (لا يشمل استخدام اليوم الحالي). أما الإضافات الناتجة عن الشراء والمكافآت فتظهر فورًا.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
from الاستعلام string (YYYY-MM-DD) اختياري — تاريخ البداية (UTC). قبل to بـ 29 يومًا عند الإغفال
to الاستعلام string (YYYY-MM-DD) اختياري — تاريخ النهاية (UTC، شاملًا ذلك اليوم). اليوم الحالي عند الإغفال. يمكن أن يصل النطاق إلى 366 يومًا
group_by الاستعلام string اختياري day وحدة التجميع. day (يومي) / month (شهري)
حقول الاستجابة
الحقلالنوعالوصف
data[].period string الفترة. YYYY-MM-DD للتجميع اليومي وYYYY-MM للتجميع الشهري. لا تُدرج الفترات التي لا استخدام فيها ولا إضافة
data[].consumed integer الاستخدام
data[].added integer الإضافات (بعد طرح النقصان مثل إلغاء مكافآت الإحالة)
data[].consumed_by_type object الاستخدام حسب النوع (text / image / video / audio وغيرها)
data[].added_by_type object الإضافات حسب النوع. purchase (شراء) / bonus (مكافأة) / refund (استرداد) / referral_revoke (إلغاء مكافأة الإحالة، قيمة سالبة)
meta.from string تاريخ بداية الفترة المجمّعة
meta.to string تاريخ نهاية الفترة المجمّعة
meta.group_by string وحدة التجميع
meta.total_consumed integer إجمالي الاستخدام في الفترة
meta.total_added integer إجمالي الإضافات في الفترة
الأخطاء
الحالةالرمزمتى يحدث
403 forbidden موظف يستخدم Token الخاص بالفريق (لا يستطيع الحصول على سجل استخدام Token للفريق إلا مالك الفريق والمشرفون)
422 validation_error النطاق أطول من 366 يومًا، أو to قبل from، أو تعذّرت قراءة قيمة على أنها تاريخ، أو group_by ليست day / month
مثال على الطلب
curl "https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/token-usage?from=2026-10-01&to=2026-10-20&group_by=day");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "period": "2026-10-18",
      "consumed": 450,
      "added": 0,
      "consumed_by_type": { "image": 300, "text": 150 },
      "added_by_type": {}
    },
    {
      "period": "2026-10-20",
      "consumed": 1000,
      "added": 4800,
      "consumed_by_type": { "video": 1000 },
      "added_by_type": { "purchase": 5000, "referral_revoke": -200 }
    }
  ],
  "meta": {
    "from": "2026-10-01",
    "to": "2026-10-20",
    "group_by": "day",
    "total_consumed": 1450,
    "total_added": 4800
  }
}
GET › /me/storage

التخزين

يحصل على استخدام التخزين والسعة وتفصيل حسب نوع الملف. وفي الفريق يُعيد التخزين المشترك للفريق.

حقول الاستجابة
الحقلالنوعالوصف
used_bytes integer الاستخدام (بالبايت). يساوي مجموع by_type
capacity_bytes integer | null السعة (بالبايت). null تعني بلا حد، و0 تعني عدم وجود تخزين (خطة Free)
by_type[].file_type string | null نوع الملف. material (مادة) / image (صورة) / video (فيديو) / bgm / voice (صوت) / movie (فيديو مكتمل)
by_type[].bytes integer استخدام هذا النوع (بالبايت)
by_type[].files integer عدد ملفات هذا النوع
مثال على الطلب
curl "https://stepeee.com/public-api/v1/me/storage" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/storage",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/storage", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/storage")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/storage"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/storage");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "used_bytes": 734003200,
    "capacity_bytes": null,
    "by_type": [
      { "file_type": "image", "bytes": 52428800, "files": 120 },
      { "file_type": "movie", "bytes": 629145600, "files": 8 },
      { "file_type": "voice", "bytes": 52428800, "files": 15 }
    ]
  }
}
GET › /me/payments

سجل المدفوعات

يحصل على المدفوعات مثل رسوم الخطة وشراء Token من الأحدث إلى الأقدم. ويمكنك استخدامه لاستيراد المدفوعات إلى نظام المحاسبة لديك.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
status الاستعلام string اختياري — التصفية حسب حالة الدفع (مفصولة بفواصل). succeeded / refunded / partially_refunded. الكل عند الإغفال
type الاستعلام string اختياري — التصفية حسب نوع الدفع (مفصولة بفواصل). القيم نفسها في data[].type
from الاستعلام string اختياري — يُعيد فقط العناصر التي أُنشئت في هذا التاريخ والوقت أو بعدهما
to الاستعلام string اختياري — يُعيد فقط العناصر التي أُنشئت في هذا التاريخ والوقت أو قبلهما
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].payment_unique string معرّف الدفعة
data[].type string النوع. token_first_time (أول شراء لـ Token) / token_regular (شراء Token) / subscription_vault وsubscription_plus وsubscription_pro وsubscription_team (رسوم الخطط) / smm_application وsmm_contract وsmm_usage (رسوم إدارة حساب X)
data[].description string اسم الدفعة (بالإنجليزية)
data[].status string الحالة. succeeded (مدفوع) / refunded (مسترد بالكامل) / partially_refunded (مسترد جزئيًا)
data[].currency string العملة (رمز ISO 4217 بأحرف صغيرة)
data[].amount_subtotal integer المبلغ قبل الضريبة (بأصغر وحدة)
data[].tax_amount integer الضريبة (بأصغر وحدة)
data[].amount_total integer المبلغ شاملًا الضريبة (بأصغر وحدة)
data[].line_items[] object البنود. type (base_plan: رسوم الخطة / storage_addon: تخزين إضافي / extra_member: عضو إضافي) وquantity (الكمية) وamount (المبلغ) وdescription (الوصف، null إن لم يوجد)
data[].receipt_url string | null رابط الإيصال (Stripe). قد يتعذّر فتحه بعد مرور مدة على إصداره
data[].invoice_pdf_url string | null رابط ملف PDF للفاتورة (Stripe). قد يتعذّر فتحه بعد مرور مدة على إصداره
data[].created_at string وقت الدفع
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/payments?status=succeeded&per_page=10");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "payment_unique": "Xy12AbCd34Ef",
      "type": "subscription_team",
      "description": "Team Monthly",
      "status": "succeeded",
      "currency": "usd",
      "amount_subtotal": 5000,
      "tax_amount": 500,
      "amount_total": 5500,
      "line_items": [
        { "type": "base_plan", "quantity": 1, "amount": 4000, "description": "Team plan" },
        { "type": "extra_member", "quantity": 2, "amount": 1000, "description": null }
      ],
      "receipt_url": "https://pay.stripe.com/receipts/...",
      "invoice_pdf_url": "https://pay.stripe.com/invoice/.../pdf",
      "created_at": "2026-10-01T08:00:00Z"
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 10, "last_page": 1 }
}
GET › /me/referral

برنامج الإحالة

يحصل على رمز الإحالة الخاص بك وحالة الإحالات والمكافآت.

حقول الاستجابة
الحقلالنوعالوصف
code string | null رمز الإحالة (null إذا لم يكن لديك رمز بعد)
referral_url string | null رابط الإحالة (null إذا لم يكن لديك رمز إحالة)
is_active boolean هل رمز الإحالة مفعّل
reward_type string | null طريقة استلام المكافآت. cash (نقدًا) / token (Token). null إذا لم يكن لديك رمز إحالة
clicks integer عدد مرات فتح رابط الإحالة
signups integer عدد الأشخاص الذين سجّلوا عبر إحالتك
conversions integer عدد الأشخاص الذين اشتركوا في خطة مدفوعة عبر إحالتك
earned object المكافآت المؤكدة حتى الآن {amount (بأصغر وحدة), currency}
earned_tokens integer Token المستلمة حتى الآن
pending object المكافآت التي تنتظر التأكيد {amount, currency}
available object المكافآت التي يمكنك طلب استلامها {amount, currency}
مثال على الطلب
curl "https://stepeee.com/public-api/v1/me/referral" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/me/referral",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/me/referral", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/me/referral")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/me/referral"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/me/referral");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "code": "REFk5m2j8x9ab",
    "referral_url": "https://stepeee.com?ref=REFk5m2j8x9ab",
    "is_active": true,
    "reward_type": "cash",
    "clicks": 12,
    "signups": 4,
    "conversions": 2,
    "earned": { "amount": 1300, "currency": "usd" },
    "earned_tokens": 0,
    "pending": { "amount": 300, "currency": "usd" },
    "available": { "amount": 800, "currency": "usd" }
  }
}

المشاريع

احصل على المشاريع وبنية المفاهيم والعناوين داخلها.

GET › /projects

قائمة المشاريع

يحصل على المشاريع التي يمكنك الوصول إليها من الأحدث إلى الأقدم.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].project_unique string معرّف المشروع
data[].project_name string اسم المشروع
data[].description string | null وصف المشروع
data[].access_level string صلاحيتك. owner (مشروعك الخاص) / admin (صلاحية كاملة بصفتك مالك الفريق أو مشرفًا) / edit (صلاحية تعديل ممنوحة في الفريق)
data[].team object | null الفريق إذا كان المشروع مشروع فريق، وnull إذا كان المشروع خاصًا بك وحدك
data[].team.team_unique string معرّف الفريق
data[].is_readonly boolean هل المشروع للعرض فقط لأنه تجاوز الحد بعد خفض الخطة (يُلغى ذلك عند الترقية)
data[].readonly_since string | null وقت تحوّل المشروع إلى العرض فقط
data[].created_at string تاريخ الإنشاء
data[].updated_at string تاريخ التحديث
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "project_unique": "a1b2c3d4e5",
      "project_name": "Sample Project",
      "description": "Sample project description",
      "access_level": "owner",
      "team": null,
      "is_readonly": false,
      "readonly_since": null,
      "created_at": "2026-01-10T09:00:00Z",
      "updated_at": "2026-10-01T12:00:00Z"
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /projects/{project_unique}

تفاصيل المشروع

يحصل على تفاصيل مشروع واحد مع عدد المفاهيم والعناوين لكل وضع وعدد عناصر المحتوى حسب التقدّم.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
حقول الاستجابة
الحقلالنوعالوصف
project_unique string معرّف المشروع
project_name string اسم المشروع
description string | null وصف المشروع
access_level string صلاحيتك. owner (مشروعك الخاص) / admin (صلاحية كاملة بصفتك مالك الفريق أو مشرفًا) / edit (صلاحية تعديل ممنوحة في الفريق)
team object | null الفريق إذا كان المشروع مشروع فريق، وnull إذا كان المشروع خاصًا بك وحدك
team.team_unique string معرّف الفريق
is_readonly boolean هل المشروع للعرض فقط لأنه تجاوز الحد بعد خفض الخطة (يُلغى ذلك عند الترقية)
readonly_since string | null وقت تحوّل المشروع إلى العرض فقط
created_at string تاريخ الإنشاء
updated_at string تاريخ التحديث
scope string المنطقة المستهدفة. global (غير محددة) / region (بلد محدد)
scope_region string | null البلد المستهدف (ISO 3166-1 alpha-2، مثل JP). null عند global
counts.{mode}.concepts integer عدد المفاهيم لكل وضع (moviemode / blogmode / carouselmode / postmode)
counts.{mode}.titles integer | null عدد العناوين (null لـ postmode لأنه بلا عناوين)
counts.{mode}.contents object عدد عناصر المحتوى {total (الإجمالي), not_started (لم يبدأ), in_progress (قيد الإنتاج), complete (مكتمل)}
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "project_unique": "a1b2c3d4e5",
    "project_name": "Sample Project",
    "description": "Sample project description",
    "access_level": "owner",
    "team": null,
    "is_readonly": false,
    "readonly_since": null,
    "created_at": "2026-01-10T09:00:00Z",
    "updated_at": "2026-10-01T12:00:00Z",
    "scope": "region",
    "scope_region": "JP",
    "counts": {
      "moviemode": {
        "concepts": 2,
        "titles": 5,
        "contents": { "total": 8, "not_started": 1, "in_progress": 3, "complete": 4 }
      },
      "blogmode": {
        "concepts": 1,
        "titles": 3,
        "contents": { "total": 3, "not_started": 0, "in_progress": 1, "complete": 2 }
      },
      "carouselmode": {
        "concepts": 0,
        "titles": 0,
        "contents": { "total": 0, "not_started": 0, "in_progress": 0, "complete": 0 }
      },
      "postmode": {
        "concepts": 1,
        "titles": null,
        "contents": { "total": 1, "not_started": 0, "in_progress": 1, "complete": 0 }
      }
    }
  }
}
GET › /projects/{project_unique}/concepts

قائمة المفاهيم

يحصل على المفاهيم داخل المشروع عبر جميع الأوضاع من الأحدث إلى الأقدم.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
mode الاستعلام string اختياري — التصفية حسب الوضع. يمكنك تمرير أكثر من قيمة من moviemode (فيديو) وblogmode (مدونة) وcarouselmode (كاروسيل) وpostmode (منشور) مفصولة بفواصل. جميع الأوضاع عند الإغفال
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].concept_unique string معرّف المفهوم
data[].mode string moviemode (فيديو) / blogmode (مدونة) / carouselmode (كاروسيل) / postmode (منشور)
data[].concept_name string اسم المفهوم
data[].title_count integer | null عدد العناوين (null لـ postmode)
data[].content_count integer عدد عناصر المحتوى
data[].created_at string تاريخ الإنشاء
data[].updated_at string تاريخ التحديث
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts?mode=moviemode,postmode");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "concept_unique": "pC7d2KqLx01m",
      "mode": "postmode",
      "concept_name": "SaaS growth tips",
      "title_count": null,
      "content_count": 1,
      "created_at": "2026-10-02T09:00:00Z",
      "updated_at": "2026-10-02T09:00:00Z"
    },
    {
      "concept_unique": "mC4f9TnB2q",
      "mode": "moviemode",
      "concept_name": "Cat facts",
      "title_count": 3,
      "content_count": 5,
      "created_at": "2026-09-20T03:00:00Z",
      "updated_at": "2026-09-28T03:00:00Z"
    }
  ],
  "meta": { "total": 2, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /projects/{project_unique}/concepts/{concept_unique}

تفاصيل المفهوم

يحصل على تفاصيل مفهوم واحد. تتضمن مفاهيم الفيديو والمدونة والكاروسيل قائمة العناوين، وتتضمن مفاهيم المنشورات (postmode) شخصية الناشر وقواعد النشر.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
concept_unique المسار string إلزامي — معرّف المفهوم
حقول الاستجابة
الحقلالنوعالوصف
concept_unique / mode / concept_name / title_count / content_count / created_at / updated_at — مثل قائمة المفاهيم
description string | null وصف المفهوم
scope string المنطقة المستهدفة. global (غير محددة) / region (بلد محدد)
scope_region string | null البلد المستهدف (ISO 3166-1 alpha-2، مثل JP). null عند global
default_template_unique string | null قالب الإعداد المستخدم للمحتوى الجديد (template_unique في قائمة القوالب). null عند عدم التعيين أو لـ postmode
titles array | null قائمة العناوين (من الأحدث إلى الأقدم). null لـ postmode
titles[].title_unique string معرّف العنوان
titles[].title_name string العنوان
titles[].article_type string | null النوع. standard (عادي) / news (أخبار) لـ moviemode، وstandard / news / promotion (تعريف بمنتج) لـ blogmode. null لـ carouselmode
titles[].content_count integer عدد عناصر المحتوى لهذا العنوان
persona object | null شخصية الناشر (لـ postmode فقط، null إذا لم تُنشأ)
persona.persona_unique string معرّف الشخصية
persona.gender string الجنس. male / female / undisclosed (غير مُفصح عنه)
persona.generation string الفئة العمرية. 10s / 20s / 30s / 40s / 50s / 60s_plus
persona.region string | null رمز بلد المنطقة الثقافية
persona.keywords object الكلمات المفتاحية للشخصية. occupation (المهنة) وindustry (المجال) وresidence (السكن) وworkstyle (أسلوب العمل) وhousehold (الأسرة) وpersonality (الطباع) سلاسل نصية، وinterest (الاهتمامات) وexpertise (الخبرة) مصفوفات من السلاسل. تُدرج المضبوطة منها فقط
persona.description string نص الشخصية
persona.casual_description string | null نص الشخصية المستخدم للمنشورات اليومية (null إن لم يوجد)
persona.taboos array ما يجب تجنبه في المنشورات
persona.timezone_mode string طريقة تحديد المنطقة الزمنية. auto (من المنطقة، أو من لغة النشر عند عدم وجود منطقة) / specify (المنطقة الزمنية المحددة)
persona.timezone string | null المنطقة الزمنية المستخدمة لجدول النشر (بصيغة IANA). null عند تعذّر تحديدها لأن قواعد النشر لم تُنشأ
rule object | null قواعد النشر (لـ postmode فقط، null إذا لم تُنشأ)
rule.rule_unique string معرّف قواعد النشر
rule.language string لغة النشر
rule.formality string أسلوب الكلام. very_casual (عفوي جدًا) / casual (عفوي) / normal (عادي) / polite (مهذب) / honorific (رسمي)
rule.emoji string الرموز التعبيرية. never (لا تُستخدم) / sometimes (أحيانًا) / often (كثيرًا) / always (دائمًا)
rule.line_break string كثافة فواصل الأسطر. none (بلا) / moderate (معتدلة) / frequent (كثيرة)
rule.post_type_share object نسبة كل نوع من المنشورات (%). assertion (رأي) / knowhow (معرفة عملية) / experience (تجربة) / casual (يومي)
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
404 not_found المفهوم غير موجود (Concept not found.)
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/concepts/pC7d2KqLx01m");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "concept_unique": "pC7d2KqLx01m",
    "mode": "postmode",
    "concept_name": "SaaS growth tips",
    "title_count": null,
    "content_count": 1,
    "created_at": "2026-10-02T09:00:00Z",
    "updated_at": "2026-10-02T09:00:00Z",
    "description": "Practical growth tips for SaaS founders",
    "scope": "global",
    "scope_region": null,
    "default_template_unique": null,
    "titles": null,
    "persona": {
      "persona_unique": "aV3kQ9mN2pRt",
      "gender": "female",
      "generation": "30s",
      "region": "JP",
      "keywords": { "occupation": "SaaS marketer", "interest": ["growth", "analytics"] },
      "description": "A B2B SaaS marketer with ten years of experience...",
      "casual_description": null,
      "taboos": ["politics"],
      "timezone_mode": "auto",
      "timezone": "Asia/Tokyo",
      "updated_at": "2026-10-02T09:10:00Z"
    },
    "rule": {
      "rule_unique": "rU5tW7yZ9aBc",
      "language": "ja",
      "formality": "polite",
      "emoji": "sometimes",
      "line_break": "moderate",
      "post_type_share": { "assertion": 40, "knowhow": 30, "experience": 20, "casual": 10 },
      "updated_at": "2026-10-02T09:20:00Z"
    }
  }
}

المحتوى

احصل على محتوى الفيديو والمدونة والكاروسيل والمنشورات عبر جميع الأوضاع. وفي التفاصيل يحتوي package على ما يُنشر إلى كل شبكة اجتماعية أو موقع (النص والصور والفيديو والتعليقات)، لذا يمكنك نقل المحتوى الذي أنشأته في Stepeee إلى أنظمتك.

GET › /projects/{project_unique}/contents

قائمة المحتوى

يحصل على المحتوى داخل المشروع (فيديو ومدونة وكاروسيل ومنشورات) عبر جميع الأوضاع. ويمكنك التصفية حسب التقدّم ولغة النشر وما إذا كان قد نُشر وغير ذلك.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
mode الاستعلام string اختياري — التصفية حسب الوضع. يمكنك تمرير أكثر من قيمة من moviemode (فيديو) وblogmode (مدونة) وcarouselmode (كاروسيل) وpostmode (منشور) مفصولة بفواصل. جميع الأوضاع عند الإغفال
status الاستعلام string اختياري — التصفية حسب التقدّم. not_started (لم يبدأ) / in_progress (قيد الإنتاج) / complete (مكتمل)
concept_unique الاستعلام string اختياري — يُعيد محتوى هذا المفهوم فقط
title_unique الاستعلام string اختياري — يُعيد محتوى هذا العنوان فقط (لا يُدرج postmode لأنه بلا عناوين)
language الاستعلام string اختياري — التصفية حسب لغة النشر (مثل ja أو en)
published الاستعلام string اختياري — تُعيد true المحتوى المنشور فقط، وتُعيد false المحتوى الذي لم يُنشر بعد فقط
from الاستعلام string اختياري — يُعيد فقط العناصر التي أُنشئت في هذا التاريخ والوقت أو بعدهما
to الاستعلام string اختياري — يُعيد فقط العناصر التي أُنشئت في هذا التاريخ والوقت أو قبلهما
sort الاستعلام string اختياري -created_at الترتيب. created_at / -created_at / updated_at / -updated_at (تعني - من الأحدث إلى الأقدم)
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].mode string moviemode (فيديو) / blogmode (مدونة) / carouselmode (كاروسيل) / postmode (منشور)
data[].variation_unique string معرّف المحتوى
data[].variation_no integer الرقم داخل العنوان (داخل المفهوم لـ postmode)
data[].title string العنوان (اسم المفهوم لـ postmode)
data[].concept object المفهوم الذي ينتمي إليه {concept_unique, concept_name}
data[].title_unique string | null معرّف العنوان الذي ينتمي إليه (null لـ postmode)
data[].language string | null لغة النشر (اللغة التي يراها المشاهدون والقرّاء). null إذا لم تُضبط
data[].status string التقدّم. not_started (لم يبدأ) / in_progress (قيد الإنتاج) / complete (عُيّن مكتملًا)
data[].progress.step_process integer الخطوة المكتملة (من 0 إلى 3)
data[].progress.is_complete boolean هل عُيّن مكتملًا
data[].is_readonly boolean هل هو للعرض فقط بسبب خفض الخطة
data[].confirmed_at string | null وقت تعيين المحتوى على أنه رُوجع (null لـ postmode وعند عدم المراجعة)
data[].published_platforms array الوجهات التي نُشر إليها (success / partial_success)
data[].created_at string تاريخ الإنشاء
data[].updated_at string تاريخ التحديث
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents?mode=blogmode&status=complete&published=false");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "mode": "blogmode",
      "variation_unique": "bmA1b2C3d4E5",
      "variation_no": 1,
      "title": "How to start a blog",
      "concept": { "concept_unique": "bC2x8RtY4u", "concept_name": "Blogging for beginners" },
      "title_unique": "bT9kL3mN5pQr",
      "language": "en",
      "status": "complete",
      "progress": { "step_process": 3, "is_complete": true },
      "is_readonly": false,
      "confirmed_at": "2026-10-03T08:00:00Z",
      "published_platforms": [],
      "created_at": "2026-10-01T03:00:00Z",
      "updated_at": "2026-10-03T08:00:00Z"
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /projects/{project_unique}/contents/{variation_unique}

تفاصيل المحتوى

يحصل على تفاصيل عنصر محتوى واحد. يحتوي package على ما يُنشر فعلًا إلى كل وجهة (وهو نفسه عند النشر من Stepeee). أما قائمة منشورات محتوى المنشورات (postmode) فاحصل عليها من الجدول.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
variation_unique المسار string إلزامي — معرّف المحتوى
حقول الاستجابة
الحقلالنوعالوصف
mode / variation_unique / … / updated_at — مثل قائمة المحتوى
publish[] object نتائج النشر حسب الوجهة
publish[].platform string وجهة النشر. youtube / tiktok / instagram / x / wordpress / webhook
publish[].status string نتيجة النشر. success (منشور) / failed (فشل) / scheduled (مجدول لدى الوجهة) / processing (قيد المعالجة) / partial_success (نجح النشر وفشلت خطوة مرافقة مثل تعيين الصورة المصغرة) / reviewing (نجح النشر وينتظر مراجعة الوجهة فلم يتحدد الرابط بعد)
publish[].post_url string | null رابط المنشور (null إذا لم يتحدد بعد)
publish[].posted_at string | null وقت النشر (null إذا لم يُنشر)
content object البيانات المُولّدة حسب الوضع. blogmode: body_html (نص المقالة) / carouselmode: scenario (بنية الشرائح؛ resolved_header وresolved_footer وresolved_texts هي النصوص بلغة النشر) / moviemode: movie_unique وdownload_url وthumbnail_url (الفيديو المحدد في Step3؛ الروابط صالحة لمدة ساعة من إصدارها) / postmode: posts (post_text وpost_type)
package object | null ما يُنشر. null لـ postmode
package.video (moviemode) object | null الفيديو المكتمل {file: {url, expires_at}, thumbnail: {url, expires_at} | null, duration_ms, width, height, size_bytes}. null إذا لم يوجد بعد
package.youtube.title (moviemode) string | null عنوان YouTube
package.youtube.description (moviemode) string | null وصف YouTube (يتضمن النص الثابت)
package.youtube.thumbnail (moviemode) object | null الصورة المصغرة لـ YouTube {url, expires_at, width, height}. null لمقاطع الفيديو العمودية (Shorts) التي لا تُعيَّن لها صورة مصغرة
package.tiktok.caption (moviemode) string | null تعليق TikTok
package.instagram.caption (moviemode / carouselmode) string | null تعليق Instagram (يتضمن النص الثابت)
package.instagram.cover (moviemode) object | null صورة غلاف Instagram {url, expires_at, width, height}
package.x.posts (moviemode / blogmode / carouselmode) array منشورات X. تُنشر منشوران فأكثر بالترتيب على شكل سلسلة
package.title (blogmode) string | null عنوان المقالة
package.meta_description (blogmode) string | null الوصف التعريفي (meta description)
package.body_html (blogmode) string | null HTML لنص المقالة. الصور موضوعة في src لوسوم img، وأكواد الإحالة التسويقية والمراجعات الخاصة بتعريف المنتجات مستبدلة مسبقًا. يمكنك نشره على موقعك كما هو
package.images (blogmode) array صور النص (بترتيب ظهورها) {url, expires_at, width, height}
package.cover_image (blogmode) object | null صورة الغلاف {url, expires_at, width, height}
package.audio (blogmode) object | null صوت المقالة {url, expires_at, duration_ms}
package.slides[] (carouselmode) object صور الشرائح (بترتيب الشرائح) {no, image: {url, expires_at, width, height}}
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
404 not_found المحتوى غير موجود (Content not found.)
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/bmA1b2C3d4E5");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "mode": "blogmode",
    "variation_unique": "bmA1b2C3d4E5",
    "variation_no": 1,
    "title": "How to start a blog",
    "concept": { "concept_unique": "bC2x8RtY4u", "concept_name": "Blogging for beginners" },
    "title_unique": "bT9kL3mN5pQr",
    "language": "en",
    "status": "complete",
    "progress": { "step_process": 3, "is_complete": true },
    "is_readonly": false,
    "confirmed_at": "2026-10-03T08:00:00Z",
    "published_platforms": ["wordpress"],
    "created_at": "2026-10-01T03:00:00Z",
    "updated_at": "2026-10-03T08:00:00Z",
    "publish": [
      {
        "platform": "wordpress",
        "status": "success",
        "post_url": "https://blog.example.com/how-to-start-a-blog/",
        "posted_at": "2026-10-03T09:00:00Z"
      }
    ],
    "content": { "body_html": "<h2>Why start a blog</h2><p>...</p>" },
    "package": {
      "title": "How to Start a Blog in 2026",
      "meta_description": "A step-by-step guide to starting your first blog.",
      "body_html": "<h2>Why start a blog</h2><p>...</p><figure><img src=\"https://...\" alt=\"\" /></figure>",
      "images": [
        { "url": "https://...", "expires_at": "2026-10-21T10:00:00Z", "width": 1536, "height": 1024 }
      ],
      "cover_image": { "url": "https://...", "expires_at": "2026-10-21T10:00:00Z", "width": 1200, "height": 630 },
      "audio": null,
      "x": { "posts": ["New post: How to start a blog in 2026"] }
    }
  }
}
GET › /projects/{project_unique}/contents/{variation_unique}/schedule

جدول النشر

يحصل على المنشورات المخططة والمُولّدة والمنشورة لمحتوى المنشورات (postmode) بترتيب الموعد المجدول. ويتضمن كذلك حالة الأتمتة.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
variation_unique المسار string إلزامي — معرّف المحتوى
from الاستعلام string اختياري — بداية النطاق (الموعد المجدول). قبل 7 أيام من الآن عند الإغفال (قبل to بـ 37 يومًا عند تحديد to فقط)
to الاستعلام string اختياري — نهاية النطاق (الموعد المجدول). بعد 30 يومًا من الآن عند الإغفال (بعد from بـ 37 يومًا عند تحديد from فقط). يمكن أن يصل النطاق إلى 92 يومًا
حقول الاستجابة
الحقلالنوعالوصف
automation.enabled boolean هل الأتمتة مفعّلة
automation.is_executing boolean هل إنشاء المنشورات التلقائي قيد التشغيل (true حتى بعد إيقاف الأتمتة ما دامت هناك منشورات قيد الإنشاء)
automation.week_limit integer | null أقصى عدد من الأسابيع تُنشأ لها الخطط تلقائيًا (null تعني بلا حد)
automation.week_count integer عدد الأسابيع التي أُنشئت لها الخطط حتى الآن
automation.next_refill_at string | null موعد إنشاء الخطط التالية (null عند تعطيل الأتمتة)
automation.timezone string | null المنطقة الزمنية المستخدمة لجدول النشر
items[].schedule_unique string معرّف الموعد المجدول
items[].post_unique string | null معرّف المنشور (null إذا لم يُنشأ النص بعد)
items[].scheduled_at string موعد النشر المجدول
items[].scheduled_at_local string الموعد المجدول بالتوقيت المحلي لـ timezone (YYYY-MM-DDTHH:MM:SS)
items[].timezone string المنطقة الزمنية وقت إنشاء الخطة
items[].status string الحالة. pending (بانتظار إنشاء النص) / generating (قيد الإنشاء) / generated (أُنشئ وبانتظار النشر) / awaiting_image (بانتظار الصورة) / posting (قيد النشر) / posted (منشور) / failed (فشل) / discarded (أُلغي)
items[].confirm_state string المراجعة قبل النشر. none (بلا مراجعة) / awaiting (لا يُنشر حتى الموافقة) / notice (يُنشر بعد الإشعار فقط) / confirmed (تمت الموافقة)
items[].created_via string طريقة الإنشاء. auto (الأتمتة) / manual (يدويًا)
items[].post_type string نوع المنشور. assertion (رأي) / knowhow (معرفة عملية) / experience (تجربة) / casual (يومي)
items[].text string | null نص المنشور (null إذا لم يُنشأ بعد)
items[].thread[] object المنشورات التالية في السلسلة (بالترتيب) {text, post_url, posted_at, image}
items[].image object | null الصورة المرفقة {url, expires_at} (null إن لم توجد)
items[].post_url string | null رابط المنشور (null إذا لم يتحدد بعد)
items[].posted_at string | null وقت النشر (null إذا لم يُنشر)
items[].fail_reason string | null سبب الفشل. token_expired (انقطاع ربط X) / api_error (خطأ من X) / not_found (هدف النشر غير موجود) / insufficient_token (Token غير كافية) / no_x_account (لم يُضبط حساب X) / node_ws_timeout (انتهت مهلة إنشاء النص) / unconfirmed (لم تتم الموافقة)
meta.from / meta.to string النطاق المُعاد
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
404 not_found المحتوى ليس منشورات (postmode)، أو المحتوى غير موجود (Schedule not found.)
422 validation_error النطاق أطول من 92 يومًا، أو to قبل from، أو تعذّرت قراءة قيمة على أنها تاريخ ووقت
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/contents/pmV7d2KqLx01/schedule?from=2026-10-20&to=2026-11-20");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "automation": {
      "enabled": true,
      "is_executing": true,
      "week_limit": 4,
      "week_count": 2,
      "next_refill_at": "2026-10-26T15:00:00Z",
      "timezone": "Asia/Tokyo"
    },
    "items": [
      {
        "schedule_unique": "Sc1aB2cD3eF4",
        "post_unique": "Po1aB2cD3eF4",
        "scheduled_at": "2026-10-20T01:00:00Z",
        "scheduled_at_local": "2026-10-20T10:00:00",
        "timezone": "Asia/Tokyo",
        "status": "posted",
        "confirm_state": "none",
        "created_via": "auto",
        "post_type": "assertion",
        "text": "Most teams overthink onboarding...",
        "thread": [
          {
            "text": "First, cut the steps in half.",
            "post_url": "https://x.com/i/status/1848000000000000002",
            "posted_at": "2026-10-20T01:00:05Z",
            "image": null
          }
        ],
        "image": { "url": "https://...", "expires_at": "2026-10-21T10:00:00Z" },
        "post_url": "https://x.com/i/status/1848000000000000001",
        "posted_at": "2026-10-20T01:00:00Z",
        "fail_reason": null
      },
      {
        "schedule_unique": "Sc9zY8xW7vU6",
        "post_unique": null,
        "scheduled_at": "2026-10-25T09:30:00Z",
        "scheduled_at_local": "2026-10-25T18:30:00",
        "timezone": "Asia/Tokyo",
        "status": "pending",
        "confirm_state": "none",
        "created_via": "auto",
        "post_type": "knowhow",
        "text": null,
        "thread": [],
        "image": null,
        "post_url": null,
        "posted_at": null,
        "fail_reason": null
      }
    ]
  },
  "meta": { "from": "2026-10-20T00:00:00Z", "to": "2026-11-20T23:59:59Z" }
}

نتائج النشر والوجهات

احصل على نتائج النشر إلى الشبكات الاجتماعية وWordPress وwebhook، وعلى حالة الوجهات المرتبطة بالمشروع. ويمكنك استخدام ذلك لاكتشاف الحسابات المنقطعة.

GET › /projects/{project_unique}/publications

نتائج النشر

يحصل على نتائج النشر للمشروع عبر جميع الأوضاع والوجهات من الأحدث إلى الأقدم. وبالنسبة إلى المنشورات (postmode) تُدرج المنشورات المنشورة والفاشلة (أول منشور في كل سلسلة).

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
mode الاستعلام string اختياري — التصفية حسب الوضع. يمكنك تمرير أكثر من قيمة من moviemode (فيديو) وblogmode (مدونة) وcarouselmode (كاروسيل) وpostmode (منشور) مفصولة بفواصل. جميع الأوضاع عند الإغفال
platform الاستعلام string اختياري — التصفية حسب الوجهة (مفصولة بفواصل). youtube / tiktok / instagram / x / wordpress / webhook
status الاستعلام string اختياري — التصفية حسب نتيجة النشر (مفصولة بفواصل). success / failed / scheduled / processing / partial_success / reviewing
from الاستعلام string اختياري — يُعيد فقط النتائج التي يكون وقت نشرها (أو وقت تسجيلها إذا لم تُنشر) في هذا التاريخ والوقت أو بعدهما
to الاستعلام string اختياري — يُعيد فقط النتائج التي يكون وقت نشرها (أو وقت تسجيلها إذا لم تُنشر) في هذا التاريخ والوقت أو قبلهما
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].publication_unique string معرّف نتيجة النشر
data[].mode string moviemode (فيديو) / blogmode (مدونة) / carouselmode (كاروسيل) / postmode (منشور)
data[].content.variation_unique string معرّف المحتوى
data[].content.title string | null العنوان (اسم المفهوم لـ postmode)
data[].platform string وجهة النشر. youtube / tiktok / instagram / x / wordpress / webhook
data[].account object | null الحساب المستخدم للنشر {account_unique, name}. تكون name هي null للحسابات التي أُلغي ربطها. null لـ postmode
data[].status string نتيجة النشر. success (منشور) / failed (فشل) / scheduled (مجدول لدى الوجهة) / processing (قيد المعالجة) / partial_success (نجح النشر وفشلت خطوة مرافقة مثل تعيين الصورة المصغرة) / reviewing (نجح النشر وينتظر مراجعة الوجهة فلم يتحدد الرابط بعد)
data[].post_url string | null رابط المنشور (null إذا لم يتحدد بعد)
data[].error_code string | null رمز سبب الفشل (يختلف حسب الوجهة والوضع)
data[].is_automation boolean هل نُشر بواسطة الأتمتة
data[].posted_at string | null وقت النشر (null إذا لم يُنشر)
data[].created_at string تاريخ الإنشاء
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/publications?platform=x,youtube&status=failed");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "publication_unique": "Xk3p9QmZ2aLw",
      "mode": "postmode",
      "content": { "variation_unique": "pmV7d2KqLx01", "title": "SaaS growth tips" },
      "platform": "x",
      "account": null,
      "status": "success",
      "post_url": "https://x.com/i/status/1848123456789012345",
      "error_code": null,
      "is_automation": true,
      "posted_at": "2026-10-04T10:00:00Z",
      "created_at": "2026-10-03T22:10:00Z"
    },
    {
      "publication_unique": "Pq2wE4rT6yUi",
      "mode": "blogmode",
      "content": { "variation_unique": "bmA1b2C3d4E5", "title": "How to start a blog" },
      "platform": "wordpress",
      "account": { "account_unique": "Wp3xY5zA7bCd", "name": "My WP Site" },
      "status": "failed",
      "post_url": null,
      "error_code": "auth_failed",
      "is_automation": false,
      "posted_at": null,
      "created_at": "2026-10-02T10:00:00Z"
    }
  ],
  "meta": { "total": 2, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /projects/{project_unique}/accounts

الوجهات المرتبطة

يحصل على الوجهات المرتبطة بالمشروع (حسابات الشبكات الاجتماعية وWordPress وwebhook) وحالتها. وعندما تصبح status هي expired أو connection_error يلزم إعادة الربط.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
حقول الاستجابة
الحقلالنوعالوصف
data[].account_unique string معرّف الوجهة
data[].platform string وجهة النشر. youtube / tiktok / instagram / x / wordpress / webhook
data[].name string اسم العرض. اسم الحساب للشبكات الاجتماعية، واسم الموقع لـ WordPress، ونطاق رابط الوجهة لـ webhook (بالشكل https://example.com/… دون المسار)
data[].image_url string | null رابط صورة أيقونة الحساب (للشبكات الاجتماعية فقط)
data[].status string الحالة. active (متاح) / expired (انتهت صلاحية الربط ويلزم إعادة الربط) / connection_error (تعذّر الاتصال بـ WordPress)
data[].token_expires_at string | null موعد انتهاء صلاحية الربط (للشبكات الاجتماعية فقط)
data[].connected_at string | null وقت الربط
data[].last_used_at string | null آخر وقت استُخدم فيه للنشر (للشبكات الاجتماعية فقط)
data[].site_url string | null رابط موقع WordPress (لـ WordPress فقط)
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
مثال على الطلب
curl "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/a1b2c3d4e5/accounts");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "account_unique": "Wh9kQ2mN4pRt",
      "platform": "webhook",
      "name": "https://hooks.example.com/…",
      "image_url": null,
      "status": "active",
      "token_expires_at": null,
      "connected_at": "2026-07-01T00:00:00Z",
      "last_used_at": null,
      "site_url": null
    },
    {
      "account_unique": "Wp3xY5zA7bCd",
      "platform": "wordpress",
      "name": "Example Blog",
      "image_url": null,
      "status": "connection_error",
      "token_expires_at": null,
      "connected_at": "2026-08-01T00:00:00Z",
      "last_used_at": null,
      "site_url": "https://blog.example.com"
    },
    {
      "account_unique": "Yt4aB6cD8eFg",
      "platform": "youtube",
      "name": "Channel B",
      "image_url": "https://yt3.ggpht.com/abc.png",
      "status": "expired",
      "token_expires_at": "2026-10-01T00:00:00Z",
      "connected_at": "2026-09-01T00:00:00Z",
      "last_used_at": "2026-09-30T00:00:00Z",
      "site_url": null
    }
  ]
}

الأتمتة

احصل على تقدّم أتمتة الفيديو والمدونة والكاروسيل. أما أتمتة المنشورات (وضع المنشور) فاستخدم جدول المحتوى للحصول عليها.

GET › /automations

عمليات الأتمتة

يحصل على عمليات أتمتة الفيديو والمدونة والكاروسيل (المجدولة وقيد التشغيل وبانتظار المراجعة والمنتهية) من الأحدث إلى الأقدم.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
status الاستعلام string اختياري — التصفية حسب الحالة (مفصولة بفواصل). القيم نفسها في data[].status
mode الاستعلام string اختياري — التصفية حسب الوضع (مفصولة بفواصل). moviemode / blogmode / carouselmode
project_unique الاستعلام string اختياري — يُعيد عمليات هذا المشروع فقط
from الاستعلام string اختياري — يُعيد فقط العناصر التي أُنشئت في هذا التاريخ والوقت أو بعدهما
to الاستعلام string اختياري — يُعيد فقط العناصر التي أُنشئت في هذا التاريخ والوقت أو قبلهما
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].auto_unique string معرّف عملية الأتمتة
data[].mode string moviemode / blogmode / carouselmode
data[].project object المشروع {project_unique, project_name}
data[].content.variation_unique string معرّف المحتوى
data[].content.title string | null العنوان (اسم المفهوم لـ postmode)
data[].run_no integer رقم هذه العملية بالنسبة إلى المحتوى
data[].status string الحالة. pending (بانتظار التشغيل؛ مجدولة عندما يكون reserved_at في المستقبل) / executing (قيد التشغيل) / waiting_confirmation (بانتظار مراجعة المحتوى؛ تستمر بعد المراجعة) / completed (اكتملت) / failed (فشلت) / stopped (أُوقفت) / token_shortage (انتهت لنفاد Token)
data[].execution_mode string sequential (واحدة تلو الأخرى) / parallel (في آنٍ واحد)
data[].phases object حالة كل مرحلة {setup, step1, step2, step3}. not_started (لم تبدأ) / running (قيد التشغيل، أو المرحلة التي توقفت عندها) / done (اكتملت، بما في ذلك المتخطاة، وفي run انتهى بالحالة completed، الخطوات التي كانت خارج نطاق هذا الـ run) / error (فشلت)
data[].template.setup_template_name string | null اسم قالب الإعداد المستخدم عند البدء
data[].template.automation_template_name string | null اسم قالب الأتمتة المستخدم عند البدء
data[].reserved_at string | null موعد التشغيل المجدول
data[].executed_at string | null وقت بدء التشغيل
data[].completed_at string | null وقت انتهاء العملية (عند completed / failed / stopped / token_shortage)
data[].created_at string وقت تسجيل العملية
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/automations?status=executing,waiting_confirmation");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "auto_unique": "aB3dE5fG7h",
      "mode": "blogmode",
      "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My Blog" },
      "content": { "variation_unique": "Xy12Zw34Ab56", "title": "Spring travel tips" },
      "run_no": 2,
      "status": "executing",
      "execution_mode": "sequential",
      "phases": { "setup": "done", "step1": "done", "step2": "running", "step3": "not_started" },
      "template": { "setup_template_name": "Default setup", "automation_template_name": null },
      "reserved_at": null,
      "executed_at": "2026-10-19T23:09:27Z",
      "completed_at": null,
      "created_at": "2026-10-19T23:09:20Z"
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /automations/{auto_unique}

تفاصيل عملية الأتمتة

يحصل على تفاصيل عملية أتمتة واحدة وتقدّم كل خطوة فيها. ويمكنك استخدامه لمتابعة التقدّم أثناء التشغيل.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
auto_unique المسار string إلزامي — معرّف عملية الأتمتة
حقول الاستجابة
الحقلالنوعالوصف
auto_unique / mode / … / created_at — مثل قائمة عمليات الأتمتة
steps[].key string اسم الخطوة (مثل step1_1_text)
steps[].phase string مرحلة الخطوة. setup / step1 / step2 / step3
steps[].status string حالة الخطوة. not_run (لم تُنفّذ أو غير منطبقة أو قيد التنفيذ) / success (نجحت) / error (فشلت) / skipped (تُخطيت)
steps[].started_at string | null وقت بدء الخطوة الجارية (تصبح null عند انتهائها)
steps[].finished_at string | null وقت انتهاء الخطوة
steps[].duration_sec number | null عدد الثواني المستغرقة (عند success / error)
steps[].error_code string | null سبب الفشل. internal_error / automation_record_not_found / automation_stopped_by_admin / insufficient_token (Token غير كافية) / token_group_blocked (بلوغ حد حصة الفريق) / automation_auth_error (خطأ مصادقة لدى الوجهة) / automation_not_found / automation_conflict / automation_rate_limited (حد المعدل لدى الوجهة) / automation_server_error (خطأ لدى الوجهة) / automation_network_error (خطأ في الشبكة) / automation_step_failed. null عند عدم تسجيل سبب
accounts[] object الوجهات عند البدء {platform, account_unique, name}. تكون name هي null لـ webhook
stop_requested boolean هل طُلب الإيقاف
confirmation.requested_at string | null وقت بدء انتظار المراجعة
confirmation.confirmed_at string | null وقت مراجعة المحتوى (null أثناء انتظار المراجعة أو عند عدم المراجعة)
الأخطاء
الحالةالرمزمتى يحدث
404 not_found الأتمتة غير موجودة أو خارج نطاق ما يمكنك الوصول إليه (Automation not found.)
مثال على الطلب
curl "https://stepeee.com/public-api/v1/automations/aB3dE5fG7h" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/automations/aB3dE5fG7h",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations/aB3dE5fG7h", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations/aB3dE5fG7h")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations/aB3dE5fG7h"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/automations/aB3dE5fG7h");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "auto_unique": "aB3dE5fG7h",
    "mode": "blogmode",
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My Blog" },
    "content": { "variation_unique": "Xy12Zw34Ab56", "title": "Spring travel tips" },
    "run_no": 2,
    "status": "failed",
    "execution_mode": "sequential",
    "phases": { "setup": "done", "step1": "done", "step2": "done", "step3": "error" },
    "template": { "setup_template_name": "Default setup", "automation_template_name": "Skip voice" },
    "reserved_at": null,
    "executed_at": "2026-10-19T23:09:27Z",
    "completed_at": "2026-10-19T23:17:50Z",
    "created_at": "2026-10-19T23:09:20Z",
    "steps": [
      { "key": "setup", "phase": "setup", "status": "success", "started_at": null, "finished_at": "2026-10-19T23:09:29Z", "duration_sec": 2.3, "error_code": null },
      { "key": "step1_1_text", "phase": "step1", "status": "success", "started_at": null, "finished_at": "2026-10-19T23:11:40Z", "duration_sec": 126.3, "error_code": null },
      { "key": "step2_2", "phase": "step2", "status": "skipped", "started_at": null, "finished_at": "2026-10-19T23:17:39Z", "duration_sec": null, "error_code": null },
      { "key": "step3_4_webhook", "phase": "step3", "status": "error", "started_at": null, "finished_at": "2026-10-19T23:17:46Z", "duration_sec": 1.2, "error_code": "automation_server_error" }
    ],
    "accounts": [
      { "platform": "webhook", "account_unique": "dxuD2gk3NYuA", "name": null }
    ],
    "stop_requested": false,
    "confirmation": { "requested_at": null, "confirmed_at": null }
  }
}

المواد والقوالب

احصل على موادي (الصور والفيديو وBGM) وعلى قوالب الإعداد والأتمتة.

GET › /materials

قائمة المواد

يحصل على موادي (الصور والفيديو وBGM) من الأحدث إلى الأقدم. وفي الفريق يُعيد المواد المشتركة للفريق. لا تُدرج الصور المستخدمة داخل مشروع فقط ولا الملفات التي لا تزال قيد الإنشاء.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
kind الاستعلام string اختياري — التصفية حسب نوع المادة. image (صورة) / video (فيديو) / bgm
type الاستعلام string اختياري — التصفية حسب استخدام المادة. القيم نفسها في data[].type. وعند استخدامه مع kind لا يمكن تحديد إلا استخدامات ذلك النوع
category_unique الاستعلام string اختياري — يُعيد مواد هذه الفئة فقط
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].material_unique string معرّف المادة
data[].kind string النوع. image (صورة) / video (فيديو) / bgm
data[].type string الاستخدام. image_element (عنصر) / image_vertical (عمودية) / image_horizontal (أفقية) / reference_person (صورة مرجعية: شخص) / reference_background (صورة مرجعية: خلفية) / reference_layout (صورة مرجعية: تخطيط) / reference_cta (صورة مرجعية: CTA) / reference_pet (صورة مرجعية: حيوان أليف) / reference_product (صورة مرجعية: منتج أو خدمة) / image_rulebook (دليل القواعد) / image_promotion (ترويج) / video_vertical (فيديو عمودي) / video_horizontal (فيديو أفقي) / bgm
data[].category object | null الفئة {category_unique, name} (null إذا لم تُصنّف)
data[].width / data[].height integer | null العرض والارتفاع (بالبكسل). null لـ BGM وعند عدم القياس
data[].duration_ms integer | null المدة (بالملّي ثانية). null للصور
data[].size_bytes integer حجم الملف (بالبايت). قد يكون 0 عندما تشير المادة إلى مادة مشتركة
data[].file object الملف نفسه {url, expires_at}
data[].thumbnail object | null الصورة المصغرة {url, expires_at}. null لـ BGM والعناصر وأثناء إنشاء الصورة المصغرة
data[].created_at string تاريخ الإنشاء
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/materials?kind=image&type=image_vertical");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "material_unique": "aB3dE5fG7hJ9kL1mN3pQ",
      "kind": "image",
      "type": "image_vertical",
      "category": { "category_unique": "Xy12Ab34Cd", "name": "Product shots" },
      "width": 768,
      "height": 1344,
      "duration_ms": null,
      "size_bytes": 1234567,
      "file": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
      "thumbnail": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
      "created_at": "2026-10-01T10:00:00Z"
    },
    {
      "material_unique": "Zq9Wv8Ut7Sr6Qp5On4Ml",
      "kind": "bgm",
      "type": "bgm",
      "category": null,
      "width": null,
      "height": null,
      "duration_ms": 30000,
      "size_bytes": 482133,
      "file": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
      "thumbnail": null,
      "created_at": "2026-09-30T08:12:00Z"
    }
  ],
  "meta": { "total": 2, "current_page": 1, "per_page": 20, "last_page": 1 }
}
GET › /materials/{material_unique}

تفاصيل المادة

يحصل على مادة واحدة.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
material_unique المسار string إلزامي — معرّف المادة
حقول الاستجابة
الحقلالنوعالوصف
material_unique string معرّف المادة
kind string النوع. image (صورة) / video (فيديو) / bgm
type string الاستخدام. image_element (عنصر) / image_vertical (عمودية) / image_horizontal (أفقية) / reference_person (صورة مرجعية: شخص) / reference_background (صورة مرجعية: خلفية) / reference_layout (صورة مرجعية: تخطيط) / reference_cta (صورة مرجعية: CTA) / reference_pet (صورة مرجعية: حيوان أليف) / reference_product (صورة مرجعية: منتج أو خدمة) / image_rulebook (دليل القواعد) / image_promotion (ترويج) / video_vertical (فيديو عمودي) / video_horizontal (فيديو أفقي) / bgm
category object | null الفئة {category_unique, name} (null إذا لم تُصنّف)
width / height integer | null العرض والارتفاع (بالبكسل). null لـ BGM وعند عدم القياس
duration_ms integer | null المدة (بالملّي ثانية). null للصور
size_bytes integer حجم الملف (بالبايت). قد يكون 0 عندما تشير المادة إلى مادة مشتركة
file object الملف نفسه {url, expires_at}
thumbnail object | null الصورة المصغرة {url, expires_at}. null لـ BGM والعناصر وأثناء إنشاء الصورة المصغرة
created_at string تاريخ الإنشاء
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المادة غير موجودة أو خارج نطاق ما يمكنك الوصول إليه (Material not found.)
مثال على الطلب
curl "https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/materials/aB3dE5fG7hJ9kL1mN3pQ");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "material_unique": "aB3dE5fG7hJ9kL1mN3pQ",
    "kind": "image",
    "type": "image_vertical",
    "category": { "category_unique": "Xy12Ab34Cd", "name": "Product shots" },
    "width": 768,
    "height": 1344,
    "duration_ms": null,
    "size_bytes": 1234567,
    "file": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
    "thumbnail": { "url": "https://...", "expires_at": "2026-10-21T11:00:00Z" },
    "created_at": "2026-10-01T10:00:00Z"
  }
}
GET › /material-categories

فئات المواد

يحصل على فئات المواد وعدد المواد في كل فئة.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
kind الاستعلام string اختياري — التصفية حسب نوع المادة. image (صورة) / video (فيديو) / bgm
type الاستعلام string اختياري — التصفية حسب استخدام المادة. القيم نفسها في data[].type. وعند استخدامه مع kind لا يمكن تحديد إلا استخدامات ذلك النوع
حقول الاستجابة
الحقلالنوعالوصف
data[].category_unique string معرّف الفئة
data[].name string اسم الفئة
data[].kind string النوع. image (صورة) / video (فيديو) / bgm
data[].type string الاستخدام. image_element (عنصر) / image_vertical (عمودية) / image_horizontal (أفقية) / reference_person (صورة مرجعية: شخص) / reference_background (صورة مرجعية: خلفية) / reference_layout (صورة مرجعية: تخطيط) / reference_cta (صورة مرجعية: CTA) / reference_pet (صورة مرجعية: حيوان أليف) / reference_product (صورة مرجعية: منتج أو خدمة) / image_rulebook (دليل القواعد) / image_promotion (ترويج) / video_vertical (فيديو عمودي) / video_horizontal (فيديو أفقي) / bgm
data[].is_system boolean هل أنشأ Stepeee الفئة تلقائيًا
data[].material_count integer عدد المواد في الفئة
الأخطاء
الحالةالرمزمتى يحدث
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/material-categories?kind=image" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/material-categories?kind=image",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/material-categories?kind=image", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/material-categories?kind=image")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/material-categories?kind=image"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/material-categories?kind=image");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "category_unique": "Bg12Ab34Cd",
      "name": "Lo-fi",
      "kind": "bgm",
      "type": "bgm",
      "is_system": false,
      "material_count": 3
    },
    {
      "category_unique": "Xy12Ab34Cd",
      "name": "Product shots",
      "kind": "image",
      "type": "image_vertical",
      "is_system": false,
      "material_count": 12
    }
  ]
}
GET › /templates

قائمة القوالب

يحصل على قوالب الإعداد وقوالب الأتمتة من الأحدث تحديثًا إلى الأقدم. وفي الفريق يُعيد القوالب المشتركة للفريق.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
mode الاستعلام string اختياري — التصفية حسب الوضع. moviemode / blogmode / carouselmode / postmode
kind الاستعلام string اختياري — التصفية حسب نوع القالب. setup / automation
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].template_unique string معرّف القالب
data[].kind string النوع. setup (قالب إعداد يجمع إعدادات الإنتاج) / automation (قالب أتمتة يحدد الخطوات التي تنفذها الأتمتة)
data[].mode string moviemode (فيديو) / blogmode (مدونة) / carouselmode (كاروسيل) / postmode (منشور)
data[].name string اسم القالب
data[].created_at string تاريخ الإنشاء
data[].updated_at string تاريخ التحديث
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/templates?kind=setup&mode=moviemode");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "template_unique": "Ab12Cd34Ef",
      "kind": "automation",
      "mode": "carouselmode",
      "name": "Morning carousel",
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-10-05T00:00:00Z"
    },
    {
      "template_unique": "Gh56Ij78Kl",
      "kind": "setup",
      "mode": "moviemode",
      "name": "60-second explainer",
      "created_at": "2026-01-01T00:00:00Z",
      "updated_at": "2026-10-01T00:00:00Z"
    }
  ],
  "meta": { "total": 2, "current_page": 1, "per_page": 20, "last_page": 1 }
}

العناوين والمحتوى

أضف عناوين إلى مفاهيم الفيديو والمدونة والكاروسيل، واحذف المحتوى. متاح في خطة Pro أو أعلى.

POST › /projects/{project_unique}/concepts/{concept_unique}/titles

إضافة عناوين

يضيف عناوين دفعة واحدة إلى مفهوم فيديو أو مدونة أو كاروسيل، وينشئ أول محتوى لكل عنوان (المعالجة نفسها التي تجري عند إضافة العناوين يدويًا في التطبيق). لا تُنشأ العناوين التي يوجد اسمها مسبقًا في المفهوم نفسه، ولا الأسماء التي تتكرر للمرة الثانية أو أكثر في الطلب نفسه، بل تُدرج في skipped. يمكن أن يحتوي المفهوم على 100 عنوان كحد أقصى، وإذا كانت الإضافة ستتجاوز 100 فلا يُنشأ أي شيء (ولا تُحسب الأسماء التي تُتخطى). وإذا حال حد المحتوى في الخطة دون إنشاء المحتوى فيُنشأ العنوان وحده ويكون variation_unique بقيمة null. ولا يمكن ضبط إعدادات الترويج والتسويق بالعمولة للمدونة، إذ تُنشأ العناوين بوصفها مقالات قياسية. وفي الفريق يكون مالك الفريق هو مالك العناوين والمحتوى الذي تنشئه.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
concept_unique المسار string إلزامي — معرّف المفهوم (مفهوم فيديو أو مدونة أو كاروسيل ضمن المشروع)
titles الجسم string[] إلزامي — العناوين المراد إضافتها. من 1 إلى 50 عنصرًا. يجب أن يكون كل عنوان من 1 إلى 500 حرف بعد إزالة المسافات في البداية والنهاية (لا يُسمح بالعناوين المكوّنة من مسافات فقط أو من «0» فقط أو التي تحتوي على سطر جديد في وسطها)
language الجسم string إلزامي — لغة النشر للمحتوى المُنشأ (رمز لغة مثل ja أو en أو fr)
setup_template_unique الجسم string | null اختياري — معرّف قالب الإعداد المراد تطبيقه (template_unique من GET /templates، بنوع kind يساوي setup ووضع المفهوم نفسه). إذا حُذف فيُستخدم القالب الافتراضي للمفهوم (أو الإعداد القياسي إذا لم يُضبط قالب)
Idempotency-Key الترويسة string اختياري — سلسلة فريدة تُنشئها لكل عملية (من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة). إعادة إرسال المحتوى نفسه بالمفتاح نفسه تُعيد الاستجابة الأولى كما هي (راجع Idempotency-Key في المواصفات المشتركة)
حقول الاستجابة
الحقلالنوعالوصف
created[] object العناوين التي أُنشئت (بترتيب الإرسال)
created[].title_unique string معرّف العنوان
created[].title_name string اسم العنوان (بعد إزالة المسافات في البداية والنهاية)
created[].variation_unique string | null معرّف أول محتوى أُنشئ. null إذا تعذّر إنشاؤه بسبب حد المحتوى في الخطة
skipped[] object العناوين التي لم تُنشأ (بترتيب الإرسال)
skipped[].title_name string اسم العنوان (بعد إزالة المسافات في البداية والنهاية)
skipped[].reason string سبب عدم الإنشاء. duplicate (يوجد عنوان بالاسم نفسه في المفهوم نفسه، أو تكرر الاسم للمرة الثانية أو أكثر في الطلب نفسه)
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
403 readonly المشروع للقراءة فقط بسبب تخفيض الخطة
404 not_found المشروع غير موجود أو خارج نطاق وصولك، أو المفهوم ليس ضمن ذلك المشروع
409 title_limit_reached ستؤدي الإضافة إلى تجاوز المفهوم 100 عنوان (لا يُنشأ أي شيء). يحتوي details على limit (الحد) وtotal_after_add (العدد بعد الإضافة)
409 idempotency_request_in_progress طلب بالـ Idempotency-Key نفسه لا يزال قيد المعالجة
422 validation_error المعاملات غير صحيحة
422 mode_not_supported مفهوم منشورات (وضع المنشور) أو مفهوم صور
422 template_not_found القالب المحدد في setup_template_unique غير موجود (بما في ذلك القوالب من وضع آخر)
422 idempotency_key_invalid قيمة Idempotency-Key ليست من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة
422 idempotency_key_reused استُخدم الـ Idempotency-Key نفسه لطلب بمحتوى مختلف
مثال على الطلب
curl -X POST "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90" \
  -d '{
  "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
  "language": "en",
  "setup_template_unique": "Gh56Ij78Kl"
}'
import requests

body = """{
  "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
  "language": "en",
  "setup_template_unique": "Gh56Ij78Kl"
}"""

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
  body: JSON.stringify({
    "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
    "language": "en",
    "setup_template_unique": "Gh56Ij78Kl"
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")
request.httpBody = """
{
  "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
  "language": "en",
  "setup_template_unique": "Gh56Ij78Kl"
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
          "language": "en",
          "setup_template_unique": "Gh56Ij78Kl"
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "titles": ["Easy breakfast for beginners", "Meal prep in 5 minutes", "Easy breakfast for beginners"],
  "language": "en",
  "setup_template_unique": "Gh56Ij78Kl"
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/concepts/Cx2Yz4Wv6Ut8/titles");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "created": [
      { "title_unique": "q8Wm2LzR0pXa", "title_name": "Easy breakfast for beginners", "variation_unique": "Hn4kT7sY1cVb" },
      { "title_unique": "Zr5uP9eK3wQd", "title_name": "Meal prep in 5 minutes", "variation_unique": "Jm8oB2fN6xLe" }
    ],
    "skipped": [
      { "title_name": "Easy breakfast for beginners", "reason": "duplicate" }
    ]
  }
}
DELETE › /projects/{project_unique}/contents/{variation_unique}

حذف المحتوى

يحذف محتوى فيديو أو مدونة أو كاروسيل (المعالجة نفسها التي تجري عند حذف المحتوى في التطبيق). يختفي المحتوى المحذوف من القوائم والتفاصيل فورًا، وبعد delete_at (بعد 3 أيام) يُحذف نهائيًا مع الصور والصوت والفيديو المُنشأة. وتُنقص أرقام المحتوى التالي ضمن العنوان نفسه بمقدار واحد. ولا يمكن حذف محتوى تعمل أتمتته أو مجدولة، لذا أوقف الأتمتة أولًا. ولا يمكن حذف آخر محتوى متبقٍ في العنوان ولا محتوى المنشورات (وضع المنشور).

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
project_unique المسار string إلزامي — معرّف المشروع
variation_unique المسار string إلزامي — معرّف المحتوى
حقول الاستجابة
الحقلالنوعالوصف
variation_unique string معرّف المحتوى المحذوف
mode string moviemode (فيديو) / blogmode (مدونة) / carouselmode (كاروسيل)
delete_at string تاريخ ووقت الحذف النهائي
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
403 readonly المحتوى أو المشروع للقراءة فقط بسبب تخفيض الخطة
404 not_found المشروع غير موجود أو خارج نطاق وصولك، أو المحتوى ليس ضمن ذلك المشروع، أو حُذف مسبقًا
409 automation_running توجد أتمتة قيد التشغيل أو مجدولة (لم تنتهِ أتمتة بعد)
409 last_variation آخر محتوى متبقٍ في العنوان
422 mode_not_supported محتوى منشورات (وضع المنشور)
مثال على الطلب
curl -X DELETE "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "DELETE",
    "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb")!)
request.httpMethod = "DELETE"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("DELETE", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/projects/Pq7Rs9Tu1V/contents/Hn4kT7sY1cVb");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "variation_unique": "Hn4kT7sY1cVb",
    "mode": "blogmode",
    "delete_at": "2026-10-24T12:00:00Z"
  }
}

عمليات الأتمتة

ابدأ أتمتة الفيديو والمدونة والكاروسيل وغيّر جدولتها وأوقفها، ووافق على الأتمتة التي تنتظر المراجعة. يمكنك التعامل مع الأتمتة نفسها التي تحصل عليها عبر GET /automations. الإيقاف متاح في أي خطة، أما بقية العمليات فتتطلب خطة Pro أو أعلى.

POST › /automations

بدء الأتمتة

يبدأ أتمتة المحتوى (فيديو أو مدونة أو كاروسيل) وفق إعدادات قالب أتمتة. إذا حددت reserved_at فتُجدول، وإذا حُذف فتعمل الآن. يجب أن يكون كل المحتوى المستهدف ضمن المشروع نفسه والوضع نفسه. وإذا تعذّر بدء محتوى واحد على الأقل فلا يُسجَّل أي شيء، وتبيّن الاستجابة أي محتوى تعذّر بدؤه ولماذا. تُتخطى الخطوات المُنشأة مسبقًا ويبدأ التشغيل من أول خطوة لم تُنشأ بعد، ولا تُنفَّذ الخطوات المضبوطة على التخطي في قالب الأتمتة. وبالنسبة إلى المحتوى الذي لم يكتمل إعداده فيُثبَّت الإعداد عند البدء. يستهلك تشغيل الأتمتة Token. ولا يُتحقق من الرصيد عند البدء، وإذا نفد أثناء التشغيل فتنتهي الأتمتة بـ token_shortage. ومع الإعدادات التي تتطلب مراجعة المحتوى تتوقف الأتمتة في منتصفها عند waiting_confirmation، فوافق عليها باستخدام POST /automations/{auto_unique}/confirm. أما النشر التلقائي للمنشورات (وضع المنشور) فهو آلية منفصلة تُفعَّل وتُعطَّل لكل محتوى في التطبيق، ولا يمكن بدؤه عبر نقطة النهاية هذه.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
variation_uniques الجسم string[] إلزامي — قيم variation_unique للمحتوى المراد أتمتته. من 1 إلى 50 عنصرًا، دون تكرار
automation_template_unique الجسم string إلزامي — معرّف قالب الأتمتة (template_unique من GET /templates?kind=automation، بوضع المحتوى نفسه)
reserved_at الجسم string اختياري — موعد التشغيل (تاريخ ووقت في المستقبل). حدده بصيغة ISO 8601 مع فرق التوقيت، وتُعامل القيم التي لا تتضمن فرق التوقيت على أنها UTC. إذا حُذف فتعمل الآن
Idempotency-Key الترويسة string إلزامي — سلسلة فريدة تُنشئها لكل عملية (من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة). إلزامية لمنع البدء مرتين. إعادة إرسال المحتوى نفسه بالمفتاح نفسه تُعيد الاستجابة الأولى كما هي (راجع Idempotency-Key في المواصفات المشتركة)
حقول الاستجابة
الحقلالنوعالوصف
data[].auto_unique string معرّف عملية الأتمتة
data[].mode string moviemode / blogmode / carouselmode
data[].project object المشروع {project_unique, project_name}
data[].content.variation_unique string معرّف المحتوى
data[].content.title string | null العنوان (اسم المفهوم لـ postmode)
data[].run_no integer رقم هذه العملية بالنسبة إلى المحتوى
data[].status string الحالة. pending (بانتظار التشغيل؛ مجدولة عندما يكون reserved_at في المستقبل) / executing (قيد التشغيل) / waiting_confirmation (بانتظار مراجعة المحتوى؛ تستمر بعد المراجعة) / completed (اكتملت) / failed (فشلت) / stopped (أُوقفت) / token_shortage (انتهت لنفاد Token)
data[].execution_mode string sequential (واحدة تلو الأخرى) / parallel (في آنٍ واحد)
data[].phases object حالة كل مرحلة {setup, step1, step2, step3}. not_started (لم تبدأ) / running (قيد التشغيل، أو المرحلة التي توقفت عندها) / done (اكتملت، بما في ذلك المتخطاة، وفي run انتهى بالحالة completed، الخطوات التي كانت خارج نطاق هذا الـ run) / error (فشلت)
data[].template.setup_template_name string | null اسم قالب الإعداد المستخدم عند البدء
data[].template.automation_template_name string | null اسم قالب الأتمتة المستخدم عند البدء
data[].reserved_at string | null موعد التشغيل المجدول
data[].executed_at string | null وقت بدء التشغيل
data[].completed_at string | null وقت انتهاء العملية (عند completed / failed / stopped / token_shortage)
data[].created_at string وقت تسجيل العملية
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
404 content_not_found يوجد variation_unique ليس ضمن المحتوى الذي يمكنك الوصول إليه (بما في ذلك المحتوى الذي جُدول حذفه بعد قبول الطلب، ولا يُسجَّل أي شيء). يحتوي details.variation_uniques على القيم المطابقة
404 automation_template_not_found قالب الأتمتة غير موجود
409 contents_not_automatable يوجد محتوى لا يمكن بدؤه (لا يُسجَّل أي شيء). يحتوي details.contents على مصفوفة من {variation_unique, reason}. وقيمة reason هي automation_active (لم تنتهِ أتمتة بعد) / content_complete (مكتمل مسبقًا) / content_readonly (للقراءة فقط بسبب تخفيض الخطة) / layout_template_required (محتوى كاروسيل في مشروع لا يحتوي على أي قالب تخطيط)
409 idempotency_request_in_progress طلب بالـ Idempotency-Key نفسه لا يزال قيد المعالجة
422 validation_error المعاملات غير صحيحة (0 عنصر أو 51 عنصرًا فأكثر، أو تكرار، أو reserved_at في الماضي، وما إلى ذلك)
422 mode_not_supported يتضمن محتوى منشورات (وضع المنشور). يحتوي details.variation_uniques على القيم المطابقة
422 mixed_modes يختلط محتوى من أوضاع مختلفة
422 mixed_projects يختلط محتوى من مشاريع مختلفة
422 automation_template_mode_mismatch وضع قالب الأتمتة يختلف عن وضع المحتوى
422 idempotency_key_required الترويسة Idempotency-Key مفقودة
422 idempotency_key_invalid قيمة Idempotency-Key ليست من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة
422 idempotency_key_reused استُخدم الـ Idempotency-Key نفسه لطلب بمحتوى مختلف
503 automation_dispatch_failed فشل بدء التشغيل الفوري. تصبح الأتمتة المسجلة failed. وإعادة الإرسال بالـ Idempotency-Key نفسه تسجلها من جديد وتبدؤها
مثال على الطلب
curl -X POST "https://stepeee.com/public-api/v1/automations" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90" \
  -d '{
  "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
  "automation_template_unique": "Tm7pL2xQ9z",
  "reserved_at": "2030-01-02T12:04:05+09:00"
}'
import requests

body = """{
  "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
  "automation_template_unique": "Tm7pL2xQ9z",
  "reserved_at": "2030-01-02T12:04:05+09:00"
}"""

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/automations",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
  body: JSON.stringify({
    "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
    "automation_template_unique": "Tm7pL2xQ9z",
    "reserved_at": "2030-01-02T12:04:05+09:00"
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")
request.httpBody = """
{
  "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
  "automation_template_unique": "Tm7pL2xQ9z",
  "reserved_at": "2030-01-02T12:04:05+09:00"
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
          "automation_template_unique": "Tm7pL2xQ9z",
          "reserved_at": "2030-01-02T12:04:05+09:00"
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "variation_uniques": ["Ab3dEf6hIj9k", "Lm2nOp5qRs8t"],
  "automation_template_unique": "Tm7pL2xQ9z",
  "reserved_at": "2030-01-02T12:04:05+09:00"
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/automations");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "auto_unique": "Qw3eRt6yUi",
      "mode": "blogmode",
      "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
      "content": { "variation_unique": "Ab3dEf6hIj9k", "title": "My blog title" },
      "run_no": 1,
      "status": "pending",
      "execution_mode": "sequential",
      "phases": { "setup": "running", "step1": "not_started", "step2": "not_started", "step3": "not_started" },
      "template": { "setup_template_name": null, "automation_template_name": "Morning blog" },
      "reserved_at": "2030-01-02T03:04:05Z",
      "executed_at": null,
      "completed_at": null,
      "created_at": "2026-10-21T10:00:00Z"
    },
    {
      "auto_unique": "As4dFg7hJk",
      "mode": "blogmode",
      "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
      "content": { "variation_unique": "Lm2nOp5qRs8t", "title": "My blog title" },
      "run_no": 1,
      "status": "pending",
      "execution_mode": "sequential",
      "phases": { "setup": "running", "step1": "not_started", "step2": "not_started", "step3": "not_started" },
      "template": { "setup_template_name": null, "automation_template_name": "Morning blog" },
      "reserved_at": "2030-01-02T03:04:05Z",
      "executed_at": null,
      "completed_at": null,
      "created_at": "2026-10-21T10:00:00Z"
    }
  ]
}
PATCH › /automations/{auto_unique}

تغيير موعد الجدولة

يغيّر موعد تشغيل أتمتة بانتظار التشغيل (status بقيمة pending). ولا يمكن تغيير الأتمتة التي بدأت أو انتهت.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
auto_unique المسار string إلزامي — معرّف عملية الأتمتة
reserved_at الجسم string إلزامي — موعد التشغيل الجديد (تاريخ ووقت في المستقبل). حدده بصيغة ISO 8601 مع فرق التوقيت، وتُعامل القيم التي لا تتضمن فرق التوقيت على أنها UTC
حقول الاستجابة
الحقلالنوعالوصف
auto_unique string معرّف عملية الأتمتة
mode string moviemode / blogmode / carouselmode
project object المشروع {project_unique, project_name}
content.variation_unique string معرّف المحتوى
content.title string | null العنوان (اسم المفهوم لـ postmode)
run_no integer رقم هذه العملية بالنسبة إلى المحتوى
status string الحالة. pending (بانتظار التشغيل؛ مجدولة عندما يكون reserved_at في المستقبل) / executing (قيد التشغيل) / waiting_confirmation (بانتظار مراجعة المحتوى؛ تستمر بعد المراجعة) / completed (اكتملت) / failed (فشلت) / stopped (أُوقفت) / token_shortage (انتهت لنفاد Token)
execution_mode string sequential (واحدة تلو الأخرى) / parallel (في آنٍ واحد)
phases object حالة كل مرحلة {setup, step1, step2, step3}. not_started (لم تبدأ) / running (قيد التشغيل، أو المرحلة التي توقفت عندها) / done (اكتملت، بما في ذلك المتخطاة، وفي run انتهى بالحالة completed، الخطوات التي كانت خارج نطاق هذا الـ run) / error (فشلت)
template.setup_template_name string | null اسم قالب الإعداد المستخدم عند البدء
template.automation_template_name string | null اسم قالب الأتمتة المستخدم عند البدء
reserved_at string | null موعد التشغيل المجدول
executed_at string | null وقت بدء التشغيل
completed_at string | null وقت انتهاء العملية (عند completed / failed / stopped / token_shortage)
created_at string وقت تسجيل العملية
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
404 not_found الأتمتة غير موجودة أو خارج نطاق ما يمكنك الوصول إليه (Automation not found.)
409 automation_not_pending ليست بانتظار التشغيل (pending)، فقد بدأت أو انتهت
422 validation_error قيمة reserved_at مفقودة أو لا يمكن قراءتها تاريخًا ووقتًا أو تقع في الماضي
مثال على الطلب
curl -X PATCH "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "reserved_at": "2031-05-06T07:08:09+09:00"
}'
import requests

body = """{
  "reserved_at": "2031-05-06T07:08:09+09:00"
}"""

response = requests.request(
    "PATCH",
    "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi", {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "reserved_at": "2031-05-06T07:08:09+09:00"
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi")!)
request.httpMethod = "PATCH"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = """
{
  "reserved_at": "2031-05-06T07:08:09+09:00"
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .method("PATCH", HttpRequest.BodyPublishers.ofString("""
        {
          "reserved_at": "2031-05-06T07:08:09+09:00"
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "reserved_at": "2031-05-06T07:08:09+09:00"
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "auto_unique": "Qw3eRt6yUi",
    "mode": "blogmode",
    "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
    "content": { "variation_unique": "Ab3dEf6hIj9k", "title": "My blog title" },
    "run_no": 1,
    "status": "pending",
    "execution_mode": "sequential",
    "phases": { "setup": "running", "step1": "not_started", "step2": "not_started", "step3": "not_started" },
    "template": { "setup_template_name": null, "automation_template_name": "Morning blog" },
    "reserved_at": "2031-05-05T22:08:09Z",
    "executed_at": null,
    "completed_at": null,
    "created_at": "2026-10-21T10:00:00Z"
  }
}
POST › /automations/{auto_unique}/stop

إيقاف الأتمتة

العملية نفسها التي يجريها الإيقاف في التطبيق. متاحة في أي خطة (لتتمكن من الإيقاف حتى بعد تغيير خطتك). تصبح الأتمتة التي تنتظر التشغيل (بما فيها المجدولة) أو تنتظر المراجعة stopped فورًا. أما الأتمتة قيد التشغيل فيُطلب إيقافها: تبقى executing وقت الاستجابة، ثم تصبح stopped عند الفاصل التالي بين الخطوات (تحقق عبر GET /automations/{auto_unique}). وتُترك الأتمتة المنتهية كما هي وتُعاد حالتها الحالية.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
auto_unique المسار string إلزامي — معرّف عملية الأتمتة
حقول الاستجابة
الحقلالنوعالوصف
auto_unique string معرّف عملية الأتمتة
mode string moviemode / blogmode / carouselmode
project object المشروع {project_unique, project_name}
content.variation_unique string معرّف المحتوى
content.title string | null العنوان (اسم المفهوم لـ postmode)
run_no integer رقم هذه العملية بالنسبة إلى المحتوى
status string الحالة. pending (بانتظار التشغيل؛ مجدولة عندما يكون reserved_at في المستقبل) / executing (قيد التشغيل) / waiting_confirmation (بانتظار مراجعة المحتوى؛ تستمر بعد المراجعة) / completed (اكتملت) / failed (فشلت) / stopped (أُوقفت) / token_shortage (انتهت لنفاد Token)
execution_mode string sequential (واحدة تلو الأخرى) / parallel (في آنٍ واحد)
phases object حالة كل مرحلة {setup, step1, step2, step3}. not_started (لم تبدأ) / running (قيد التشغيل، أو المرحلة التي توقفت عندها) / done (اكتملت، بما في ذلك المتخطاة، وفي run انتهى بالحالة completed، الخطوات التي كانت خارج نطاق هذا الـ run) / error (فشلت)
template.setup_template_name string | null اسم قالب الإعداد المستخدم عند البدء
template.automation_template_name string | null اسم قالب الأتمتة المستخدم عند البدء
reserved_at string | null موعد التشغيل المجدول
executed_at string | null وقت بدء التشغيل
completed_at string | null وقت انتهاء العملية (عند completed / failed / stopped / token_shortage)
created_at string وقت تسجيل العملية
الأخطاء
الحالةالرمزمتى يحدث
404 not_found الأتمتة غير موجودة أو خارج نطاق ما يمكنك الوصول إليه (Automation not found.)
مثال على الطلب
curl -X POST "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/stop");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "auto_unique": "Qw3eRt6yUi",
    "mode": "blogmode",
    "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
    "content": { "variation_unique": "Ab3dEf6hIj9k", "title": "My blog title" },
    "run_no": 1,
    "status": "stopped",
    "execution_mode": "sequential",
    "phases": { "setup": "running", "step1": "not_started", "step2": "not_started", "step3": "not_started" },
    "template": { "setup_template_name": null, "automation_template_name": "Morning blog" },
    "reserved_at": "2030-01-02T03:04:05Z",
    "executed_at": null,
    "completed_at": "2026-10-21T10:05:00Z",
    "created_at": "2026-10-21T10:00:00Z"
  }
}
POST › /automations/{auto_unique}/confirm

الموافقة على أتمتة تنتظر المراجعة

بالنسبة إلى أتمتة متوقفة بانتظار مراجعة المحتوى (status بقيمة waiting_confirmation)، يعلّم المحتوى بأنه رُوجع ويُشغّل بقية الخطوات (إنشاء نصوص الشبكات الاجتماعية والنشر وما إلى ذلك). العملية نفسها التي تجري عند مراجعة المحتوى في التطبيق. وعند النجاح تعود الأتمتة إلى pending ويبدأ تشغيلها فورًا.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
auto_unique المسار string إلزامي — معرّف عملية الأتمتة
Idempotency-Key الترويسة string اختياري — سلسلة فريدة تُنشئها لكل عملية (من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة). إعادة إرسال المحتوى نفسه بالمفتاح نفسه تُعيد الاستجابة الأولى كما هي (راجع Idempotency-Key في المواصفات المشتركة)
حقول الاستجابة
الحقلالنوعالوصف
auto_unique string معرّف عملية الأتمتة
mode string moviemode / blogmode / carouselmode
project object المشروع {project_unique, project_name}
content.variation_unique string معرّف المحتوى
content.title string | null العنوان (اسم المفهوم لـ postmode)
run_no integer رقم هذه العملية بالنسبة إلى المحتوى
status string الحالة. pending (بانتظار التشغيل؛ مجدولة عندما يكون reserved_at في المستقبل) / executing (قيد التشغيل) / waiting_confirmation (بانتظار مراجعة المحتوى؛ تستمر بعد المراجعة) / completed (اكتملت) / failed (فشلت) / stopped (أُوقفت) / token_shortage (انتهت لنفاد Token)
execution_mode string sequential (واحدة تلو الأخرى) / parallel (في آنٍ واحد)
phases object حالة كل مرحلة {setup, step1, step2, step3}. not_started (لم تبدأ) / running (قيد التشغيل، أو المرحلة التي توقفت عندها) / done (اكتملت، بما في ذلك المتخطاة، وفي run انتهى بالحالة completed، الخطوات التي كانت خارج نطاق هذا الـ run) / error (فشلت)
template.setup_template_name string | null اسم قالب الإعداد المستخدم عند البدء
template.automation_template_name string | null اسم قالب الأتمتة المستخدم عند البدء
reserved_at string | null موعد التشغيل المجدول
executed_at string | null وقت بدء التشغيل
completed_at string | null وقت انتهاء العملية (عند completed / failed / stopped / token_shortage)
created_at string وقت تسجيل العملية
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
404 not_found الأتمتة غير موجودة أو خارج نطاق ما يمكنك الوصول إليه (Automation not found.)
409 automation_not_waiting_confirmation ليست بانتظار المراجعة (waiting_confirmation)
409 content_readonly المحتوى للقراءة فقط بسبب تخفيض الخطة
409 idempotency_request_in_progress طلب بالـ Idempotency-Key نفسه لا يزال قيد المعالجة
422 idempotency_key_invalid قيمة Idempotency-Key ليست من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة
422 idempotency_key_reused استُخدم الـ Idempotency-Key نفسه لطلب بمحتوى مختلف
503 automation_dispatch_failed فشل بدء تشغيل بقية الخطوات. تصبح الأتمتة failed (ويبقى المحتوى مُراجَعًا، لذا ابدأ أتمتة جديدة للمتابعة)
مثال على الطلب
curl -X POST "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90"
import requests

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/automations/Qw3eRt6yUi/confirm");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "auto_unique": "Qw3eRt6yUi",
    "mode": "carouselmode",
    "project": { "project_unique": "Pj8kL3mN2b", "project_name": "My Project" },
    "content": { "variation_unique": "Ab3dEf6hIj9k", "title": "My carousel title" },
    "run_no": 1,
    "status": "pending",
    "execution_mode": "parallel",
    "phases": { "setup": "done", "step1": "done", "step2": "done", "step3": "running" },
    "template": { "setup_template_name": null, "automation_template_name": "Weekly carousel" },
    "reserved_at": null,
    "executed_at": "2026-10-21T09:00:00Z",
    "completed_at": null,
    "created_at": "2026-10-21T09:00:00Z"
  }
}

مراجعة المنشورات

بالنسبة إلى محتوى أتمتة المنشورات (وضع المنشور) المضبوط على مراجعة إلزامية أو اختيارية قبل النشر، وافق على المنشورات أو انشرها الآن أو غيّر موعدها أو ألغِها. المنشورات المستهدفة هي نفسها الموجودة في قائمة المراجعة في التطبيق وفي روابط رسائل المراجعة، وتنطبق عليها القواعد نفسها. القائمة متاحة في أي خطة، أما العمليات فتتطلب خطة Pro أو أعلى.

GET › /post-confirms

المنشورات التي تنتظر المراجعة

يحصل على المنشورات التي أُرسلت لها رسالة مراجعة والتي لم يحن موعدها بعد (upcoming) أو انتهت مهلتها (expired)، مرتبةً حسب الموعد المجدول. منشورات upcoming هي المنشورات التي تنتظر الموافقة (awaiting، لا تُنشر دون موافقة) والمنشورات المكتفية بالإشعار (notice، تُنشر كما هي). أما منشورات expired فهي التي تجاوزت موعدها دون موافقة ولم تُنشر، وتُعاد لمدة 30 يومًا فقط بعد الموعد المجدول. تُعاد السلسلة عنصرًا واحدًا لأول منشور فيها، وتوضع المنشورات الثانية وما بعدها في thread. متاح في أي خطة.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
state الاستعلام string اختياري — التصفية حسب upcoming (قبل الموعد المجدول) أو expired (انتهت المهلة). كلاهما إذا حُذف
project_unique الاستعلام string اختياري — إعادة منشورات هذا المشروع فقط
page الاستعلام integer اختياري 1 الصفحة المطلوبة (بدءًا من 1)
per_page الاستعلام integer اختياري 20 عدد العناصر في الصفحة (من 1 إلى 100)
حقول الاستجابة
الحقلالنوعالوصف
data[].schedule_unique string معرّف المنشور المجدول. يُستخدم في مسارات العمليات
data[].state string | null upcoming (قبل الموعد المجدول) / expired (انتهت المهلة). null للمنشورات التي لم تعد قيد المراجعة بعد الموافقة أو تغيير الموعد وما إلى ذلك (في استجابات العمليات فقط)
data[].confirm_state string awaiting (تنتظر الموافقة، لا تُنشر حتى الموافقة) / notice (إشعار فقط، تُنشر كما هي) / confirmed (تمت الموافقة) / none (بلا مراجعة)
data[].confirm_mode string إعداد مراجعة المحتوى. required (لا يُنشر حتى الموافقة) / optional (يُنشر حتى دون موافقة) / none (بلا مراجعة)
data[].can_approve boolean هل يمكن الموافقة عليه (true عندما يكون upcoming وawaiting)
data[].can_post_now boolean هل يمكن نشره الآن (true عندما يكون expired)
data[].can_reschedule boolean هل يمكن تغيير موعده (true عندما يكون expired)
data[].scheduled_at string موعد النشر المجدول
data[].scheduled_at_local string الموعد المجدول بالتوقيت المحلي لـ timezone (YYYY-MM-DDTHH:MM:SS)
data[].timezone string المنطقة الزمنية وقت إنشاء الخطة
data[].deadline_at string | null آخر موعد للعمليات. بالنسبة إلى upcoming هو الموعد المجدول (وبعده يصبح expired)، وبالنسبة إلى expired هو بعد 30 يومًا من الموعد المجدول (وبعده يختفي من القائمة ولا يمكن التعامل معه). null إذا كانت قيمة state هي null
data[].project object المشروع {project_unique, project_name}
data[].concept object المفهوم {concept_unique, concept_name}
data[].variation_unique string معرّف المحتوى
data[].post_unique string معرّف المنشور (مطابق لـ items[].post_unique في جدول النشر)
data[].post_type string نوع المنشور. assertion (رأي) / knowhow (معرفة عملية) / experience (تجربة) / casual (يومي)
data[].text string نص المنشور (أول منشور في السلسلة)
data[].thread[] object المنشورات الثانية وما بعدها في السلسلة {text, image} (بالترتيب، ومصفوفة فارغة إذا لم تكن سلسلة)
data[].image object | null الصورة المرفقة {url, expires_at} (رابط موقّع تنتهي صلاحيته بعد ساعة واحدة). null إذا لم توجد
meta.total integer العدد الإجمالي للعناصر المطابقة
meta.current_page integer الصفحة الحالية
meta.per_page integer عدد العناصر في الصفحة
meta.last_page integer الصفحة الأخيرة
الأخطاء
الحالةالرمزمتى يحدث
404 not_found المشروع غير موجود أو خارج نطاق ما يمكنك الوصول إليه (Project not found.)
422 validation_error المعاملات غير صحيحة
مثال على الطلب
curl "https://stepeee.com/public-api/v1/post-confirms?state=upcoming" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/post-confirms?state=upcoming",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-confirms?state=upcoming", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-confirms?state=upcoming")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-confirms?state=upcoming"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/post-confirms?state=upcoming");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "schedule_unique": "aB3dE5fG7hJ9",
      "state": "upcoming",
      "confirm_state": "awaiting",
      "confirm_mode": "required",
      "can_approve": true,
      "can_post_now": false,
      "can_reschedule": false,
      "scheduled_at": "2026-10-19T13:00:00Z",
      "scheduled_at_local": "2026-10-19T22:00:00",
      "timezone": "Asia/Tokyo",
      "deadline_at": "2026-10-19T13:00:00Z",
      "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
      "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
      "variation_unique": "Vr5Ws7Xt9Yu1",
      "post_unique": "Ps3Qt5Ru7Sv9",
      "post_type": "knowhow",
      "text": "First post of the thread",
      "thread": [
        { "text": "Second post", "image": null },
        { "text": "Third post", "image": { "url": "https://...", "expires_at": "2026-10-19T13:00:00Z" } }
      ],
      "image": null
    }
  ],
  "meta": { "total": 1, "current_page": 1, "per_page": 20, "last_page": 1 }
}
POST › /post-schedules/{schedule_unique}/approve

الموافقة على منشور

يوافق على منشور ينتظر الموافقة (upcoming مع confirm_state بقيمة awaiting). تُنشر المنشورات الموافق عليها في موعدها المجدول. أما المنشورات التي تجاوزت موعدها فاستخدم النشر الآن أو تغيير الموعد.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
schedule_unique المسار string إلزامي — معرّف المنشور المجدول (schedule_unique من GET /post-confirms)
Idempotency-Key الترويسة string اختياري — سلسلة فريدة تُنشئها لكل عملية (من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة). إعادة إرسال المحتوى نفسه بالمفتاح نفسه تُعيد الاستجابة الأولى كما هي (راجع Idempotency-Key في المواصفات المشتركة)
حقول الاستجابة
الحقلالنوعالوصف
schedule_unique / state / … / image — مطابق لعنصر واحد في قائمة المنشورات التي تنتظر المراجعة (الحالة بعد العملية)
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
404 post_schedule_not_found منشور لا يظهر في GET /post-confirms (غير موجود أو خارج نطاق وصولك أو ليس قيد المراجعة أو تمت الموافقة عليه)
409 confirm_expired تجاوز الموعد المجدول (استخدم النشر الآن أو تغيير الموعد)
409 confirm_not_pending لا ينتظر الموافقة (مثل منشور مكتفٍ بالإشعار)
409 idempotency_request_in_progress طلب بالـ Idempotency-Key نفسه لا يزال قيد المعالجة
422 idempotency_key_invalid قيمة Idempotency-Key ليست من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة
422 idempotency_key_reused استُخدم الـ Idempotency-Key نفسه لطلب بمحتوى مختلف
مثال على الطلب
curl -X POST "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90"
import requests

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/approve");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "state": null,
    "confirm_state": "confirmed",
    "confirm_mode": "required",
    "can_approve": false,
    "can_post_now": false,
    "can_reschedule": false,
    "scheduled_at": "2026-10-19T13:00:00Z",
    "scheduled_at_local": "2026-10-19T22:00:00",
    "timezone": "Asia/Tokyo",
    "deadline_at": null,
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
    "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
    "variation_unique": "Vr5Ws7Xt9Yu1",
    "post_unique": "Ps3Qt5Ru7Sv9",
    "post_type": "knowhow",
    "text": "First post of the thread",
    "thread": [
      { "text": "Second post", "image": null },
      { "text": "Third post", "image": { "url": "https://...", "expires_at": "2026-10-19T13:00:00Z" } }
    ],
    "image": null
  }
}
POST › /post-schedules/{schedule_unique}/post-now

نشر منشور منتهي المهلة الآن

يجدول منشورًا منتهي المهلة ليُنشر بعد دقيقة واحدة من الآن ويعلّمه بأنه تمت الموافقة عليه (سيُنشر قريبًا). وتُزاح المنشورات الثانية وما بعدها في السلسلة بالمقدار نفسه. لا يمكن استخدامه إلا مع المنشورات منتهية المهلة.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
schedule_unique المسار string إلزامي — معرّف المنشور المجدول (schedule_unique من GET /post-confirms)
allow_close_slot الجسم boolean اختياري false true للمتابعة حتى لو أصبح الفاصل عن المنشورات المجدولة الأخرى للمحتوى نفسه أقصر من الحد الأدنى (90 دقيقة)
Idempotency-Key الترويسة string اختياري — سلسلة فريدة تُنشئها لكل عملية (من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة). إعادة إرسال المحتوى نفسه بالمفتاح نفسه تُعيد الاستجابة الأولى كما هي (راجع Idempotency-Key في المواصفات المشتركة)
حقول الاستجابة
الحقلالنوعالوصف
schedule_unique / state / … / image — مطابق لعنصر واحد في قائمة المنشورات التي تنتظر المراجعة (الحالة بعد العملية)
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
403 resource_readonly المحتوى للقراءة فقط بسبب تخفيض الخطة
404 post_schedule_not_found منشور لا يظهر في GET /post-confirms (غير موجود أو خارج نطاق وصولك أو ليس قيد المراجعة أو تمت الموافقة عليه)
409 confirm_not_expired لم تنتهِ المهلة (استخدم الموافقة قبل الموعد المجدول)
409 schedule_close_to_other_slot قيمة allow_close_slot هي false، وسيصبح الفاصل عن منشور مجدول آخر للمحتوى نفسه أقصر من 90 دقيقة. يحتوي details على min_gap_minutes (الحد الأدنى للفاصل بالدقائق) وtimezone وconflicts (مصفوفة من المنشورات المجدولة القريبة {scheduled_at_local, minutes_apart})
409 schedule_locked قيد النشر أو منشور مسبقًا، أو خلال دقيقتين من الموعد المجدول حيث يتداخل مع النشر
409 schedule_processing جرت العملية في الوقت نفسه مع النشر وتعذّر تطبيقها
409 idempotency_request_in_progress طلب بالـ Idempotency-Key نفسه لا يزال قيد المعالجة
422 validation_error قيمة allow_close_slot ليست true أو false
422 idempotency_key_invalid قيمة Idempotency-Key ليست من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة
422 idempotency_key_reused استُخدم الـ Idempotency-Key نفسه لطلب بمحتوى مختلف
مثال على الطلب
curl -X POST "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90" \
  -d '{
  "allow_close_slot": true
}'
import requests

body = """{
  "allow_close_slot": true
}"""

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
  body: JSON.stringify({
    "allow_close_slot": true
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")
request.httpBody = """
{
  "allow_close_slot": true
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "allow_close_slot": true
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "allow_close_slot": true
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9/post-now");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "state": null,
    "confirm_state": "confirmed",
    "confirm_mode": "required",
    "can_approve": false,
    "can_post_now": false,
    "can_reschedule": false,
    "scheduled_at": "2026-10-21T12:01:00Z",
    "scheduled_at_local": "2026-10-21T21:01:00",
    "timezone": "Asia/Tokyo",
    "deadline_at": null,
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
    "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
    "variation_unique": "Vr5Ws7Xt9Yu1",
    "post_unique": "Ps3Qt5Ru7Sv9",
    "post_type": "knowhow",
    "text": "First post of the thread",
    "thread": [
      { "text": "Second post", "image": null },
      { "text": "Third post", "image": { "url": "https://...", "expires_at": "2026-10-19T13:00:00Z" } }
    ],
    "image": null
  }
}
PATCH › /post-schedules/{schedule_unique}

تغيير موعد منشور منتهي المهلة

يغيّر الموعد المجدول لمنشور منتهي المهلة ويعلّمه بأنه تمت الموافقة عليه (سيُنشر في الموعد المحدد). وتُزاح المنشورات الثانية وما بعدها في السلسلة بالمقدار نفسه. لا يمكن تغيير الموعد إلا للمنشورات منتهية المهلة.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
schedule_unique المسار string إلزامي — معرّف المنشور المجدول (schedule_unique من GET /post-confirms)
scheduled_at الجسم string إلزامي — الموعد المجدول الجديد (تاريخ ووقت في المستقبل). حدده بصيغة ISO 8601 مع فرق التوقيت (مثل 2026-10-21T09:30:00+09:00 أو 2026-10-21T00:30:00Z، ويمكن حذف الثواني وتُقتطع أجزاء الثانية). ويُحوَّل إلى الوقت في timezone الخاص بالمنشور ثم يُحفظ
allow_close_slot الجسم boolean اختياري false true للمتابعة حتى لو أصبح الفاصل عن المنشورات المجدولة الأخرى للمحتوى نفسه أقصر من الحد الأدنى (90 دقيقة)
حقول الاستجابة
الحقلالنوعالوصف
schedule_unique / state / … / image — مطابق لعنصر واحد في قائمة المنشورات التي تنتظر المراجعة (الحالة بعد العملية)
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
403 resource_readonly المحتوى للقراءة فقط بسبب تخفيض الخطة
404 post_schedule_not_found منشور لا يظهر في GET /post-confirms (غير موجود أو خارج نطاق وصولك أو ليس قيد المراجعة أو تمت الموافقة عليه)
409 confirm_not_expired لم تنتهِ المهلة (استخدم الموافقة قبل الموعد المجدول)
409 schedule_close_to_other_slot قيمة allow_close_slot هي false، وسيصبح الفاصل عن منشور مجدول آخر للمحتوى نفسه أقصر من 90 دقيقة. يحتوي details على min_gap_minutes (الحد الأدنى للفاصل بالدقائق) وtimezone وconflicts (مصفوفة من المنشورات المجدولة القريبة {scheduled_at_local, minutes_apart})
409 schedule_locked قيد النشر أو منشور مسبقًا، أو خلال دقيقتين من الموعد المجدول حيث يتداخل مع النشر
409 schedule_processing جرت العملية في الوقت نفسه مع النشر وتعذّر تطبيقها
422 confirm_reschedule_past قيمة scheduled_at في الوقت الحالي أو قبله
422 validation_error قيمة scheduled_at مفقودة أو بلا فرق توقيت أو لا يمكن قراءتها تاريخًا ووقتًا، أو قيمة allow_close_slot ليست true أو false
مثال على الطلب
curl -X PATCH "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
  "scheduled_at": "2026-10-22T09:30:00-05:00",
  "allow_close_slot": false
}'
import requests

body = """{
  "scheduled_at": "2026-10-22T09:30:00-05:00",
  "allow_close_slot": false
}"""

response = requests.request(
    "PATCH",
    "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9", {
  method: "PATCH",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "scheduled_at": "2026-10-22T09:30:00-05:00",
    "allow_close_slot": false
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9")!)
request.httpMethod = "PATCH"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = """
{
  "scheduled_at": "2026-10-22T09:30:00-05:00",
  "allow_close_slot": false
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .method("PATCH", HttpRequest.BodyPublishers.ofString("""
        {
          "scheduled_at": "2026-10-22T09:30:00-05:00",
          "allow_close_slot": false
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "scheduled_at": "2026-10-22T09:30:00-05:00",
  "allow_close_slot": false
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "state": null,
    "confirm_state": "confirmed",
    "confirm_mode": "required",
    "can_approve": false,
    "can_post_now": false,
    "can_reschedule": false,
    "scheduled_at": "2026-10-22T14:30:00Z",
    "scheduled_at_local": "2026-10-22T23:30:00",
    "timezone": "Asia/Tokyo",
    "deadline_at": null,
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
    "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
    "variation_unique": "Vr5Ws7Xt9Yu1",
    "post_unique": "Ps3Qt5Ru7Sv9",
    "post_type": "knowhow",
    "text": "First post of the thread",
    "thread": [
      { "text": "Second post", "image": null },
      { "text": "Third post", "image": { "url": "https://...", "expires_at": "2026-10-19T13:00:00Z" } }
    ],
    "image": null
  }
}
DELETE › /post-schedules/{schedule_unique}

إلغاء منشور

يلغي منشورًا (سواء قبل موعده المجدول أو بعد انتهاء مهلته). يُحذف المنشور والمنشورات الثانية وما بعدها في السلسلة والجدولة معًا. ولا يمكن التراجع عن ذلك.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
schedule_unique المسار string إلزامي — معرّف المنشور المجدول (schedule_unique من GET /post-confirms)
حقول الاستجابة
الحقلالنوعالوصف
schedule_unique string معرّف المنشور المجدول الملغى
deleted boolean true دائمًا
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
403 resource_readonly المحتوى للقراءة فقط بسبب تخفيض الخطة
404 post_schedule_not_found منشور لا يظهر في GET /post-confirms (غير موجود أو خارج نطاق وصولك أو ليس قيد المراجعة أو تمت الموافقة عليه)
409 post_posting_locked قيد النشر (بما في ذلك المنشورات الثانية وما بعدها في السلسلة) ولا يمكن إلغاؤه
مثال على الطلب
curl -X DELETE "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "DELETE",
    "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9")!)
request.httpMethod = "DELETE"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("DELETE", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/post-schedules/aB3dE5fG7hJ9");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "deleted": true
  }
}

Webhook

يرسل أحداث الأتمتة والنشر بصيغة JSON إلى عناوين URL التي تسجلها. استخدمه لمعرفة الاكتمال والفشل والمراجعة دون استدعاء API مرارًا. يتطلب التسجيل وإرسال الاختبار خطة Pro أو أعلى، أما العرض والحذف فمتاحان في أي خطة.

GET › /webhooks

قائمة نقاط Webhook

يحصل على النقاط المسجلة بترتيب تسجيلها (5 كحد أقصى، دون ترقيم صفحات). لا يتضمن سر التوقيع. متاح في أي خطة.

حقول الاستجابة
الحقلالنوعالوصف
data[].webhook_unique string معرّف النقطة
data[].url string عنوان URL للوجهة
data[].events string[] أسماء الأحداث المراد استقبالها
data[].description string | null ملاحظة
data[].is_active boolean هل تُرسَل الأحداث حاليًا. true عندما يكون المالك على خطة Pro أو أعلى (وبالنسبة إلى أعضاء الفريق عندما يكون مالك الفريق على خطة Team). ولا تُرسَل الأحداث التي تقع وهي false
data[].last_delivery_at string | null موعد آخر محاولة إرسال (لا يشمل إرسال الاختبار)
data[].last_delivery_status string | null نتيجة آخر إرسال. succeeded (نجح) / failed (فشل). null إذا لم يُرسَل شيء بعد
data[].last_response_status integer | null حالة HTTP المستلمة في آخر إرسال (null إذا لم توجد استجابة)
data[].last_error string | null سبب فشل آخر إرسال. القيم مطابقة لقيمة error في إرسال الاختبار
data[].created_at string تاريخ الإنشاء
مثال على الطلب
curl "https://stepeee.com/public-api/v1/webhooks" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.get(
    "https://stepeee.com/public-api/v1/webhooks",
    headers={"Authorization": "Bearer sk_xxxxxxxxxxxxxxxx"},
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/webhooks", {
  headers: { Authorization: "Bearer sk_xxxxxxxxxxxxxxxx" },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/webhooks")!)
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/webhooks"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/webhooks");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": [
    {
      "webhook_unique": "Xk3pQ9vLm2Ta",
      "url": "https://example.com/hooks/stepeee",
      "events": ["automation.completed", "post.published"],
      "description": "production hook",
      "is_active": true,
      "last_delivery_at": "2026-10-21T12:01:00Z",
      "last_delivery_status": "failed",
      "last_response_status": 503,
      "last_error": "non_2xx_response",
      "created_at": "2026-10-20T09:00:00Z"
    }
  ]
}
POST › /webhooks

تسجيل نقطة Webhook

يسجّل نقطة. يُعاد secret (سر التوقيع) في هذه الاستجابة فقط، ولا توجد طريقة لعرضه لاحقًا. وإذا فقدته فاحذف النقطة وسجّلها من جديد. يمكنك تسجيل 5 نقاط كحد أقصى. ولا تُرسَل الأحداث التي وقعت قبل التسجيل.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
url الجسم string إلزامي — عنوان URL للوجهة (https فقط، والمنفذ 443 فقط (يمكن حذفه)، و2048 حرفًا كحد أقصى). لا يمكن تسجيل عناوين URL التي تحتوي على اسم مستخدم أو كلمة مرور. ولا يمكن تسجيل عناوين URL التي تُحلّ إلى عناوين داخلية أو محجوزة (عناوين IP خاصة، وعنوان الاسترجاع، وعناوين الربط المحلي، وlocalhost، وما إلى ذلك) ولا عناوين URL التي يتعذّر حل اسمها
events الجسم string[] إلزامي — أسماء الأحداث المراد استقبالها (واحد أو أكثر من قائمة الأحداث، دون تكرار)
description الجسم string | null اختياري — ملاحظة (100 حرف كحد أقصى)
Idempotency-Key الترويسة string اختياري — سلسلة فريدة تُنشئها لكل عملية (من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة). إعادة إرسال المحتوى نفسه بالمفتاح نفسه تُعيد الاستجابة الأولى كما هي (راجع Idempotency-Key في المواصفات المشتركة)
حقول الاستجابة
الحقلالنوعالوصف
webhook_unique string معرّف النقطة
url string عنوان URL للوجهة
events string[] أسماء الأحداث المراد استقبالها
description string | null ملاحظة
is_active boolean هل تُرسَل الأحداث حاليًا. true عندما يكون المالك على خطة Pro أو أعلى (وبالنسبة إلى أعضاء الفريق عندما يكون مالك الفريق على خطة Team). ولا تُرسَل الأحداث التي تقع وهي false
last_delivery_at string | null موعد آخر محاولة إرسال (لا يشمل إرسال الاختبار)
last_delivery_status string | null نتيجة آخر إرسال. succeeded (نجح) / failed (فشل). null إذا لم يُرسَل شيء بعد
last_response_status integer | null حالة HTTP المستلمة في آخر إرسال (null إذا لم توجد استجابة)
last_error string | null سبب فشل آخر إرسال. القيم مطابقة لقيمة error في إرسال الاختبار
created_at string تاريخ الإنشاء
secret string سر التوقيع (يبدأ بـ whsec_). يُعاد في هذه الاستجابة فقط
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
409 webhook_limit_reached سجّلت 5 نقاط مسبقًا
409 idempotency_request_in_progress طلب بالـ Idempotency-Key نفسه لا يزال قيد المعالجة
422 validation_error الإدخال غير صحيح (عنوان URL ليس https، أو منفذ غير 443، أو عنوان URL يحتوي على اسم مستخدم أو كلمة مرور، أو عنوان URL يُحلّ إلى عنوان داخلي أو يتعذّر حل اسمه، أو اسم حدث غير معروف، أو تكرار أسماء الأحداث، وما إلى ذلك)
422 idempotency_key_invalid قيمة Idempotency-Key ليست من 1 إلى 255 حرفًا من أحرف ASCII القابلة للطباعة
422 idempotency_key_reused استُخدم الـ Idempotency-Key نفسه لطلب بمحتوى مختلف
مثال على الطلب
curl -X POST "https://stepeee.com/public-api/v1/webhooks" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90" \
  -d '{
  "url": "https://example.com/hooks/stepeee",
  "events": ["automation.completed", "post.published"],
  "description": "production hook"
}'
import requests

body = """{
  "url": "https://example.com/hooks/stepeee",
  "events": ["automation.completed", "post.published"],
  "description": "production hook"
}"""

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/webhooks",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
        "Content-Type": "application/json",
        "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
    },
    data=body,
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/webhooks", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type": "application/json",
    "Idempotency-Key": "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
  },
  body: JSON.stringify({
    "url": "https://example.com/hooks/stepeee",
    "events": ["automation.completed", "post.published"],
    "description": "production hook"
  }),
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/webhooks")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90", forHTTPHeaderField: "Idempotency-Key")
request.httpBody = """
{
  "url": "https://example.com/hooks/stepeee",
  "events": ["automation.completed", "post.published"],
  "description": "production hook"
}
""".data(using: .utf8)

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/webhooks"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .header("Content-Type", "application/json")
    .header("Idempotency-Key", "5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
        {
          "url": "https://example.com/hooks/stepeee",
          "events": ["automation.completed", "post.published"],
          "description": "production hook"
        }
        """))
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$body = <<<'JSON'
{
  "url": "https://example.com/hooks/stepeee",
  "events": ["automation.completed", "post.published"],
  "description": "production hook"
}
JSON;

$ch = curl_init("https://stepeee.com/public-api/v1/webhooks");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
    "Content-Type: application/json",
    "Idempotency-Key: 5f0c2d8e-7a41-4c1b-9d3e-2b8f6a1c4e90",
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "webhook_unique": "Xk3pQ9vLm2Ta",
    "url": "https://example.com/hooks/stepeee",
    "events": ["automation.completed", "post.published"],
    "description": "production hook",
    "is_active": true,
    "last_delivery_at": null,
    "last_delivery_status": null,
    "last_response_status": null,
    "last_error": null,
    "created_at": "2026-10-21T12:00:00Z",
    "secret": "whsec_5f0c2a9e8b7d4c3a1f6e9d8c7b6a5f4e3d2c1b0a9f8e7d6c"
  }
}
DELETE › /webhooks/{webhook_unique}

حذف نقطة Webhook

يحذف نقطة. ولا تُرسَل كذلك الأحداث التي لم تُرسَل بعد والأحداث التي تنتظر إعادة المحاولة. متاح في أي خطة.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
webhook_unique المسار string إلزامي — معرّف النقطة
حقول الاستجابة
الحقلالنوعالوصف
webhook_unique string معرّف النقطة المحذوفة
deleted boolean true دائمًا
الأخطاء
الحالةالرمزمتى يحدث
404 not_found النقطة غير موجودة أو تخص مستخدمًا آخر
مثال على الطلب
curl -X DELETE "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "DELETE",
    "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta", {
  method: "DELETE",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta")!)
request.httpMethod = "DELETE"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("DELETE", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "webhook_unique": "Xk3pQ9vLm2Ta",
    "deleted": true
  }
}
POST › /webhooks/{webhook_unique}/test

اختبار الإرسال

يرسل حدث webhook.test مرة واحدة في الحال ويُعيد النتيجة. يُرسَل بالتوقيع والترويسات وفحوص الوجهة نفسها المستخدمة مع الأحداث الفعلية، لذا يمكنك استخدامه للتحقق من التحقق من التوقيع في جهة الاستقبال. لا تُعاد محاولته ولا يُسجَّل في last_delivery_at والحقول المشابهة.

المعاملات
الاسم الموضع النوع إلزامي القيمة الافتراضية الوصف
webhook_unique المسار string إلزامي — معرّف النقطة
حقول الاستجابة
الحقلالنوعالوصف
delivered boolean هل استُلمت استجابة 2xx
response_status integer | null حالة HTTP المستلمة (null إذا لم توجد استجابة)
error string | null سبب الفشل. url_blocked (ليس https، أو منفذ غير 443، أو يحتوي على اسم مستخدم وكلمة مرور، أو حُلّ قبيل الإرسال إلى عنوان داخلي أو تعذّر حله) / timeout (لم تصل استجابة خلال 5 ثوانٍ) / connection_failed (فشل الاتصال أو TLS) / non_2xx_response (استجابة غير 2xx، وتُعامل إعادات التوجيه أيضًا على أنها فشل ولا تُتبع). null عند النجاح
الأخطاء
الحالةالرمزمتى يحدث
403 plan_required مالك مفتاح API على خطة أدنى من Pro
403 team_plan_lost أنت عضو في فريق ولم يعد مالك الفريق على خطة Team
404 not_found النقطة غير موجودة أو تخص مستخدمًا آخر
مثال على الطلب
curl -X POST "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test" \
  -H "Authorization: Bearer sk_xxxxxxxxxxxxxxxx"
import requests

response = requests.request(
    "POST",
    "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test",
    headers={
        "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
    },
)
print(response.json())
const response = await fetch("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test", {
  method: "POST",
  headers: {
    "Authorization": "Bearer sk_xxxxxxxxxxxxxxxx",
  },
});
const data = await response.json();
console.log(data);
var request = URLRequest(url: URL(string: "https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test")!)
request.httpMethod = "POST"
request.setValue("Bearer sk_xxxxxxxxxxxxxxxx", forHTTPHeaderField: "Authorization")

let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test"))
    .header("Authorization", "Bearer sk_xxxxxxxxxxxxxxxx")
    .method("POST", HttpRequest.BodyPublishers.noBody())
    .build();

HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.body());
$ch = curl_init("https://stepeee.com/public-api/v1/webhooks/Xk3pQ9vLm2Ta/test");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    "Authorization: Bearer sk_xxxxxxxxxxxxxxxx",
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = curl_exec($ch);
curl_close($ch);

echo $response;
مثال على الاستجابة
{
  "data": {
    "delivered": false,
    "response_status": 500,
    "error": "non_2xx_response"
  }
}

الأحداث

عند وقوع حدث سجّلته، يُرسَل طلب POST إلى عنوان URL المسجل. ولا تُرسَل إلا أحداث المشاريع التي يستطيع مالك النقطة الوصول إليها في ذلك الوقت. وتُفحص الأحداث كل دقيقة، لذا قد يستغرق الوصول بضع دقائق. ولا تُرسَل الأحداث التي وقعت قبل تسجيل النقطة، ولا الأحداث التي وقعت بينما كان المالك على خطة أدنى من Pro (وبالنسبة إلى أعضاء الفريق بينما لم يكن مالك الفريق على خطة Team).

الحدثالمعنى
automation.waiting_confirmationتوقفت أتمتة (فيديو أو مدونة أو كاروسيل) بانتظار مراجعة المحتوى
automation.completedاكتملت أتمتة حتى نهايتها
automation.failedانتهت أتمتة بـ failed (فشل) أو stopped (إيقاف) أو token_shortage (نفاد Token)
post.publishedتم النشر على شبكة اجتماعية (أصبحت نتيجة نشر فيديو أو مدونة أو كاروسيل success، أو نُشر منشور (وضع المنشور) على X). يشمل ذلك المنشورات اليدوية والمؤتمتة
post.failedفشل النشر (أصبحت نتيجة نشر فيديو أو مدونة أو كاروسيل failed أو partial_success، أو تُخطّي منشور (وضع المنشور) لفشل النشر أو إنشاء النص)
post.confirm_requiredظهر منشور (وضع المنشور) ينتظر الموافقة في GET /post-confirms (لا يُنشر حتى الموافقة)
webhook.testإرسال اختبار (POST /webhooks/{webhook_unique}/test). لا يمكن استخدامه حدثًا للتسجيل

جسم الطلب

الجسم بصيغة JSON (UTF-8) من {id, type, created_at, data}. id هو معرّف الحدث (يبدأ بـ evt_)، وtype هو اسم الحدث، وcreated_at هو وقت تسجيل الحدث. وعند إعادة إرسال الحدث نفسه يبقى الجسم كما هو ولا يتغير سوى t في التوقيع. وشكل data لكل حدث كما يلي.

الحدثشكل data
automation.*الشكل نفسه لعنصر واحد من data[] في GET /automations. قيمة status هي waiting_confirmation مع automation.waiting_confirmation، وcompleted مع automation.completed، وfailed أو stopped أو token_shortage مع automation.failed
post.published
post.failed
الفيديو والمدونة والكاروسيل: عنصر واحد من data[] في GET /projects/{project_unique}/publications مضافًا إليه project. ومع post.failed تكون قيمة status هي failed أو partial_success، ويحتوي error_code على رمز الفشل نفسه الوارد في نتيجة النشر. المنشورات (وضع المنشور): الشكل نفسه مضافًا إليه schedule_unique. وpublication_unique هو معرّف المنشور (null للجدولة التي فشل إنشاء نصها)، وcontent.title هو اسم المفهوم، وaccount بقيمة null، وerror_code هو token_expired / api_error / not_found / insufficient_token / no_x_account / node_ws_timeout. استخدم is_automation لمعرفة ما إذا كان المنشور مؤتمتًا
post.confirm_requiredالشكل نفسه لعنصر واحد من data[] في GET /post-confirms، بالقيم وقت تسجيل الحدث. لا يُرسَل للمنشورات المكتفية بالإشعار (notice). تنتهي صلاحية رابط الصورة الموقّع بعد ساعة واحدة من التسجيل، فإذا وصل متأخرًا فاحصل عليه مجددًا عبر GET /post-confirms. وإذا أُعيد إنشاء منشور للجدولة نفسها فيصل مرة أخرى بقيمة post_unique جديدة
webhook.test{"webhook_unique": "…"}

أمثلة على الجسم

automation.failed
{
  "id": "evt_Q2x8Lr0aZk9MvB3pT7cYw1Nd",
  "type": "automation.failed",
  "created_at": "2026-10-21T12:01:03Z",
  "data": {
    "auto_unique": "a8Kd02LmQz",
    "mode": "blogmode",
    "project": { "project_unique": "Pj7Xc2Lq9W", "project_name": "My Project" },
    "content": { "variation_unique": "Vb3Nq8Ls1Kd0", "title": "How to start" },
    "run_no": 2,
    "status": "token_shortage",
    "execution_mode": "sequential",
    "phases": { "setup": "done", "step1": "done", "step2": "running", "step3": "not_started" },
    "template": { "setup_template_name": "Default", "automation_template_name": null },
    "reserved_at": null,
    "executed_at": "2026-10-21T11:40:00Z",
    "completed_at": "2026-10-21T12:00:41Z",
    "created_at": "2026-10-21T11:39:58Z"
  }
}
post.published
{
  "id": "evt_7hT2mWq9Zp3LxR8cVb1Nk5Ds",
  "type": "post.published",
  "created_at": "2026-10-21T12:02:10Z",
  "data": {
    "publication_unique": "Lg4Hs9Pq2Wx7",
    "mode": "moviemode",
    "project": { "project_unique": "Pj7Xc2Lq9W", "project_name": "My Project" },
    "content": { "variation_unique": "Mv8Kq2Zt5Rb1", "title": "5 tips" },
    "platform": "youtube",
    "account": { "account_unique": "Ac1Bd2Ef3Gh4", "name": "My Channel" },
    "status": "success",
    "post_url": "https://www.youtube.com/watch?v=xxxxxxxx",
    "error_code": null,
    "is_automation": true,
    "posted_at": "2026-10-21T12:01:55Z",
    "created_at": "2026-10-21T12:01:20Z"
  }
}
post.failed
{
  "id": "evt_9Zq1Lm4Xc7Vb2Nk8Ds3Pt6Wr",
  "type": "post.failed",
  "created_at": "2026-10-21T09:00:40Z",
  "data": {
    "publication_unique": "Pp5Kd8Lw2Qz9",
    "mode": "postmode",
    "project": { "project_unique": "Pj7Xc2Lq9W", "project_name": "My Project" },
    "content": { "variation_unique": "Pv4Lk9Qz2Wx6", "title": "My X concept" },
    "platform": "x",
    "account": null,
    "status": "failed",
    "post_url": null,
    "error_code": "token_expired",
    "is_automation": true,
    "posted_at": null,
    "created_at": "2026-10-20T21:00:12Z",
    "schedule_unique": "Sc6Hj1Kl8Mn3"
  }
}
post.confirm_required
{
  "id": "evt_3Kd8Lq2Wz7Xc1Vb9Nm4Pt6Rs",
  "type": "post.confirm_required",
  "created_at": "2026-10-19T08:15:02Z",
  "data": {
    "schedule_unique": "aB3dE5fG7hJ9",
    "state": "upcoming",
    "confirm_state": "awaiting",
    "confirm_mode": "required",
    "can_approve": true,
    "can_post_now": false,
    "can_reschedule": false,
    "scheduled_at": "2026-10-19T13:00:00Z",
    "scheduled_at_local": "2026-10-19T22:00:00",
    "timezone": "Asia/Tokyo",
    "deadline_at": "2026-10-19T13:00:00Z",
    "project": { "project_unique": "Pq7Rs9Tu1V", "project_name": "My brand" },
    "concept": { "concept_unique": "Cx2Yz4Wv6Ut8", "concept_name": "Morning tips" },
    "variation_unique": "Vr5Ws7Xt9Yu1",
    "post_unique": "Ps3Qt5Ru7Sv9",
    "post_type": "knowhow",
    "text": "First post of the thread",
    "thread": [
      { "text": "Second post", "image": null }
    ],
    "image": { "url": "https://...", "expires_at": "2026-10-19T09:15:02Z" }
  }
}
webhook.test
{
  "id": "evt_Q2x8Lr0aZk9MvB3pT7cYw1Nd",
  "type": "webhook.test",
  "created_at": "2026-10-21T12:00:00Z",
  "data": { "webhook_unique": "Xk3pQ9vLm2Ta" }
}

ترويسات الطلب

الترويسةالوصف
Content-Type: application/jsonصيغة الجسم
Stepeee-Signature: t=1792584000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bdالتوقيع. t هو وقت الإرسال (ثوانٍ UNIX)، وv1 هو التوقيع (HMAC-SHA256 بالنظام الست عشري). راجع التحقق من التوقيع أدناه لمعرفة طريقة التحقق
Stepeee-Event-Id: evt_Q2x8Lr0aZk9MvB3pT7cYw1Ndمعرّف الحدث (مطابق لـ id في الجسم). لا يتغير عند إعادة الإرسال، فاستخدمه لإزالة التكرار
Stepeee-Event-Type: automation.failedاسم الحدث (مطابق لـ type في الجسم)
User-Agent: Stepeee-Webhooks/1.0المُرسِل

التحقق من التوقيع

للتأكد من أن الجسم المستلم أرسله Stepeee ولم يُعدَّل، تحقق من التوقيع باتباع الخطوات التالية.

  1. قسّم الترويسة Stepeee-Signature عند «,» واستخرج قيمة t= (ثوانٍ UNIX) وقيمة v1= (64 حرفًا ست عشريًا).
  2. استخدم الجسم المستلم بايتاتٍ خام كما هو (دون تحليل JSON وإعادة بنائه)، وكوّن سلسلة تضم قيمة t و«.» والجسم متتالية.
  3. احسب HMAC-SHA256 باستخدام secret الذي تلقيته عند التسجيل (القيمة كاملة بما فيها whsec_) مفتاحًا، ورمّزه بالنظام الست عشري بأحرف صغيرة.
  4. قارن القيمة المحسوبة بـ v1 باستخدام مقارنة لا يعتمد زمنها على المحتوى (مثل hmac.compare_digest في Python أو hash_equals في PHP). وإذا لم تتطابقا فأعد 400 أو ما يماثلها ولا تعالج الطلب.
  5. لمنع إعادة إرسال الطلبات القديمة، نوصي برفض الطلبات التي يختلف فيها t عن الوقت الحالي بخمس دقائق أو أكثر.
  6. استخدم id في الجسم لتخطي الأحداث التي سبق أن عالجتها.

أمثلة على شيفرة التحقق

import hmac, hashlib, time

def verify(body: bytes, header: str, secret: str, tolerance: int = 300) -> bool:
    parts = dict(p.split("=", 1) for p in header.split(","))
    t, v1 = parts.get("t"), parts.get("v1")
    if not t or not v1 or abs(time.time() - int(t)) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{t}.".encode() + body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)

# Flask: verify(request.get_data(), request.headers["Stepeee-Signature"], SECRET)
const crypto = require("crypto");

function verify(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(",").map((p) => p.split("=", 2)));
  const t = parts.t, v1 = parts.v1;
  if (!t || !v1 || Math.abs(Date.now() / 1000 - Number(t)) > toleranceSec) return false;
  const expected = crypto.createHmac("sha256", secret).update(`${t}.`).update(rawBody).digest("hex");
  return v1.length === expected.length && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
}

// Express: receive the body as raw bytes with express.raw()
app.post("/hooks/stepeee", express.raw({ type: "application/json" }), (req, res) => {
  if (!verify(req.body, req.get("Stepeee-Signature"), process.env.STEPEEE_WEBHOOK_SECRET)) return res.sendStatus(400);
  const event = JSON.parse(req.body.toString("utf8"));
  res.sendStatus(200);
});
function verifyStepeeeSignature(string $body, string $header, string $secret, int $tolerance = 300): bool
{
    $parts = [];
    foreach (explode(',', $header) as $part) {
        [$k, $v] = array_pad(explode('=', $part, 2), 2, '');
        $parts[$k] = $v;
    }
    if (! isset($parts['t'], $parts['v1']) || abs(time() - (int) $parts['t']) > $tolerance) {
        return false;
    }
    $expected = hash_hmac('sha256', $parts['t'].'.'.$body, $secret);

    return hash_equals($expected, $parts['v1']);
}

$ok = verifyStepeeeSignature(file_get_contents('php://input'), $_SERVER['HTTP_STEPEEE_SIGNATURE'] ?? '', $secret);
# BODY: raw request body, T: t from Stepeee-Signature, SECRET: whsec_...
printf '%s.%s' "$T" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $NF}'
# The signature is valid if the output equals v1

شروط النجاح وإعادة المحاولة

إذا أعدت 2xx خلال 5 ثوانٍ فيُعامل الحدث على أنه سُلّم. ولا يُقرأ جسم الاستجابة ولا تُتبع إعادات التوجيه. وتُعاد محاولة الاستجابات غير 2xx وانتهاء المهلة وفشل الاتصال، بحد أقصى 8 إرسالات بما فيها الأول. والفواصل قبل الإرسال التالي هي دقيقة واحدة ← 5 دقائق ← 30 دقيقة ← ساعتان ← 4 ساعات ← 6 ساعات ← 10 ساعات، وإذا فشلت الإرسالات الثمانية كلها فلا يُرسَل الحدث. وإذا كان المالك وقت الإرسال على خطة أدنى من Pro (وبالنسبة إلى أعضاء الفريق إذا لم يكن مالك الفريق على خطة Team) فلا يُرسَل الحدث. ولا يُرسَل كذلك إذا لم يعد المالك قادرًا على الوصول إلى المشروع وقت الإرسال (غادر الفريق أو أُزيلت صلاحيته أو حُذف المشروع).

لأن الحدث نفسه يُعاد إرساله حتى تُستلم 2xx، قد يصل الحدث نفسه مرتين أو أكثر. أزل التكرار باستخدام Stepeee-Event-Id (قيمة id في الجسم). ولا يُضمن ترتيب الوصول. ونفّذ المعالجة الثقيلة بعد إعادة 2xx.

شروط الوجهة

يجب أن تكون الوجهات عناوين URL بصيغة https، ويقتصر المنفذ على 443. ولا يمكن كذلك تسجيل عناوين URL التي تحتوي على اسم مستخدم أو كلمة مرور. ولا يمكن تسجيل عناوين URL التي تُحلّ إلى عناوين داخلية أو محجوزة (عناوين IP خاصة، وعنوان الاسترجاع، وعناوين الربط المحلي، وlocalhost، وما إلى ذلك) ولا عناوين URL التي يتعذّر حل اسمها. ويُحلّ الاسم ويُفحص أيضًا قبيل الإرسال، وإذا حُلّ إلى عنوان داخلي فيفشل الإرسال بـ url_blocked دون أن يُرسَل.