API
READ
WRITE
طريقة الاتصال
تحقق من مفتاح API الخاص بك
يمكنك التحقق منه من القائمة أعلى اليسار > الإعدادات > الحساب > مفاتيح API.
أضفه إلى ترويسة الطلب
أضف مفتاح API الصادر إلى ترويسة Authorization بصيغة Bearer.
أرسل طلبًا إلى رابط 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 -
الاشتراك
GET /me/subscription -
رصيد Token
GET /me/tokens -
استخدام Token
GET /me/token-usage -
التخزين
GET /me/storage -
سجل المدفوعات
GET /me/payments -
برنامج الإحالة
GET /me/referral
معلومات الحساب
يحصل على الملف الشخصي لمالك مفتاح 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"
}
}
الاشتراك
يحصل على حالة خطتك الحالية وفترة الفوترة وأي إلغاء مجدول وأي تغيير مجدول للخطة. ويحصل أعضاء الفريق على اشتراك مالك الفريق.
| الحقل | النوع | الوصف |
|---|---|---|
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"
}
}
}
رصيد 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
}
}
}
استخدام 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
}
}
التخزين
يحصل على استخدام التخزين والسعة وتفصيل حسب نوع الملف. وفي الفريق يُعيد التخزين المشترك للفريق.
| الحقل | النوع | الوصف |
|---|---|---|
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 }
]
}
}
سجل المدفوعات
يحصل على المدفوعات مثل رسوم الخطة وشراء 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 }
}
برنامج الإحالة
يحصل على رمز الإحالة الخاص بك وحالة الإحالات والمكافآت.
| الحقل | النوع | الوصف |
|---|---|---|
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 -
تفاصيل المشروع
GET /projects/{project_unique} -
قائمة المفاهيم
GET /projects/{project_unique}/concepts -
تفاصيل المفهوم
GET /projects/{project_unique}/concepts/{concept_unique}
قائمة المشاريع
يحصل على المشاريع التي يمكنك الوصول إليها من الأحدث إلى الأقدم.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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 }
}
تفاصيل المشروع
يحصل على تفاصيل مشروع واحد مع عدد المفاهيم والعناوين لكل وضع وعدد عناصر المحتوى حسب التقدّم.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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 }
}
}
}
}
قائمة المفاهيم
يحصل على المفاهيم داخل المشروع عبر جميع الأوضاع من الأحدث إلى الأقدم.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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 }
}
تفاصيل المفهوم
يحصل على تفاصيل مفهوم واحد. تتضمن مفاهيم الفيديو والمدونة والكاروسيل قائمة العناوين، وتتضمن مفاهيم المنشورات (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 -
تفاصيل المحتوى
GET /projects/{project_unique}/contents/{variation_unique} -
جدول النشر
GET /projects/{project_unique}/contents/{variation_unique}/schedule
قائمة المحتوى
يحصل على المحتوى داخل المشروع (فيديو ومدونة وكاروسيل ومنشورات) عبر جميع الأوضاع. ويمكنك التصفية حسب التقدّم ولغة النشر وما إذا كان قد نُشر وغير ذلك.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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 }
}
تفاصيل المحتوى
يحصل على تفاصيل عنصر محتوى واحد. يحتوي 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"] }
}
}
}
جدول النشر
يحصل على المنشورات المخططة والمُولّدة والمنشورة لمحتوى المنشورات (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 -
الوجهات المرتبطة
GET /projects/{project_unique}/accounts
نتائج النشر
يحصل على نتائج النشر للمشروع عبر جميع الأوضاع والوجهات من الأحدث إلى الأقدم. وبالنسبة إلى المنشورات (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 }
}
الوجهات المرتبطة
يحصل على الوجهات المرتبطة بالمشروع (حسابات الشبكات الاجتماعية و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
}
]
}
الأتمتة
احصل على تقدّم أتمتة الفيديو والمدونة والكاروسيل. أما أتمتة المنشورات (وضع المنشور) فاستخدم جدول المحتوى للحصول عليها.
عمليات الأتمتة
يحصل على عمليات أتمتة الفيديو والمدونة والكاروسيل (المجدولة وقيد التشغيل وبانتظار المراجعة والمنتهية) من الأحدث إلى الأقدم.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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 }
}
تفاصيل عملية الأتمتة
يحصل على تفاصيل عملية أتمتة واحدة وتقدّم كل خطوة فيها. ويمكنك استخدامه لمتابعة التقدّم أثناء التشغيل.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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 -
تفاصيل المادة
GET /materials/{material_unique} -
فئات المواد
GET /material-categories -
قائمة القوالب
GET /templates
قائمة المواد
يحصل على موادي (الصور والفيديو و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 }
}
تفاصيل المادة
يحصل على مادة واحدة.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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"
}
}
فئات المواد
يحصل على فئات المواد وعدد المواد في كل فئة.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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
}
]
}
قائمة القوالب
يحصل على قوالب الإعداد وقوالب الأتمتة من الأحدث تحديثًا إلى الأقدم. وفي الفريق يُعيد القوالب المشتركة للفريق.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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 -
حذف المحتوى
DELETE /projects/{project_unique}/contents/{variation_unique}
إضافة عناوين
يضيف عناوين دفعة واحدة إلى مفهوم فيديو أو مدونة أو كاروسيل، وينشئ أول محتوى لكل عنوان (المعالجة نفسها التي تجري عند إضافة العناوين يدويًا في التطبيق). لا تُنشأ العناوين التي يوجد اسمها مسبقًا في المفهوم نفسه، ولا الأسماء التي تتكرر للمرة الثانية أو أكثر في الطلب نفسه، بل تُدرج في 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_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 -
تغيير موعد الجدولة
PATCH /automations/{auto_unique} -
إيقاف الأتمتة
POST /automations/{auto_unique}/stop -
الموافقة على أتمتة تنتظر المراجعة
POST /automations/{auto_unique}/confirm
بدء الأتمتة
يبدأ أتمتة المحتوى (فيديو أو مدونة أو كاروسيل) وفق إعدادات قالب أتمتة. إذا حددت 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"
}
]
}
تغيير موعد الجدولة
يغيّر موعد تشغيل أتمتة بانتظار التشغيل (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"
}
}
إيقاف الأتمتة
العملية نفسها التي يجريها الإيقاف في التطبيق. متاحة في أي خطة (لتتمكن من الإيقاف حتى بعد تغيير خطتك). تصبح الأتمتة التي تنتظر التشغيل (بما فيها المجدولة) أو تنتظر المراجعة 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"
}
}
الموافقة على أتمتة تنتظر المراجعة
بالنسبة إلى أتمتة متوقفة بانتظار مراجعة المحتوى (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 -
الموافقة على منشور
POST /post-schedules/{schedule_unique}/approve -
نشر منشور منتهي المهلة الآن
POST /post-schedules/{schedule_unique}/post-now -
تغيير موعد منشور منتهي المهلة
PATCH /post-schedules/{schedule_unique} -
إلغاء منشور
DELETE /post-schedules/{schedule_unique}
المنشورات التي تنتظر المراجعة
يحصل على المنشورات التي أُرسلت لها رسالة مراجعة والتي لم يحن موعدها بعد (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 }
}
الموافقة على منشور
يوافق على منشور ينتظر الموافقة (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
}
}
نشر منشور منتهي المهلة الآن
يجدول منشورًا منتهي المهلة ليُنشر بعد دقيقة واحدة من الآن ويعلّمه بأنه تمت الموافقة عليه (سيُنشر قريبًا). وتُزاح المنشورات الثانية وما بعدها في السلسلة بالمقدار نفسه. لا يمكن استخدامه إلا مع المنشورات منتهية المهلة.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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
}
}
تغيير موعد منشور منتهي المهلة
يغيّر الموعد المجدول لمنشور منتهي المهلة ويعلّمه بأنه تمت الموافقة عليه (سيُنشر في الموعد المحدد). وتُزاح المنشورات الثانية وما بعدها في السلسلة بالمقدار نفسه. لا يمكن تغيير الموعد إلا للمنشورات منتهية المهلة.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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
}
}
إلغاء منشور
يلغي منشورًا (سواء قبل موعده المجدول أو بعد انتهاء مهلته). يُحذف المنشور والمنشورات الثانية وما بعدها في السلسلة والجدولة معًا. ولا يمكن التراجع عن ذلك.
| الاسم | الموضع | النوع | إلزامي | القيمة الافتراضية | الوصف |
|---|---|---|---|---|---|
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 أو أعلى، أما العرض والحذف فمتاحان في أي خطة.
-
قائمة نقاط Webhook
GET /webhooks -
تسجيل نقطة Webhook
POST /webhooks -
حذف نقطة Webhook
DELETE /webhooks/{webhook_unique} -
اختبار الإرسال
POST /webhooks/{webhook_unique}/test
قائمة نقاط 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"
}
]
}
تسجيل نقطة 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"
}
}
حذف نقطة 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
}
}
اختبار الإرسال
يرسل حدث 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.publishedpost.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 ولم يُعدَّل، تحقق من التوقيع باتباع الخطوات التالية.
- قسّم الترويسة Stepeee-Signature عند «,» واستخرج قيمة t= (ثوانٍ UNIX) وقيمة v1= (64 حرفًا ست عشريًا).
- استخدم الجسم المستلم بايتاتٍ خام كما هو (دون تحليل JSON وإعادة بنائه)، وكوّن سلسلة تضم قيمة t و«.» والجسم متتالية.
- احسب HMAC-SHA256 باستخدام secret الذي تلقيته عند التسجيل (القيمة كاملة بما فيها whsec_) مفتاحًا، ورمّزه بالنظام الست عشري بأحرف صغيرة.
- قارن القيمة المحسوبة بـ v1 باستخدام مقارنة لا يعتمد زمنها على المحتوى (مثل hmac.compare_digest في Python أو hash_equals في PHP). وإذا لم تتطابقا فأعد 400 أو ما يماثلها ولا تعالج الطلب.
- لمنع إعادة إرسال الطلبات القديمة، نوصي برفض الطلبات التي يختلف فيها t عن الوقت الحالي بخمس دقائق أو أكثر.
- استخدم 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 دون أن يُرسَل.