مستندات API

احراز هویت

تمامی درخواست‌ها باید با هدر Authorization به صورت Basic Authentication ارسال شوند.

فرمت: Basic base64(mobile:api_token)

mobile: شماره موبایل مدیر پنل کاربری بدون صفر ابتدایی
api_token: توکن دریافت شده از قسمت توسعه دهندگان پنل کاربری

Api Url: https://panel-api.videm.ir

GET /api/__panel/me

دریافت اطلاعات کاربر

اطلاعات کاربر جاری را برمی‌گرداند

پاسخ موفق:

{
    "status": true,
    "data": {
        "name": "نام کاربر",
        "mobile": "09123456789",
        "balance": 100000,
        ...
    }
}
GET /api/__panel/courses

دریافت لیست دوره‌ها

لیست دوره‌های کاربر را برمی‌گرداند

پاسخ موفق:

{
    "status": "success", 
    "data": [
        {
            "id": 1,
            "title": "عنوان دوره",
            ...
        }
    ]
}
GET /api/__panel/courses/{uuid}

دریافت اطلاعات دوره

اطلاعات دوره مورد نظر را برمی‌گرداند

پاسخ موفق:

{
    "status": "success", 
    "data": [
        {
            "id": 1,
            "title": "عنوان دوره",
            "description": "مدرسه هنرهای دیجیتال ایران",
            "types": {
                "video": 123
            },
            "duration": 988992342, // بر حسب ثانیه
            "status": "Publish",
            "contents_count": 0,
            "customers_count": 0,
            "chapters": [
                {
                    "id": 280,
                    "title": "هفته اول",
                    "description": "",
                    "sort": 1,
                    "contents": [
                        {
                            "type": "video",
                            "sort": 1,
                            "video": {
                                "id": 1080,
                                "uuid": "855ad9e3-...",
                                "title": "شروع دوره",
                                "description": "",
                                "status": "منتشر شد",
                                "duration": 71235 // بر حسب ثانیه
                            }
                        }
                        // ...
                    ]
                }
            ]
        }
    ]
}
GET /api/__panel/courses/{course}/assistants

دریافت لیست کارکنان

لیست استادیاران را برمی‌گرداند

نیاز به دسترسی مدیریتی دارد

پاسخ موفق:

{
            "status": "success",
            "data": [
                {
                    "id": 1,
                    "name": "نام استادیار",
                    "mobile": "09123456789",
                    ...
                }
            ]
        }
GET /api/__panel/learning-paths

دریافت لیست مسیرهای آموزشی

مسیرهای آموزشی متعلق به owner فعلی را به‌صورت صفحه‌بندی‌شده برمی‌گرداند.

پارامترهای Query:

  • title: جست‌وجوی بخشی در عنوان مسیر آموزشی؛ اختیاری.
  • customer: جست‌وجوی بخشی در نام یا شماره موبایل شرکت‌کننده؛ اختیاری. شماره با صفر ابتدای آن نیز پذیرفته می‌شود.
  • page: شماره صفحه، حداقل ۱؛ اختیاری.
  • per_page: تعداد نتیجه در هر صفحه، بین ۱ تا ۱۰۰؛ پیش‌فرض ۱۵.

فیلترهای title و customer را می‌توان هم‌زمان ارسال کرد. هر آیتم شامل uuid دوره، عنوان، تعداد شرکت‌کننده‌ها و نام حداکثر دو شرکت‌کننده است و شناسهٔ عددی مسیر برگردانده نمی‌شود.

نمونه:

GET /api/__panel/learning-paths?title=طراحی&customer=09123456789&per_page=20&page=1
GET /api/__panel/learning-paths/{uuid}

دریافت مسیر آموزشی

uuid شناسهٔ UUID دورهٔ مسیر آموزشی است؛ شناسهٔ عددی پذیرفته نمی‌شود.

پاسخ شامل تصویر دوره در فیلد image، ساختار مسیر، تنظیمات، وضعیت شرکت‌کننده‌ها و استادیارهای متصل به هر شرکت‌کننده است. در پاسخ پنل id و course_id ارسال نمی‌شوند.

image در صورت نبود تصویر null است؛ در غیر این صورت شامل id، name، url، size و mime است.

POST /api/__panel/learning-paths

ساخت مسیر آموزشی

مسیر آموزشیِ اختصاصی را هم‌زمان با اتصال به مشتری ایجاد می‌کند.

در عملیات ساخت هنوز دوره‌ای وجود ندارد که UUID آن در URL ارسال شود؛ UUID دورهٔ ساخته‌شده در فیلد data.uuid پاسخ برمی‌گردد و تمام عملیات بعدی با همان UUID انجام می‌شوند.

نیازی به ارسال customer_id نیست؛ مشتری با mobile پیدا می‌شود و در صورت نبود ساخته می‌شود.

بدنهٔ درخواست:

{
    "idempotency_key": "8c754c19-7656-4ba6-a45d-f15b3609a7e6",
    "name": "نام شرکت‌کننده",
    "mobile": "09123456789",
    "code": "+98",
    "assistant_id": [12, 24],
    "image": "123/image/jpeg/hashed-file-name.jpg",
    "expire_date": "2026-12-30",
    "first_login_at": "2026-09-25",
    "installment_count": 3,
    "learning_path": {
        "title": "مسیر طراحی محصول",
        "description": "توضیحات مسیر آموزشی",
        "items": [
            {
                "type": "section",
                "title": "مبانی",
                "sort": 1,
                "lessons": [
                    {
                        "type": "lesson",
                        "title": "درس اول",
                        "sort": 1,
                        "course_id": 12,
                        "course_content_id": 145
                    }
                ]
            }
        ]
    },
    "drip": {
        "interval_days": 7,
        "lessons_per_release": 2
    },
    "settings": {
        "devices_limit": 3,
        "has_pwa": true,
        "downloadable": true
    }
}
  • idempotency_key، name، mobile، code و learning_path اجباری‌اند.
  • mobile شمارهٔ محلی بدون کد کشور است؛ صفر ابتدای شماره پذیرفته و پیش از اعتبارسنجی حذف می‌شود. code کد کشور، مانند +98 است.
  • assistant_id اختیاری و آرایهٔ شناسه‌های استادیار است؛ هر استادیار باید متعلق به همان owner و دارای نقش استادیار باشد، در غیر این صورت پاسخ 422 است.
  • image اختیاری است. ابتدا تصویر را با endpoint آپلود تک‌فایل بفرستید و سپس مقدار data.path پاسخ را بدون تغییر در این فیلد قرار دهید؛ URL یا خود فایل را ارسال نکنید.
  • هر section باید حداقل یک lesson داشته باشد؛ sort sectionها و lessonهای هر section مثبت و یکتا است. هر lesson باید course_id و course_content_id معتبر داشته باشد، محتوا به همان دوره تعلق داشته باشد و هر محتوا فقط یک‌بار در مسیر بیاید.
  • دوره‌های مبدأ باید متعلق به owner پنل باشند. expire_date و first_login_at اختیاری و با فرمت YYYY-MM-DD هستند.
  • installment_count حداقل ۲ و حداکثر تعداد lessonهای مسیر است. در صورت ارسال drip، هر دو فیلد آن اجباری و حداقل ۱ هستند؛ lessons_per_release نمی‌تواند از تعداد lessonها بیشتر باشد.
  • devices_limit بین ۰ تا ۱۰ است. کلیدهای مجاز settings عبارت‌اند از devices_limit، has_pwaو downloadable.

idempotency_key باید UUID معتبر باشد. برای retry همان درخواست، همان کلید را ارسال کنید؛ استفاده از همان کلید با payload متفاوت خطای 422 می‌دهد.

PUT /api/__panel/learning-paths/{uuid}

ویرایش مسیر آموزشی

uuid شناسهٔ UUID دورهٔ مسیر آموزشی است؛ شناسهٔ عددی پذیرفته نمی‌شود.

ارسال کامل learning_path اجباری است و ساختار موجود را جایگزین می‌کند. تنظیمات، drip، تاریخ انقضا، تاریخ شروع و تعداد اقساط اختیاری‌اند و در صورت ارسال هم‌زمان به‌روزرسانی می‌شوند.

{
    "learning_path": {
        "title": "عنوان جدید",
        "description": "توضیحات ویرایش‌شده مسیر آموزشی",
        "items": [
            {
                "type": "section",
                "title": "مبانی",
                "sort": 1,
                "lessons": [
                    {
                        "type": "lesson",
                        "title": "درس اول",
                        "sort": 1,
                        "course_id": 12,
                        "course_content_id": 145
                    }
                ]
            }
        ]
    },
    "expire_date": "2026-12-30",
    "first_login_at": "2026-09-25",
    "installment_count": 3,
    "assistant_id": [12, 24],
    "image": "123/image/png/replacement-cover.png",
    "drip": {
        "interval_days": 7,
        "lessons_per_release": 2
    },
    "settings": {
        "devices_limit": 3,
        "has_pwa": true,
        "downloadable": true
    }
}
  • هر section باید حداقل یک lesson داشته باشد؛ sort sectionها و lessonهای هر section مثبت و یکتا است.
  • هر lesson باید course_id و course_content_id معتبر داشته باشد، محتوا به همان دوره تعلق داشته باشد و هر محتوا فقط یک‌بار در مسیر بیاید. دوره‌های مبدأ نیز باید متعلق به owner پنل باشند.
  • expire_date و first_login_at اختیاری و با فرمت YYYY-MM-DD هستند. installment_count حداقل ۲ و حداکثر تعداد lessonهای مسیر است.
  • assistant_id اختیاری و آرایهٔ شناسه‌های استادیار متعلق به همان owner است. ارسال استادیارِ نامعتبر یا بدون نقش استادیار با خطای 422 رد می‌شود.
  • در ویرایش، ارسال‌نکردن image تصویر فعلی را حفظ می‌کند؛ برای جایگزینی ابتدا فایل جدید را با endpoint آپلود تک‌فایل بفرستید و data.path پاسخ را در image قرار دهید. ارسال null تصویر را حذف می‌کند.
  • در صورت ارسال drip، هر دو فیلد آن اجباری و حداقل ۱ هستند؛ lessons_per_release نمی‌تواند از تعداد lessonها بیشتر باشد.
  • devices_limit بین ۰ تا ۱۰ است. کلیدهای مجاز settings عبارت‌اند از devices_limit، has_pwa و downloadable.
DELETE /api/__panel/learning-paths/{uuid}/courses/{sourceCourseUuid}

حذف درس‌های یک دوره از مسیر آموزشی

تمام lessonهای دورهٔ مبدأ با UUID ارسالی را از مسیر حذف می‌کند. بخش‌های بدون درس نیز حذف می‌شوند.

پس از حذف، وضعیت انتشار شرکت‌کننده و شمارندهٔ محتوا و مدت مسیر دوباره محاسبه می‌شوند.

پارامترهای مسیر:

  • uuid: UUID مسیر آموزشی
  • sourceCourseUuid: UUID دورهٔ مبدأ

بدنهٔ درخواست ندارد و پاسخ موفق، مسیر آموزشی به‌روزشده است.

DELETE /api/__panel/learning-paths/{uuid}

حذف مسیر آموزشی

uuid شناسهٔ UUID دورهٔ مسیر آموزشی است؛ شناسهٔ عددی پذیرفته نمی‌شود.

مسیر آموزشی را حذف می‌کند. ثبت‌نام مشتری در مسیر، اقساط، ارتباط مشتری با استادیار و دورهٔ ثبت‌شده در فهرست دوره‌های استادیار نیز پاک‌سازی می‌شوند.

بدنهٔ درخواست ندارد و پاسخ موفق 200 با data: null است.

POST /api/__panel/learning-paths/with_template

اختصاص مسیر آموزشی به مشتری

با انتخاب یک الگو، یک مسیر مستقل برای مشتری ساخته می‌شود. الگو و مسیرهای ساخته‌شده از آن مستقل از یکدیگر هستند.

UUID دورهٔ مسیر ساخته‌شده در فیلد data.uuid پاسخ برمی‌گردد و تمام عملیات بعدی با همان UUID انجام می‌شوند.

ابتدا الگوها را از endpoint دریافت الگوها بگیرید و template_id متعلق به همان owner را انتخاب کنید. نیازی به ارسال customer_id نیست؛ مشتری با mobile پیدا می‌شود و در صورت نبود ساخته می‌شود.

بدنهٔ درخواست:

{
    "idempotency_key": "9e9a6cd7-5216-4958-b987-29821ae3ceca",
    "name": "نام شرکت‌کننده",
    "mobile": "09123456789",
    "code": "+98",
    "template_id": 42,
    "assistant_id": [12, 24],
    "expire_date": "2026-12-30",
    "first_login_at": "2026-09-25",
    "installment_count": 3,
    "drip": {
        "interval_days": 7,
        "lessons_per_release": 2
    },
    "settings": {
        "devices_limit": 3,
        "has_pwa": true,
        "downloadable": true
    }
}
  • idempotency_key، name، mobile، code و template_id اجباری‌اند.
  • mobile شمارهٔ محلی بدون کد کشور است؛ صفر ابتدای شماره پذیرفته و پیش از اعتبارسنجی حذف می‌شود. code کد کشور، مانند +98 است.
  • assistant_id اختیاری و آرایهٔ شناسه‌های استادیار متعلق به همان owner است. ارسال استادیارِ نامعتبر یا بدون نقش استادیار با خطای 422 رد می‌شود.
  • expire_date و first_login_at اختیاری و با فرمت YYYY-MM-DD هستند. installment_count اختیاری، حداقل ۲ و حداکثر تعداد درس‌های الگو است.
  • در صورت ارسال drip، هر دو فیلد آن اجباری و حداقل ۱ هستند؛ lessons_per_release نمی‌تواند از تعداد درس‌های الگو بیشتر باشد.
  • devices_limit بین ۰ تا ۱۰ است. سایر کلیدهای مجاز settings عبارت‌اند از devices_limit، has_pwa و downloadable.

idempotency_key باید UUID معتبر باشد. برای retry همان درخواست، همان کلید را ارسال کنید؛ استفاده از همان کلید با payload متفاوت خطای 422 می‌دهد.

GET /api/__panel/learning-path-templates

دریافت الگوهای مسیر آموزشی

فقط الگوهای متعلق به owner پنل را برمی‌گرداند. اگر الگویی وجود نداشته باشد، data یک آرایهٔ خالی است.

در ساخت یا ویرایش Template نیز تصویر مستقیماً داخل درخواست آپلود نمی‌شود: فایل را ابتدا با آپلودر تک‌فایل ارسال کنید و مقدار data.path پاسخ را در فیلد image بگذارید.

پاسخ موفق:

{
    "status": "success",
    "data": [
        {
            "id": 42,
            "image": {
                "id": 91,
                "name": "template-cover.jpg",
                "url": "https://...",
                "size": "120 KB",
                "mime": "image/jpeg"
            },
            "learning_path": {
                "title": "مسیر طراحی محصول",
                "description": "توضیحات الگوی مسیر آموزشی",
                "items": []
            }
        }
    ]
}
POST /api/__panel/courses/{uuid}/customers

افزودن مشتری به دوره

افزودن مشتری به دوره مورد نظر

پارامترها:

{
    "mobile": "09123456789",
    "name": "نام مشتری",
    "tag_ids": [1,2], // اختیاری
    "assistant_id": [1], // اختیاری
    "expire_date": "2024-12-31", // اختیاری
    "devices_limit_count": 2, // اختیاری
    "installment_count": 5 // اختیاری؛ null یعنی دسترسی عادی، حداقل 2 و حداکثر تعداد درس‌های دوره
}

در صورت ارسال installment_count، دوره براساس ترتیب فعلی درس‌ها به تعداد قسمت‌های اعلام‌شده تقسیم می‌شود. همه اقساط در ابتدا پرداخت‌نشده‌اند؛ در صورتی که قسط اول پرداخت نشده باشد عملا کاربر به هیچی درسی نسترسی نخواهد داشت.

پاسخ موفق:

{
    "status": true,
    "message": "",
    "data": {
        "id": 42311,
        "name": "نام مشتری",
        "mobile": "930...",
        "installment_count": 5
    }
}
PUT /api/__panel/courses/{course:uuid}/customers/{customer:id}

ویرایش مشتری

ویرایش مشتری مورد نظر

پارامترها:

{
    "tag_ids": [1,2], // اختیاری
    "assistant_id": [1], // اختیاری
    "tag_ids": [1,2], // اختیاری
    "expire_date": "2024-12-31", // اختیاری
    "first_login_at": "2024-12-31", // اختیاری
    "devices_limit_count": 2, // اختیاری
    "installment_count": 5 // اختیاری؛ در صورت عدم ارسال، مقدار فعلی حفظ می‌شود
}

فیلد installment_count فقط در صورت ارسال تغییر می‌کند. تا پیش از ثبت اولین پرداخت می‌توان تعداد اقساط را تغییر داد یا با ارسال null برنامه را غیرفعال کرد. پس از ثبت اولین پرداخت، تعداد اقساط قابل تغییر یا حذف نیست.

پاسخ موفق:

{
    "status": true,
    "message": "",
    "data": {
        "id": 42311,
        "name": "نام مشتری",
        "mobile": "930...",
        "installment_count": 5
    }
}
GET /api/__panel/tags

دریافت لیست برچسب‌ها

دریافت لیست برچسب‌های کاربر

پاسخ موفق:

{
    "status": "success",
    "data": [
        {
            "id": 1,
            "name": "برچسب 1"
        },
        {...}
    ]
}
GET /api/__panel/courses/{uuid}/customers

دریافت لیست مشتریان

دریافت لیست مشتریان دوره مورد نظر

پارامترهای کوئری:


search=نام مشتری | شماره موبایل    // optional
tag_ids[]=1                        // optional
tag_ids[]=2                        // optional
created_after=2025-01-01           // optional
created_before=2025-01-01          // optional
page=1
مثال:
?search=محمد&tag_ids[]=1&tag_ids[]=2&created_after=2025-01-01&created_before=2025-01-01&has_chat=1&page=1

پاسخ موفق:

{
    "data": [
        {
            "id": 42311,
            "name": "محمد ",
            "email": null,
            "code": "+98",
            "mobile": "930...",
            "devices_count": 0,
            "created_at": "2025-01-22T12:45:27.000000Z",
            "expired_at": null, // تاریخ انقضای دسترسی مشتری به دوره
            "last_login_at": "2025-03-08 12:06:20",
            "first_login_at": "2025-01-22 21:24:44",
            "drip_started_at": "2025-01-22", // تاریخ شروع انتشار قطره‌ای محتوا
            "drip_stoped_at": null, // تاریخ توقف انتشار قطره‌ای؛ null یعنی فعال است
            "installment_count": 5, // null یعنی دسترسی اقساطی فعال نیست
            "options": {
                "has_chat": 1,
                "has_download": 1,
                "devices_limit_count": 10
            },
            "seconds_of_view": 46110,
            "percent_of_view": 87.58,
            "contents_viewed_count": 103
        },
        {...}
    ],
    "meta": {
        "current_page": 2,
        "from": 101,
        "last_page": 9,
        "per_page": 100,
        "to": 200,
        "total": 880
    }
}
GET /api/__panel/courses/{uuid}/customers/{customer}

دریافت جزئیات مشتری

دریافت جزئیات مشتری در دوره مورد نظر

پاسخ موفق:

{
    "data": [
        {
            "id": 42311,
            "name": "محمد ",
            "email": null,
            "code": "+98",
            "mobile": "930...",
            "devices_count": 0,
            "created_at": "2025-01-22T12:45:27.000000Z",
            "expired_at": null, // تاریخ انقضای دسترسی مشتری به دوره
            "last_login_at": "2025-03-08 12:06:20",
            "first_login_at": "2025-01-22 21:24:44",
            "drip_started_at": "2025-01-22", // تاریخ شروع انتشار قطره‌ای محتوا
            "drip_stoped_at": "2025-03-01", // تاریخ توقف انتشار قطره‌ای؛ null یعنی فعال است
            "tags": [
                {
                    "id": 1,
                    "name": "برچسب 1"
                },
                {...}
            ],
            "assistants": [
                {
                    "id": 1,
                    "name": "استادیار 1"
                },
                {...}
            ],
            "options": {
                "has_chat": 1,
                "has_download": 1,
                "devices_limit_count": 10
            },
            "contents": [
                {
                    "id": 202,
                    "type": "video",
                    "title": "شروع دوره",
                    "duration_seconds": 71,
                    "seconds_of_view": 250,
                    "percent_of_view": 100
                },
                {
                    "id": 204,
                    "type": "video",
                    "title": "تمرین تکمیلی دوم",
                    "duration_seconds": 864,
                    "seconds_of_view": 940,
                    "percent_of_view": 100
                                },
                                {...}
                            ]
                        },
                        {...}
                    ]
                }
PUT /api/__panel/courses/{course:uuid}/customers/{customer:id}/installments/{installmentNumber}/payment

اعلام پرداخت قسط مشتری

پرداخت قسط مشخص‌شده را با زمان سرور و شناسه کاربر جاری ثبت می‌کند. پرداخت‌ها باید به ترتیب انجام شوند و ثبت دوباره یک قسط، مقدار اولیه paid_at را تغییر نمی‌دهد. پرداخت قسط شماره k قسمت k+1 را تا سقف تعداد قسمت‌ها باز می‌کند؛ پرداخت قسط آخر فقط وضعیت تسویه را کامل می‌کند.

پارامتر course UUID دوره و installmentNumber شماره قسط است. این درخواست بدنه ندارد. احراز هویت آن مانند سایر endpointهای /__panel از طریق Basic API Token انجام می‌شود.

پاسخ موفق:

{
    "status": true,
    "message": "",
    "data": {
        "number": 1,
        "paid_at": "2026-09-11T18:30:00.000000Z",
        "paid_by": 19
    }
}

خطای ترتیب پرداخت (422):

{
    "message": "The given data was invalid.",
    "errors": {
        "installment_number": [
            "ابتدا باید اقساط قبلی پرداخت شوند."
        ]
    }
}
POST /api/__panel/courses/{course:uuid}/customers/{customer:id}/drip_start

شروع مجدد انتشار قطره‌ای برای مشتری

انتشار تدریجی محتوا را برای مشتری از حالت توقف خارج می‌کند. تعداد روزهای توقف به drip_started_at اضافه و drip_stoped_at خالی می‌شود.

این درخواست بدنه یا پارامتر ورودی ندارد.

پاسخ موفق:

{
    "status": true,
    "message": "",
    "data": {
        "id": 42311,
        "name": "نام مشتری",
        "mobile": "930...",
        "drip_started_at": "2026-08-04",
        "drip_stoped_at": null
    }
}
POST /api/__panel/courses/{course:uuid}/customers/{customer:id}/drip_stop

توقف انتشار قطره‌ای برای مشتری

انتشار تدریجی محتوا را برای مشتری متوقف و تاریخ امروز را در drip_stoped_at ثبت می‌کند. اگر انتشار قطره‌ای قبلاً متوقف شده باشد، تاریخ توقف اولیه تغییر نمی‌کند.

این درخواست بدنه یا پارامتر ورودی ندارد.

پاسخ موفق:

{
    "status": true,
    "message": "",
    "data": {
        "id": 42311,
        "name": "نام مشتری",
        "mobile": "930...",
        "drip_started_at": "2026-08-01",
        "drip_stoped_at": "2026-08-23"
    }
}
POST /api/__panel/media/uploads/single

آپلود تک‌فایل

یک فایل را با Basic Authentication پنل و به‌صورت multipart/form-data در فضای موقت آپلود می‌کند.

نام فیلد فایل باید file باشد.

قاعدهٔ استفاده از فایل در API:

  1. فایل را ابتدا با همین endpoint و در فیلد file آپلود کنید.
  2. مقدار data.path را از پاسخ بردارید.
  3. در درخواست اصلی، خودِ مقدار data.path را در فیلد مربوط به فایل قرار دهید؛ برای نمونه، مقدار فیلد image باید همین path باشد، نه URL تصویر و نه خود فایل.

این قاعده برای تمام فایل‌های این API برقرار است؛ از جمله image مسیر آموزشی و image الگوی مسیر آموزشی (Template).

نمونه درخواست:

curl -X POST "https://panel-api.videm.ir/api/__panel/media/uploads/single" \
    -u "username:password" \
    -F "file=@cover.jpg"

پاسخ موفق:

{
    "status": true,
    "message": "فایل با موفقیت آپلود شد",
    "data": {
        "path": "123/image/jpeg/hashed-file-name.jpg"
    }
}

نمونهٔ استفاده از path در درخواست بعدی:

{
    "image": "123/image/jpeg/hashed-file-name.jpg"
}

همین ساختار برای ساخت یا ویرایش مسیر آموزشی و Template استفاده می‌شود.

در صورت ارسال‌نشدن فایل یا شکست آپلود پاسخ 400 و در صورت Basic Authentication نامعتبر پاسخ 401 برمی‌گردد.