Nنت‌استاکسDEVELOPER GUIDEبازگشت به پنل ←
API VERSION 1.0

راهنمای اتصال به پنل نمایندگی

ساخت نمایندگی، شارژ اعتبار و مدیریت سرویس‌ها از طریق API.

شروع اتصال

در پنل، از بخش «کلیدهای API» یک کلید بسازید و آن را در هدر زیر قرار دهید. کلید نمایندگی فقط به اطلاعات همان نماینده دسترسی دارد. ساخت نمایندگی و شارژ اعتبار، به کلید مدیر نیاز دارد.

Authorization: Bearer YOUR_API_KEY
Content-Type: application/json

همهٔ مسیرها نسبت به آدرس پنل هستند. در مثال‌ها، متغیرهای زیر را با آدرس و کلید خود تنظیم کنید:

export BASE_URL='https://panel.netstux.com'
read -rsp 'API key: ' API_KEY

کلید را فقط در برنامهٔ سمت سرور نگه دارید. آن را داخل کد عمومی سایت یا اپ قرار ندهید.

دریافت ساختار کامل OpenAPI ↗

آدرس‌های پنل و اشتراک

پنل و API اصلی روی https://panel.netstux.com و آدرس جایگزین روی https://panel-2.netstux.com قرار دارند. لینک اشتراک سرویس به شکل https://sub.ixp.plus/s/SUB_ID است. دامنهٔ داخل کانفیگ‌های Shadowsocks، sda-update.icloud.com.dl.choosename.org است.

مسیر عمومی GET /s/{sub_id} با شناسهٔ محرمانهٔ اشتراک، فهرست اتصال‌ها را به‌صورت Base64 استاندارد و همراه هدر subscription-userinfo برمی‌گرداند. این پاسخ از اطلاعات ذخیره‌شده تهیه می‌شود و به پنل اصلی درخواست تازه نمی‌فرستد. این شناسه را مانند رمز اتصال نگه دارید. مرورگر صفحهٔ HTML شامل حجم باقی‌مانده، مصرف، کانفیگ‌ها و QR را می‌بیند. برای خروجی مشخص از ?format=html، ?format=json یا ?format=base64 استفاده کنید.

سرویس منقضی، بدون حجم، غیرفعال یا در حال آماده‌سازی همچنان صفحهٔ وضعیت و JSON دارد؛ اتصال‌ها فقط برای سرویس قابل استفاده ارائه می‌شوند. لینک حذف‌شده، نمایندهٔ غیرفعال یا تعویض لینک در انتظار، پاسخ ۴۰۴ می‌گیرد. usage_known=false یعنی مصرف هنوز تأیید نشده است و به معنی مصرف صفر نیست.

مصرف با یک چرخهٔ مشترک هر ۱۸۰ ثانیه دریافت می‌شود. پنل و صفحهٔ اشتراک فقط آخرین اطلاعات ذخیره‌شده را می‌خوانند؛ تعداد بازدیدکنندگان، تعداد درخواست‌های مصرف به پنل اصلی را افزایش نمی‌دهد. زمان sync_at آخرین بررسی همان سرویس را نشان می‌دهد.

قواعد حجم و اعتبار

جلوگیری از درخواست تکراری

برای ساخت سرویس، شارژ اعتبار، افزایش حجم و تعویض لینک‌ها، هدر Idempotency-Key اجباری است. برای هر عملیات جدید یک مقدار یکتا بسازید؛ هنگام تکرار همان عملیات بعد از قطع ارتباط، همان مقدار و بدنهٔ قبلی را بفرستید. یک کلید با بدنهٔ متفاوت خطای ۴۰۹ می‌دهد.

۱. ساخت پنل نمایندگی

فقط مدیر · ایجاد حساب با یک ترابایت اعتبار اولیه

POST/api/resellers
curl "$BASE_URL/api/resellers" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"username":"partner_01","name":"نماینده اول",
       "password":"REPLACE_WITH_STRONG_PASSWORD","quota_gb":1024}'

شناسهٔ id در پاسخ را برای مدیریت حساب و شارژهای بعدی نگه دارید. نام کاربری ۳ تا ۴۸ کاراکتر و رمز عبور حداقل ۱۲ کاراکتر است.

۲. شارژ حساب نماینده

فقط مدیر · مقدار زیر به اعتبار قبلی اضافه می‌شود.

POST/api/resellers/2/credit
curl "$BASE_URL/api/resellers/2/credit" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: credit-partner-2-order-1001' \
  -d '{"amount_gb":1024,"note":"شارژ ماهانه"}'

۳. ساخت سرویس

POST/api/users
curl "$BASE_URL/api/users" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: service-order-1002' \
  -d '{"name":"سرویس علی","volume_gb":20,"duration_months":3}'

این مثال با کلید نماینده اجرا می‌شود. مدیر باید فیلد عددی reseller_id را هم به بدنه اضافه کند.

{
  "id": "USER_ID",
  "name": "سرویس علی",
  "reseller_id": 2,
  "volume_gb": 20,
  "duration_months": 3,
  "status": "active",
  "used_bytes": 0,
  "usage_known": true,
  "billing_status": "reserved",
  "billed_bytes": 0,
  "refund_bytes": 0,
  "attach_pending": true,
  "subscription_url": "https://sub.ixp.plus/s/SUB_ID"
}

پاسخ واقعی شامل نام نماینده، زمان ساخت، زمان انقضا، لینک‌های اتصال در direct_links، پیشرفت لوکیشن‌ها در attached_count / attach_total و error_code نیز هست. پاسخ ۲۰۱ یعنی ثبت جدید و پاسخ ۲۰۲ یعنی بررسی نتیجه ادامه دارد. مقدار attach_pending نشان می‌دهد مسیرهای دیگر هنوز در حال اتصال هستند.

۴. مشاهده و همگام‌سازی کاربران

# List users belonging to the current account
curl "$BASE_URL/api/users" -H "Authorization: Bearer $API_KEY"

# Read one user
curl "$BASE_URL/api/users/USER_ID" -H "Authorization: Bearer $API_KEY"

# Read the latest cached state from the shared usage cycle
curl -X POST "$BASE_URL/api/users/USER_ID/sync" \
  -H "Authorization: Bearer $API_KEY"

# Delete a service (unused capacity is refunded after final usage settlement)
curl -X DELETE "$BASE_URL/api/users/USER_ID" \
  -H "Authorization: Bearer $API_KEY"

فهرست سرویس‌ها در فیلد items برمی‌گردد. صفحه‌بندی با limit (پیش‌فرض ۱۰۰، حداکثر ۵۰۰) و offset انجام می‌شود. پاسخ شامل total و next_offset نیز هست؛ این قرارداد برای گردش اعتبار هم برقرار است. برای جست‌وجو از ?q=NAME استفاده کنید. مدیر با ?reseller_id=2 سرویس‌های یک نماینده را می‌بیند. مشاهدهٔ سرویس و مسیر /sync هر دو مصرف ذخیره‌شده را برمی‌گردانند و درخواست فوری جداگانه‌ای به پنل اصلی نمی‌فرستند.

۵. افزایش حجم و تعویض لینک‌ها

همهٔ این عملیات به کلید یکتای درخواست نیاز دارند. اگر پاسخ نامشخص شد، همان بدنه و همان کلید را تکرار کنید.

# Add traffic; final volume must remain at or below 50 GB
curl -X POST "$BASE_URL/api/users/USER_ID/traffic" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: traffic-order-1003' \
  -d '{"extra_gb":5}'

# Rotate subscription URL only
curl -X POST "$BASE_URL/api/users/USER_ID/rotate-subscription" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: rotate-sub-1004' -d '{}'

# Rotate user connection credential across all attached locations
curl -X POST "$BASE_URL/api/users/USER_ID/rotate-connection" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: rotate-connection-1005' -d '{}'

افزایش حجم از اعتبار نماینده کم می‌شود و مصرف یا زمان انقضا را صفر نمی‌کند. تعویض لینک اشتراک، لینک اشتراک قبلی را باطل می‌کند؛ تعویض لینک اتصال، اطلاعات اتصال قبلی را عوض می‌کند. در هر دو حالت، حجم، مصرف، انقضا و لوکیشن‌ها حفظ می‌شوند.

پاسخ، همان ساختار سرویس را دارد. تا وقتی mutation_status برابر pending است، تغییر در حال بررسی است؛ وضعیت active سرویس به‌تنهایی به معنی پایان تغییر نیست. تغییر دیگری تا تعیین نتیجه پذیرفته نمی‌شود.

انتخاب و ویرایش نام نمایشی

نام مشتری در پنل نماینده، اشتراک و عنوان کانفیگ‌ها نمایش داده می‌شود. ویرایش نام نمایشی مصرف، انقضا و اطلاعات اتصال را تغییر نمی‌دهد.

curl -X PATCH "$BASE_URL/api/users/USER_ID" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"name":"سرویس علی رضایی"}'

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

فقط مدیر می‌تواند لوکیشن‌های نمایندگی را تغییر دهد. حساب مقصد را با ?reseller_id=7 مشخص کنید؛ انتخاب هر نمایندگی مستقل است. فهرست از دادهٔ ذخیره‌شده خوانده می‌شود؛ درخواست refresh با پاسخ ۲۰۲ دریافت تازه را در صف قرار می‌دهد. فهرست به‌طور دوره‌ای هر ۳۰ دقیقه نیز بررسی می‌شود.

curl "$BASE_URL/api/settings/inbounds?reseller_id=7" \
  -H "Authorization: Bearer $API_KEY"

curl -X POST "$BASE_URL/api/settings/inbounds/refresh" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' -d '{}'

curl -X PATCH "$BASE_URL/api/settings/inbounds?reseller_id=7" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"inbound_ids":[22,23],"primary_id":22}'

پاسخ شامل items با فیلدهای id، remark، protocol، port، enabled و selected، به‌علاوهٔ selected_ids، primary_id و refresh_pending است. reseller_id محدوده و uses_default استفاده از پیش‌فرض سیستم را نشان می‌دهد. updated_at زمان تغییر انتخاب، catalog_updated_at زمان دریافت فهرست و usage_synced_at زمان چرخهٔ مصرف را نشان می‌دهد.

انتخاب باید شامل ۱ تا ۶۴ شناسهٔ صحیح و یکتا از اینباندهای فعال باشد؛ مسیر اصلی باید عضو همین انتخاب و همهٔ اینباندها هم‌پروتکل باشند. Shadowsocks، VLESS، VMess و Trojan پشتیبانی می‌شوند. ارسال دوبارهٔ انتخاب یکسان تغییری در اعتبار یا صف ایجاد نمی‌کند و به Idempotency-Key نیاز ندارد.

تا وقتی در این محدوده سرویس موجود است، خانوادهٔ پروتکل قبلی باید حفظ شود؛ تبدیل آن به پروتکل دیگر با inbound_protocol_change_requires_empty_panel رد می‌شود.

این انتخاب فقط روی سرویس‌های موجود و ساخت‌های آیندهٔ همان نمایندگی اعمال می‌شود. انتخاب نمایندگی‌های دیگر حفظ می‌شود. ابتدا مسیرهای جدید متصل و بررسی می‌شوند و سپس اتصال همان سرویس‌ها از مسیرهای حذف‌شده برداشته می‌شود. خود اینباند پنل اصلی حذف نمی‌شود؛ مصرف، اعتبار و انقضا حفظ می‌شوند. پیشرفت از attach_pending و attached_count / attach_total قابل مشاهده است.

بدون reseller_id، این مسیر تنظیم پیش‌فرض سیستم را مدیریت می‌کند و تغییر آن فقط به حساب‌های بدون انتخاب مستقل می‌رسد. اولین ذخیرهٔ محدوده‌دار، انتخاب مستقل نمایندگی را ثبت می‌کند؛ حتی اگر با پیش‌فرض یکسان باشد. refresh فقط فهرست مشترک را تازه می‌کند.

قالب نام اتصال‌های هر نمایندگی

نماینده نام اتصال‌های مشتری‌های خودش را تنظیم می‌کند. مدیر باید ?reseller_id=7 را به این دو مسیر اضافه کند. این نام‌ها در عنوان لینک‌ها، صفحهٔ اشتراک و QR اعمال می‌شوند.

curl "$BASE_URL/api/location-labels" \
  -H "Authorization: Bearer $API_KEY"

curl -X PATCH "$BASE_URL/api/location-labels" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"labels":[{"inbound_id":22,"template":"⚡️ سریع - {name}"},
                 {"inbound_id":23,"template":""}]}'

پاسخ items دارد؛ هر مورد شامل inbound_id، remark، template، default_template و effective_template است. فقط لوکیشن‌های انتخاب‌شدهٔ مدیر پذیرفته می‌شوند.

PATCH مجموعهٔ کامل قالب‌ها را جایگزین می‌کند. موارد ارسال‌نشده و قالب خالی به پیش‌فرض برمی‌گردند؛ {"labels":[]} همهٔ قالب‌های سفارشی را پاک می‌کند. حداکثر ۶۴ مورد با شناسهٔ یکتا پذیرفته می‌شود.

هر قالب حداکثر ۱۲۰ کاراکتر دارد. فقط عبارت دقیق {name} با نام مشتری جایگزین می‌شود و نام ثابت نیز مجاز است. خط جدید، کاراکتر کنترلی و آکولاد دیگر پذیرفته نمی‌شود. برای مشتری «علی»، قالب ⚡️ سریع - {name} به «⚡️ سریع - علی» تبدیل می‌شود. این تغییر محلی است و مصرف یا مشخصات اتصال را عوض نمی‌کند.

فهرست مسیرها

روش مسیر کاربرد
GET /api/me حساب و اعتبار فعلی
GET /api/dashboard آمار و سرویس‌های اخیر
GET / POST /api/resellers فهرست / ایجاد نمایندگی؛ مدیر
PATCH /api/resellers/{id} ویرایش نام، رمز یا active؛ مدیر
POST /api/resellers/{id}/credit افزودن اعتبار؛ مدیر
GET / PATCH /api/settings/inbounds مشاهده / انتخاب لوکیشن‌های نمایندگی با reseller_id؛ مدیر
POST /api/settings/inbounds/refresh درخواست فهرست تازه در پس‌زمینه؛ مدیر
GET / PATCH /api/location-labels مشاهده / جایگزینی قالب‌های نام نمایندگی
GET /api/ledger گردش اعتبار
GET / POST /api/users فهرست / ساخت سرویس
GET / PATCH / DELETE /api/users/{id} جزئیات / ویرایش نام / حذف و تسویهٔ سرویس
POST /api/users/{id}/sync آخرین وضعیت ذخیره‌شدهٔ سرویس
POST /api/users/{id}/traffic افزایش حجم از اعتبار نماینده
POST /api/users/{id}/rotate-subscription تعویض لینک اشتراک
POST /api/users/{id}/rotate-connection تعویض لینک اتصال
GET / POST /api/keys فهرست / ساخت کلید با بدنهٔ name
DELETE /api/keys/{id} لغو کلید متعلق به حساب
GET /api/health سلامت برنامه
GET /api/upstream/health سلامت اتصال به پنل اصلی؛ مدیر

خطاها و ورود مرورگر

خطای API به شکل {"detail":"insufficient_quota"} برمی‌گردد؛ خطاهای اعتبارسنجی ۴۲۲ شامل آرایهٔ جزئیات هستند.

ورود مرورگر با POST /api/auth/login و بدنهٔ {"username":"...","password":"..."} انجام می‌شود. پاسخ، کوکی نشست و csrf_token می‌دهد. برای درخواست‌های تغییردهنده با کوکی، هدر X-CSRF-Token الزامی است. خروج: POST /api/auth/logout. احراز هویت با Bearer به CSRF نیاز ندارد.