API توکن

دستگاه را بفرستید، همان لحظه request_id بگیرید، و با آن تا توکن آنلاک دنبالش کنید.

فارسی
شروع کار

01چطور کار می‌کند

شما گوشی را با ابزار خودتان می‌خوانید و آنچه خواندید را می‌فرستید. همان لحظه یک request_id می‌گیرید. آن را به status.php برمی‌گردانید و همین، کار را روی سروری که انتخاب کرده‌اید شروع می‌کند؛ همان فراخوانی بعد از آن می‌گوید کار در چه حالی است و توکن آنلاک را برای نوشتن روی گوشی به شما می‌دهد. ما هرگز به گوشی دست نمی‌زنیم و شما هرگز با سرور سروکار ندارید.

1ارسال

token.php همه چیز را بررسی می‌کند و همان لحظه با یک request_id مثل WT-API-6AF684545B پاسخ می‌دهد. هنوز چیزی به هیچ سروری فرستاده نشده و چیزی کسر نشده است.

2تأیید در ۳۰ ثانیه

request_id را به status.php بفرستید. همین اولین فراخوانی رسید شماست: کار فقط از این لحظه شروع می‌شود. request_idای که در ۳۰ ثانیه تأیید نشود لغو می‌شود.

3گرفتن توکن

هر چند ثانیه دوباره از status.php بپرسید تا state یا done شود — همراه توکن — یا error، همراه دلیل و برگشت کردیت شما.

نقاط دسترسی

POST token.phpارسال درخواست توکن: request_id همان لحظه برمی‌گردد.
POST status.phpتأیید request_id (که کار را شروع می‌کند) و دنبال کردن آن تا توکن.
POST history.phpکارهای شما، بر اساس تاریخ و سرویس، و اینکه هر کدام چطور تمام شد.
POST balance.phpکردیت شما و اینکه کجا خرج شده.
POST servers.phpسرورهایی که می‌توانید استفاده کنید و قیمت شما روی هر کدام.

https://xiaomi.source.af/api/reseller/v1/…

02اعتبارنامه‌ها

چهار چیز شما را می‌شناساند و هر چهار باید یک حساب را نام ببرند. توکن در هدر می‌رود؛ سه تای دیگر در بدنه. اشتباه بودن هرکدام همان unauthorized را می‌دهد — هرگز نمی‌گوییم کدام، چون این به مهاجم می‌گوید کدام را نگه دارد.

فیلدچیست
Authorizationتوکن حساب — فقط مال شما. آن را در پنل خود در بخش «اعتبارنامه‌های شما» بسازید، یا از ما بخواهید. ما فقط هش آن را نگه می‌داریم، پس یک بار نمایش داده می‌شود و قابل بازیابی نیست — ساختن یک توکن تازه، توکن قبلی را همان لحظه از کار می‌اندازد.
api_keyکلید API — در بدنه، روی هر درخواست.
emailایمیل — آدرس روی حساب شما. اگر عوض شد به ما بگویید، وگرنه فراخوانی‌ها متوقف می‌شوند.
passwordرمز API — رمز API حساب شما. به‌طور پیش‌فرض همان رمز ورود شماست. اگر رمز جداگانه‌ای می‌خواهید، در پنل‌تان از حساب کاربری ← رمز API تنظیمش کنید؛ با دکمهٔ استفاده از رمز ورود من به حالت قبل برمی‌گردید و رمز جداگانه همان لحظه از کار می‌افتد. ما هم می‌توانیم آن را برایتان تنظیم کنیم. در هر حال، هرگز در لاگ‌های ما نوشته نمی‌شود و هرگز همراه کار ذخیره نمی‌شود.

هر اندپوینت POST روی HTTPS است. GET با method_not_allowed رد می‌شود؛ بدنه‌ای که JSON نباشد با bad_json.

بخش ۱ · ارسال درخواست توکن

03درخواست

POSThttps://xiaomi.source.af/api/reseller/v1/token.php
درخواست کامل
POST /api/reseller/v1/token.php HTTP/1.1
Host: xiaomi.source.af
Content-Type: application/json; charset=utf-8
Accept: application/json
Authorization: Bearer rst_YOUR_ACCOUNT_TOKEN

{
  "api_key":      "YOUR_API_KEY",
  "email":        "you@example.com",
  "password":     "YOUR_PASSWORD",
  "soc":          "frp",
  "serverid":     "server1",
  "configblob":   "eyJ0b2tlbiI6IjhmMjFjMGI0ZTlkNyIsImRldmljZU5hbWUiOiJm…",
  "request_date":     "2026-09-21T14:51:51.980Z",
  "request_language": "English"
}

هر فیلد زیر در بدنهٔ JSON می‌رود.

فیلدنوعالزامیچیست
api_keystringبلهکلید API شما.
emailstringبلهایمیل روی حساب شما.
passwordstringبلهرمز API شما — به‌طور پیش‌فرض همان رمز ورود شما، مگر اینکه در پنل‌تان از حساب کاربری ← رمز API رمز جداگانه‌ای گذاشته باشید. به اعتبارنامه‌ها نگاه کنید.
socstringبلهکدام سرویس. frp یعنی حذف FRP، fdl یعنی Fastboot به EDL. پیش‌فرض ندارد — نفرستادنش خطاست، نه حدسی که می‌تواند بابت سرویس اشتباه از شما پول بگیرد.
configblobstringبلهخوانش کامل گوشی، به‌صورت base64 یک آبجکت JSON. اینکه چه چیزهایی باید در آن باشد به soc بستگی دارد — به بلاب دستگاه نگاه کنید.
serveridstringخیرشناسهٔ عمومی سروری که باید کار را انجام دهد، مثلاً server1 — از servers.php، یا از بخش سرورها در پنل‌تان. سخت‌گیرانه است: یا همان سرور کار را انجام می‌دهد، یا درخواست با ذکر دلیل رد می‌شود. اگر نفرستید، ارزان‌ترین سروری را که کار می‌گیرد انتخاب می‌کنیم. صاحبان ابزار: همیشه آن را بفرستید. به انتخاب سرور نگاه کنید.
request_datestringخیراختیاری. اینکه سرور شما چه زمانی این درخواست را فرستاده، ISO-8601 با Z یا آفست. دست‌نخورده در client_sent برگردانده می‌شود و هرگز در محاسبات ما به کار نمی‌رود. اگر نفرستید چیزی عوض نمی‌شود، جز اینکه client_sent و client_clock_offset_seconds با مقدار null برمی‌گردند.
request_languagestringخیراختیاری. زبانِ message‌ای که در ردِ درخواست به مشتری نشان داده می‌شود: یکی از English، Persian، Spanish، French، Turkish، Arabic (یا کد دوحرفی مثل en/fa). اگر نفرستید یا ناشناخته باشد، پاسخ به انگلیسی می‌آید. در هر درخواست بفرستید (token.php، status.php و خواندن‌ها). فیلدهای ساختارمند (مثل flash_status، region، takes_on) در هر صورت برمی‌گردند، پس می‌توانید جملهٔ خودتان را به هر زبانی هم بسازید.

04بلاب دستگاه

بلاب، base64 یک آبجکت JSON است که خوانش کامل گوشی را در خود دارد — هر چیزی که ابزار شما در آن حالت می‌خواند، نه فقط توکن. اینکه چه چیزی الزامی است به soc بستگی دارد: برای frp گوشی در حالت Mi Assistant (سایدلود / ریکاوری) است و برای fdl در حالت Fastboot. هر مقدار را دقیقاً همان‌طور بفرستید که گوشی جواب داد — نه کوتاه‌شده، نه با قالبی دیگر.

frp — گوشی در حالت Mi Assistant (سایدلود / ریکاوری)

فیلدخواندن باالزامیچیستنمونه
tokengetmitoken:بله — null رد می‌شودچالش FRP، دقیقاً همان‌طور که خوانده شد8f21c0b4e9d7…
deviceNamegetdevice:بله — null رد می‌شودکدنام همراه با پسوند منطقهfleur_global
versiongetversion:بله — null رد می‌شودبیلد رامOS2.0.207.0.VMTMIXM
serialgetsn:بله — null رد می‌شودشمارهٔ سریالfb4d921c
codebasegetcodebase:بله — اگر خوانده نشد nullنسخهٔ اندروید15
regiongetregion:بله — اگر خوانده نشد nullمنطقهٔ رامIR
cpuidgetcpuid:بله — اگر خوانده نشد nullشناسهٔ CPU، اگر گوشی جواب دهد0x000460E1
recoverygetrecoveryversion:بله — اگر خوانده نشد nullنسخهٔ ریکاوری — فقط فهرست دستگاه‌های پشتیبانی‌نشدهٔ ما آن را می‌خواند2
branchgetbranch:خیر — null مشکلی نداردشاخهٔ رامF
languagegetlanguage:خیر — null مشکلی نداردزبان دستگاه — فقط فهرست دستگاه‌های پشتیبانی‌نشدهٔ ما آن را می‌خواندfa
romzonegetromzone:خیر — null مشکلی نداردROM Zone — فقط فهرست دستگاه‌های پشتیبانی‌نشدهٔ ما آن را می‌خواند2
frp · قبل از base64
{
  "token":      "8f21c0b4e9d7…",
  "deviceName": "fleur_global",
  "version":    "OS2.0.207.0.VMTMIXM",
  "serial":     "fb4d921c",
  "codebase":   "15",
  "region":     "IR",
  "cpuid":      "0x000460E1",
  "recovery":   "2",
  "branch":     "F",
  "language":   "fa"
}

برای frp، productName را نفرستید. نادیده گرفته می‌شود: محصول را خودمان از deviceName درمی‌آوریم (fleur_global ← fleur)، درست همان‌طور که ابزار خودمان این کار را می‌کند. بیلد رام در version می‌رود. نسخهٔ قبلی همین صفحه گفته بود بیلد رام را در productName بگذارید — اگر کلاینت شما چنین می‌کند، آن را به version منتقل کنید.

fdl — گوشی در حالت Fastboot

فیلدخواندن باالزامیچیستنمونه
tokenoem get_token
(getvar:token)
بله — null رد می‌شودتوکن فست‌بوت، دقیقاً همان‌طور که خوانده شدVQHzN2Ib…
productgetvar:productبله — null رد می‌شودکدنام، بدون منطقهfleur
serialgetvar:serialnoبله — null رد می‌شودشمارهٔ سریالfb4d921c
cpuidgetvar:cpuidبله — اگر خوانده نشد nullشناسهٔ CPU، اگر گوشی جواب دهد0x000460E1
fdl · قبل از base64
{
  "token":   "VQHzN2Ib…",
  "product": "fleur",
  "serial":  "fb4d921c",
  "cpuid":   "0x000460E1"
}

هر فیلدی را وقتی گوشی نتوانست بخواندش می‌توان null فرستاد (null در JSON یا متن "null") — هرگز unknown، N/A یا متن خالی نفرستید. بعدش بستگی به فیلد دارد: فیلدی که بله — null رد می‌شود دارد، سرورها کار را با آن می‌سازند؛ پس درخواست با incomplete_configblob رد می‌شود، نام فیلد در nulls می‌آید و چیزی کسر نمی‌شود — گوشی را دوباره بخوانید و اطلاعات کامل را بفرستید؛ فیلدی که بله — اگر خوانده نشد null دارد باید همیشه در بلاب باشد و با null کار مثل همیشه انجام می‌شود (اگر اصلاً نفرستید رد می‌شود)؛ فیلدی که خیر — null مشکلی ندارد دارد را null بفرستید یا نفرستید — کار انجام می‌شود. کاری که با فیلدهای null فرستاده شود با همان چیزی که فرستاده‌اید انجام می‌شود: اگر توکنش بعداً به خاطر فیلدی که خوانده نشده روی گوشی کار نکند، قابل برگشت (refund) نیست. هر فیلدی را که گوشی جواب داد بفرستید.

بعضی سرورها برای بررسی ریجن دستگاه به cpuid نیاز دارند. هر وقت گوشی آن را داد، حتماً بفرستید (در حالت Mi Assistant سریال 0x… همان CPU ID است). اگر نفرستید، null در نظر گرفته می‌شود و کار ادامه پیدا می‌کند.

frp · region null
{
  "token":      ",VQEBHQEQNzczMmNmNjE0MzcxMTgwZAIE1UIc…",
  "deviceName": "fog",
  "version":    "V13.0.8.0.SGEMIXM",
  "serial":     "0xd5421c9d",
  "codebase":   "12",
  "region":     null,
  "cpuid":      "0xd5421c9d",
  "recovery":   "2",
  "branch":     "F",
  "language":   "fa-IR"
}

نام‌های دیگری که برای همین فیلدها می‌پذیریم: authKey یا auth_key به‌جای token؛ devicename یا device_name به‌جای deviceName؛ osVersion یا os_version به‌جای version؛ serial_number یا serialNumber به‌جای serial (برای fdl همچنین serialno)؛ productName یا productname به‌جای product؛ cpu_id به‌جای cpuid.

پیش از هر کسری بررسی می‌شود

همه‌چیز پیش از رزرو یا کسر هر مبلغی بررسی می‌شود. فیلد الزامی (بله — null رد می‌شود) که فرستاده نشود در missing می‌آید؛ اگر null فرستاده شود در nulls؛ و اگر خوانشی ناموفق داشته باشد — N/A، unknown، none یا متن یک خطا — در invalid. هر کدام با HTTP ۴۰۰ و کد incomplete_configblob رد می‌شود، همراه با حالتی که گوشی باید در آن باشد در mode: Mi Assistant یا Fastboot. فیلدهای اختیاری را هر وقت گوشی جواب داد بفرستید؛ اگر نبود، null بود یا خوانشی ناموفق داشت، فقط کنار گذاشته می‌شود و به جایی نمی‌رود — جلوی کار را نمی‌گیرد. بلابی که توکنش نباشد یا null باشد پاسخ missing_token می‌گیرد.

incomplete_configblob
HTTP/1.1 400 Bad Request

{
  "status":  400,
  "error":   "incomplete_configblob",
  "message": "The field deviceName (null) is required and must be sent filled in — the server needs it to run this job. Read the device again and send the complete information. Nothing was charged. (configblob is not complete for frp (device in Mi Assistant mode) -- null: deviceName; missing: region. A field the phone does not report is sent as null, e.g. \"region\": null.)",
  "missing": ["region"],
  "invalid": [],
  "nulls":   ["deviceName"],
  "mode":    "Mi Assistant",
  "data":    { "state":"error", "start_date":{ … }, "end_date":{ … }, "response_date":{ … } }
}

# No request_id was given: nothing was created, held or charged.

قالب مخصوص هر سرور را خودمان از همین فیلدها می‌سازیم؛ پس شما هرگز شکلی را که مال یک سرور خاص است نمی‌فرستید — و با عوض شدن serverid هیچ چیزی در آنچه می‌فرستید عوض نمی‌شود.

چه می‌فرستید و چه می‌گیرید:

شما می‌فرستیدما برمی‌گردانیممعنی
deviceNamedevice_nameکدنام همراه با پسوند منطقه (frp)
—product_modelکدنام، بدون منطقه — خودمان آن را از deviceName درمی‌آوریم (frp)
productproduct_model
device_name
کدنام، بدون منطقه (fdl)
versiondevice_versionبیلد رام (frp)
serialserial_numberشمارهٔ سریال
codebasecodebaseنسخهٔ اندروید (frp)
branchbranchشاخهٔ رام (frp)
regionregionمنطقهٔ رام (frp)
cpuidcpu_idشناسهٔ CPU، اگر گوشی جواب دهد
token—در device تکرار نمی‌شود

فیلدی که به آن سرویس مربوط نیست، به‌جای اینکه حذف شود با null برمی‌گردد؛ پس یک پارسر هر دو سرویس را می‌خواند.

05دستگاه‌های پشتیبانی‌شده

بعضی از بیلد نامبرها پشتیبانی نمی‌شوند و ممکن است بعضی از کشورها هم پشتیبانی نشوند. برای اینکه بدانید کدام‌ها، بعد از گرفتن API صاحب ابزار، از ادمین در تلگرام یا واتساپ بپرسید.

دستگاهی که در فهرست دستگاه‌های پشتیبانی‌نشدهٔ خود ما باشد، همان لحظه با unsupported (422) از token.php رد می‌شود: نه request_idای، نه ارسالی به هیچ سروری و نه هیچ کسری. این فهرست می‌تواند هر فیلد configblob را بسنجد — مدل، فریمور، نسخهٔ اندروید، شاخه، زبان، منطقه، نسخهٔ ریکاوری، ROM Zone، سریال و CPU id — پس هر چه ابزارتان خواند بفرستید.

دقت کنید: ارسال مدلی که پشتیبانی نمی‌شود کردیت شما را از بین می‌برد — بازگردانده نمی‌شود — و گاهی باعث بسته شدن حساب‌تان می‌شود.

همان دستگاه پشتیبانی‌نشده بارها و بارها: هر بار که دستگاهی به‌عنوان پشتیبانی‌نشده رد شود (unsupported) برای حساب شما و همان دستگاه در ۵ دقیقه شمرده می‌شود. ردِ چهارم در message خود هشدار دارد و strike.warning برابر true است (strike = {count, max, window_seconds, warning} در هر ردی از این نوع هست): ارسال دوبارهٔ این دستگاه حساب شما را مسدود می‌کند. یک رد دیگرِ همین دستگاه در همان ۵ دقیقه حساب شما را ۵ دقیقه محدود می‌کند: هر درخواست تازه با account_restricted (403) جواب می‌گیرد. با دیدن هشدار متوقف شوید و سروری را که دستگاه را می‌پذیرد به مشتری پیشنهاد دهید.

وقتی دستگاهی به خاطر ریجنش رد شود و یکی از سرورهای شما برای آن ریجن پریمیوم باشد، ردِ unsupported فیلدهای region، suggested، premium (مثل check.php) و takes_on را دارد و message آن سرور را نام می‌برد: «ریجن دستگاه شما CN است. این دستگاه باید با Server 6.3 انجام شود — این سرور پریمیوم است و درصد موفقیت حذف FRP این دستگاه با آن بسیار بالاست.» چیزی کسر نشد.

وقتی سرورهای پریمیوم آن ریجن همه خاموش باشند یا اسلات آزاد نداشته باشند، چیزی پیشنهاد نمی‌شود (suggested برابر null)، slots_full برابر true است و message همین را می‌گوید: «★ Server 6.3 ریجن AE دستگاه شما را پشتیبانی می‌کند، اما اسلات‌های آن موقتاً پر شده است. لطفاً کمی بعد دوباره سر بزنید، یا تازه‌ترین وضعیت سرورها و باز شدن اسلات‌ها را در کانال تلگرام ما … دنبال کنید.» آن را نشان دهید و بگذارید مشتری بعداً دوباره امتحان کند، به‌جای اینکه دستگاه را به سروری بفرستید که ریجنش را نمی‌پذیرد. سرور پریمیوم همیشه با ستاره‌اش (★) نام برده می‌شود.

وقتی سروری که انتخاب کرده‌اید خودش دستگاهی را رد کند، پاسخ unsupported از status.php فیلد server_message را دارد: جملهٔ خودِ سرور، بدون نام هیچ تأمین‌کننده‌ای، مثلاً «This device is not supported (China Device Not Supported) · CPUID: 0xe4f01f4c · Product: star · IMEI: 867869053687315»؛ message هم با همین تمام می‌شود. data.amount_charged می‌گوید کار شارژ شد یا نه: سروری که دستگاهی را پیش از اجرای کار رد کند چیزی کسر نمی‌کند، و ما هم کسر نمی‌کنیم.

از ادمین بپرسید: Telegram: @RaminGSM WhatsApp: +93799691689

06انتخاب سرور

هر سرور یک شناسهٔ عمومی دارد که ما به آن داده‌ایم — server1، server2… — و یک نام، مثل Server 1. هر دو را servers.php با نام‌های serverid و name فهرست می‌کند، و در پنل شما هم زیر بخش سرورها هستند. برای اجرای کار روی یکی از آن‌ها، شناسه‌اش را در serverid بفرستید.

دو حالت
# 1. name the server -- exactly this one, or an error saying why not
{ "soc":"frp", "configblob":"…", "serverid":"server1" }

# 2. leave it out -- we take the cheapest server taking jobs
{ "soc":"frp", "configblob":"…" }

# every answer names the server that runs the job
-> { "data": { "request_id":"WT-API-6AF684545B", "serverid":"server1", "server_name":"Server 1", … } }

اگر serverid را نفرستید، ما برایتان انتخاب می‌کنیم: ارزان‌ترین سروری که کار می‌گیرد و حساب شما اجازهٔ استفاده از آن را دارد. اگر یکی را نام ببرید، سخت‌گیرانه است: یا همان سرور کار را انجام می‌دهد، یا درخواست رد می‌شود — unknown_serverid (۴۰۴) وقتی هیچ سروری این شناسه را ندارد، server_not_allowed (۴۰۳) وقتی برای حساب شما فعال نیست، و server_offline (۵۰۳) وقتی همین حالا نمی‌تواند این سرویس را بگیرد. هرگز بی‌خبر از شما سرور را عوض نمی‌کنیم.

برخی سرورها از چند دستگاه ساخته شده‌اند که می‌توان تک‌تک آن‌ها را انتخاب کرد. servers.php هر دستگاه را مانند یک سرور جداگانه، با قیمت خودش فهرست می‌کند — مثلاً serverid برابر server6-2 و name برابر Server 6.2. همان serverid را بفرستید تا کار دقیقاً روی همان دستگاه و با قیمت خودش انجام شود، یا با ذکر دلیل رد شود. اگر شناسهٔ خود سرور (server6) را بفرستید، ارزان‌ترین دستگاه فعال آن را به کار می‌گیریم.

ما سرور را پیش از رزرو یا کسر هر مبلغی بررسی می‌کنیم. اگر نتواند کار را بگیرد، server_offline می‌گیرید و هیچ چیزی خرج نمی‌شود — یکی دیگر از servers.php انتخاب کنید و دوباره بفرستید، یا serverid را نفرستید تا ما انتخاب کنیم.

server_offline
{ "soc":"frp", "configblob":"…", "serverid":"server2" }

-> HTTP 503
   {
     "status":  503,
     "error":   "server_offline",
     "message": "The selected server is off right now (FRP). Use one of the other servers (servers.php lists them) or try again later.",
     "data":    { "state":"error", … }
   }

# No request_id was given: nothing was created, held or charged.
# We never move the request to another server for you.

صاحبان ابزار: همیشه serverid را بفرستید. فهرست را با servers.php (یا از بخش سرورها در پنل‌تان) بگیرید، بگذارید مشتری‌تان انتخاب کند، و همان شناسه را بفرستید. آن‌وقت توکن از همان سرور می‌آید، یا پاسخ دقیقاً می‌گوید چرا نیامد — هرگز از سرور دیگری گرفته نمی‌شود.

هر پاسخ، سروری را که کار را انجام می‌دهد با serverid و server_name نام می‌برد — حتی وقتی انتخاب را به ما سپرده‌اید — تا سرور کند را از دستگاه کند تشخیص بدهید.

07پیش از گرفتن request_id

token.php فقط وقتی request_id می‌دهد که همهٔ بررسی‌های زیر، به همین ترتیب، درست باشند. اولین بررسی‌ای که رد شود پاسخ شماست — با کد error خودش — و هیچ request_idای داده نمی‌شود: چیزی ساخته، نگه داشته یا کسر نشده است.

#چه چیزی بررسی می‌شوداگر رد شود
1درخواست POST است و بدنهٔ آن JSON و حداکثر ۲۵۶ کیلوبایت.method_not_allowed 405
bad_json 400
body_too_large 413
2هر چهار اعتبارنامهٔ شما یک حساب فعال را نشان می‌دهند: توکن حساب، api_key، email و password.unauthorized 401
too_many_failures 429
3درخواست از نشانی‌ای می‌آید که در فهرست IPهای مجاز حساب شماست، اگر فهرستی گذاشته باشید.ip_not_allowed 403
4از سقف تعداد درخواست در ساعت عبور نکرده‌اید.rate_limited 429
حساب به خاطر ارسال پشت‌سرهمِ یک دستگاه پشتیبانی‌نشده محدود نشده باشد (به دستگاه‌های پشتیبانی‌شده نگاه کنید).account_restricted 403
5soc برابر frp یا fdl است، این سرویس به حساب شما فروخته می‌شود، و روشن است.missing_soc 400
bad_service 400
not_entitled 403
disabled 503
6configblob معتبر است و خواندن کاملی را که حالت گوشی لازم دارد در خود دارد.missing_configblob 400
bad_configblob 400
missing_token 400
incomplete_configblob 400
7دستگاه در فهرست دستگاه‌هایی که سرویس نمی‌دهیم نیست.unsupported 422
8سروری که در serverid نام بردید وجود دارد، برای حساب شما فعال است، و همین حالا کار می‌گیرد: روشن، با قیمت مشخص، آنلاین و از سمت ما آماده.unknown_serverid 404
server_not_allowed 403
server_offline 503
سروری نام نبردید: ارزان‌ترین سروری را که کار می‌گیرد و حساب شما اجازهٔ استفاده از آن را دارد برمی‌داریم، و پاسخ نامش را می‌آورد.service_not_allowed 403
service_offline 503
یک پیش‌بررسی اطلاعات دستگاه روی سرور انتخابی: ریجنِ خودِ دستگاه خوانده و با فهرست ما سنجیده می‌شود؛ ریجنی که سرور انتخابی پشتیبانی نکند با unsupported رد می‌شود (پاسخ region دستگاه، takes_on، suggested و premium را می‌آورد). وضعیت فلش هم خوانده می‌شود، اما در تصمیم نقشی ندارد. این پیش از دادن request_id رخ می‌دهد، پس چیزی کسر نمی‌شود. اگر این پیش‌بررسی در دسترس نباشد، نادیده گرفته می‌شود و همان فهرست دستگاه‌های بالا اعمال می‌ماند.unsupported 422
9همین دستگاه — همان توکن دستگاه، برای همان سرویس و همان سرور — در ۳۰ دقیقهٔ گذشته فرستاده نشده باشد. اگر فرستاده شده و آن کار شروع شده، همان کار را پس می‌گیرید: request_id و وضعیتش، یا توکنش — هرگز کار دوم یا کسر دوم. کاری که شکست خورده، یا request_idاش هرگز تأیید نشده، با یک کار تازه جایگزین می‌شود.—
10کردیت شما قیمت یک کار روی همان سرور را پوشش می‌دهد — همان price که servers.php برایش نشان می‌دهد. اینجا بررسی می‌شود؛ مبلغ فقط وقتی کار شروع شود نگه داشته می‌شود.no_credit 402
همهٔ بررسی‌ها درست بود: همان لحظه request_id را با state برابر waiting می‌گیرید. هنوز چیزی به هیچ سروری فرستاده نشده و تا وقتی آن را با status.php تأیید نکنید، مبلغی نگه داشته نمی‌شود.

08request_id شما

پاسخ همان لحظه می‌آید: HTTP 202 با state برابر waiting. request_id همان WorkID کار است — همان WT-API-6AF684545B را در پنل خود می‌بینید و می‌توانید آنجا جستجویش کنید. نگهش دارید: تأیید کار، دنبال کردنش، گرفتن توکن و پرسیدن از ما دربارهٔ آن، همه با همین request_id انجام می‌شود. یک request_id که پیش از 2026-10-17 داده شده، مثل Api123، همه‌جا هنوز کار می‌کند و با همان شکل پاسخ داده می‌شود.

پاسخ token.php
HTTP/1.1 202 Accepted

{
  "status": 202,
  "data": {
    "request_id":     "WT-API-6AF684545B",
    "soc":            "frp",
    "serverid":       "server1",
    "server_name":    "Server 1",
    "configblob":     "eyJ0b2tlbiI6IjhmMjFj…",
    "device":         { "product_model":"fleur", "device_name":"fleur_global", … },
    "state":          "waiting",
    "confirm_within": 30,
    "price":          1.2,
    "currency":       "USD",
    "response_token": null,
    "start_date":     { … },
    "end_date":       { … },
    "response_date":  { … }
  }
}

# Nothing has been sent to any server yet, and nothing is held.
# Send this request_id to status.php within 30 seconds: that starts the job.

آن را در ۳۰ ثانیه تأیید کنید. آن را به status.php بفرستید: همین فراخوانی رسید شماست و کار را شروع می‌کند. request_idای که در ۳۰ ثانیه تأیید نشود لغو می‌شود — چیزی به هیچ سروری فرستاده نشده و چیزی کسر نشده — و فراخوانی بعدی با آن پاسخ request_expired می‌گیرد: درخواست را دوباره بفرستید تا request_id تازه بگیرید. پس اگر پاسخی هرگز به دستتان نرسید، هیچ کاری در جریان نیست که نتوانید دنبالش کنید.

فیلدچیست
request_idشناسهٔ ما برای این کار — WorkID آن، مثل WT-API-6AF684545B. کار را با آن تأیید کنید، دنبال کنید و تحویل بگیرید، و در هر سؤالی دربارهٔ آن، همین را به ما بگویید.
statewaiting
confirm_withinثانیه‌های باقی‌مانده برای تأیید آن با status.php.
priceهزینهٔ این کار برای شما روی همان سرور — هنگام شروع نگه داشته می‌شود و فقط اگر توکن بیاید کسر می‌شود.
serveridشناسهٔ عمومی سروری که کار را انجام داد — همان serverid که خودتان می‌توانید بفرستید.
server_nameنام عمومی همان سرور، مثلاً Server 1.

همین دستگاه — همان توکن دستگاه، برای همان سرویس و همان سرور — در ۳۰ دقیقهٔ گذشته فرستاده نشده باشد. اگر فرستاده شده و آن کار شروع شده، همان کار را پس می‌گیرید: request_id و وضعیتش، یا توکنش — هرگز کار دوم یا کسر دوم. کاری که شکست خورده، یا request_idاش هرگز تأیید نشده، با یک کار تازه جایگزین می‌شود.

بخش ۲ · بررسی درخواست

09تأیید و پیگیری

POSThttps://xiaomi.source.af/api/reseller/v1/status.php

request_id را با همان چهار اعتبارنامه به status.php بفرستید. اولین فراخوانی در ۳۰ ثانیه کار را شروع می‌کند و همان لحظه pending پاسخ می‌دهد؛ پس از آن هر retry_after ثانیه دوباره بپرسید تا state دیگر pending نباشد. یک کار معمولاً ۱۵ تا ۲۵ ثانیه طول می‌کشد.

status.php
POST /api/reseller/v1/status.php
{ "api_key":"…", "email":"…", "password":"…", "request_id":"WT-API-6AF684545B" }

# 1. the first call, within 30 seconds -- your receipt: the job starts now
-> HTTP 202  { "status":202, "data":{ "request_id":"WT-API-6AF684545B", "state":"pending", "retry_after":3, … } }

# 2. ask again every retry_after seconds
-> HTTP 202  { "status":202, "data":{ "request_id":"WT-API-6AF684545B", "state":"pending", "retry_after":3, … } }

# 3. the token
-> HTTP 200  { "status":200, "data":{ "request_id":"WT-API-6AF684545B", "state":"done",
                                      "response_token":"THE_UNLOCK_TOKEN_GOES_HERE", … } }

# Asked again later with the same request_id: the same token, at no extra cost.

معنای state

وضعیتHTTPیعنی چه، و چه کار کنید
pending202کار نزد سرور است. پس از retry_after ثانیه دوباره بپرسید.
done200توکن در response_token است: آن را روی گوشی بنویسید. هزینهٔ کار کسر شده؛ پاسخ مبلغ و کردیت باقی‌ماندهٔ شما را می‌گوید.
error4xx · 5xxتوکنی نیامد. error دلیلش را می‌گوید — server_offline، unsupported، server_unavailable، failed یا no_credit. مبلغ کامل به کردیت شما برمی‌گردد، مگر وقتی سرور بگوید این دستگاه را پشتیبانی نمی‌کند (unsupported): هزینهٔ آن کار کسر می‌شود، همان‌طور که amount_charged نشان می‌دهد.
expired410در ۳۰ ثانیه تأیید نشد: لغو شد، چیزی فرستاده نشد، چیزی کسر نشد. درخواست را دوباره بفرستید تا request_id تازه بگیرید.
not_found404هیچ درخواستی با این request_id به حساب شما تعلق ندارد.

توکن همراه کار، روی سرور ما نگه داشته می‌شود. اگر پاسخی هرگز به دستتان نرسید، با همان request_id دوباره از status.php بپرسید: تا وقتی کار در جریان است pending می‌گیرید و وقتی تمام شد توکن را — هر چند بار که بپرسید، بدون هزینهٔ اضافه. کاری که شکست خورده دلیلش را می‌گوید.

request_expired
# the first status.php call came more than 30 seconds after token.php answered
-> HTTP 410
   {
     "status":  410,
     "error":   "request_expired",
     "message": "This request_id was not confirmed with status.php within 30 seconds, so it was cancelled. Nothing was sent to any server and nothing was charged. Send a new request to get a new request_id.",
     "data":    { "request_id":"WT-API-6AF684545B", "state":"expired", "response_token":null, … }
   }

status.php محدودیت خودش را دارد — ۱۲۰ فراخوانی در دقیقه برای هر حساب — و از سهمیهٔ ساعتی شما کم نمی‌کند، پس دنبال کردن یک کار هرگز درخواست‌های توکن شما را مصرف نمی‌کند.

10پاسخ

یک شکل برای هر پاسخ دربارهٔ یک کار، چه از token.php، چه از status.php و چه از history.php. state یکی از waiting، pending، done، error یا expired است؛ وضعیت HTTP هم همین را می‌گوید، تا پیش از خواندن پاسخ بتوانید تصمیم بگیرید.

توکن تحویل شد
HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8

{
  "status": 200,
  "data": {
    "request_id":  "WT-API-6AF684545B",
    "soc":         "frp",
    "serverid":    "server1",
    "server_name": "Server 1",
    "configblob":  "eyJ0b2tlbiI6IjhmMjFjMGI0ZTlkNyIsImRldmljZU5hbWUiOiJm…",

    "device": {
      "product_model":  "fleur",
      "serial_number":  "fb4d921c",
      "device_version": "OS2.0.207.0.VMTMIXM",
      "device_name":    "fleur_global",
      "cpu_id":         "0x000460E1",
      "codebase":       "14",
      "branch":         "F",
      "region":         "global",
      "soc":            "frp"
    },

    "state":          "done",
    "response_token": "THE_UNLOCK_TOKEN_GOES_HERE",
    "provider_ref":   "R7F3A9C21B04E",
    "amount_charged": 1.2,
    "credit":         93.8,
    "currency":       "USD",

    "start_date": {
      "client_sent":       "2026-09-21T14:51:51.980Z",
      "server_received":   "2026-09-21T14:51:52.392Z",
      "upstream_sent":     "2026-09-21T14:51:52.560Z",
      "upstream_received": "2026-09-21T14:51:57.392Z",
      "elapsed_seconds":   5.0
    },
    "end_date": {
      "upstream_answered": "2026-09-21T14:51:57.392Z",
      "server_answered":   "2026-09-21T14:52:00.392Z",
      "elapsed_seconds":   3.0
    },
    "response_date": {
      "total_seconds":               8.0,
      "client_clock_offset_seconds": 0.412
    }
  }
}

هر فیلد در پاسخ:

فیلدچیست
request_idشناسهٔ ما برای این کار — WorkID آن، مثل WT-API-6AF684545B. کار را با آن تأیید کنید، دنبال کنید و تحویل بگیرید، و در هر سؤالی دربارهٔ آن، همین را به ما بگویید.
socسرویسی که اجرا شد.
serveridشناسهٔ عمومی سروری که کار را انجام داد — همان serverid که خودتان می‌توانید بفرستید.
server_nameنام عمومی همان سرور، مثلاً Server 1.
configblobهمان configblob که فرستادید، بایت به بایت.
deviceدستگاه، باز شده. همیشه هست.
statewaiting، pending، done، error یا expired.
response_tokenتوکن آنلاک. همین را روی گوشی می‌نویسید.
provider_refشمارهٔ کار خود سرور، به درد پیگیری می‌خورد.
amount_chargedاین کار چقدر برای شما تمام شد.
creditکردیت شما بعد از کسر.
currencyواحد پول هر دو عدد.

یک خطا

HTTP 4xx / 5xx
# the job started, and the server could not take it
-> HTTP 503
   {
     "status":  503,
     "error":   "server_offline",
     "message": "The selected server is off right now (FRP). Use one of the other servers (servers.php lists them) or try again later. Nothing was charged.",
     "data":    { "request_id":"WT-API-1C93E07B2D", "serverid":"server2", "server_name":"Server 2",
                  "state":"error", "response_token":null, … }
   }

# The price is back on your credit in full. The job was not moved to another server.

سه بلوک زمانی

سه بلوک، و با هم جمع می‌شوند: start_date.elapsed_seconds به‌علاوهٔ end_date.elapsed_seconds دقیقاً برابر response_date.total_seconds است، چون هر سه از همان چند لحظهٔ یکسان به دست می‌آیند.

در مثال پایین، ۵ ثانیه طول کشید تا توکن گرفته شود و ۳ ثانیه تا تحویل داده شود، یعنی ۸ ثانیه در کل.

فیلدچیست
start_date — گرفتن توکن
client_sentزمانی که سرور شما درخواست را فرستاد — عیناً همان که فرستادید
server_receivedزمانی که درخواست به سرور ما رسید
upstream_sentزمانی که ما درخواست را به سرور توکن فرستادیم
upstream_receivedزمانی که پاسخ سرور توکن به ما رسید
elapsed_secondsاز رسیدن تا گرفتن توکن — ۵ ثانیه در مثال
end_date — تحویل دادن آن
upstream_answeredزمانی که سرور توکن به سرور ما پاسخ داد
server_answeredزمانی که سرور ما پاسخ را به شما داد
elapsed_secondsفقط مرحلهٔ تحویل — ۳ ثانیه در مثال
response_date — کل ماجرا
total_seconds۵ + ۳ = ۸ ثانیه
client_clock_offset_secondsفاصلهٔ ساعت شما با ساعت ما

بلوک‌های زمانی از لحظه‌ای اندازه گرفته می‌شوند که token.php درخواست را دریافت کرد. end_date وقتی تمام می‌شود که پاسخِ همراه توکن از ما بیرون رفت، پس فاصلهٔ بین فراخوانی‌های status.php شما را هم در بر می‌گیرد.

چرا زمان خودِ شما در جمع‌ها استفاده نمی‌شود
آن در client_sent بازتاب داده می‌شود و مال شماست، نه ما — اگر ساعت سرور شما یک دقیقه جلو باشد، محاسبه با آن مدت زمانی منفی گزارش می‌کند. هر عدد سپری‌شده از ساعت ما می‌آید، و فاصلهٔ بین این دو جداگانه به‌عنوان client_clock_offset_seconds گزارش می‌شود تا ببینیدش، نه اینکه بی‌صدا داخل عددی برود که بابتش صورتحساب می‌دهید.

11خواندن اطلاعات دستگاه (soc)

علاوه بر frp و fdl، حساب‌های «صاحب ابزار» می‌توانند اطلاعات دستگاه را هم بخوانند. این سرویس‌ها از همان مسیر token.php سپس status.php کار می‌کنند، اما هیچ سروری نمی‌گیرند و به‌جای توکن، اطلاعات دستگاه را به‌صورت فیلد برمی‌گردانند. فعلاً رایگان‌اند (بعداً ممکن است قیمت بگیرند).

مقدارهای soc

socچه می‌کندورودیزمان پاسخ
frpآنلاک FRP؛ یک توکن پاسخ برمی‌گرداند.configblob — کل اطلاعات خوانده‌شدهٔ دستگاهبی‌درنگ
fdlمجوز FDL؛ یک توکن پاسخ برمی‌گرداند.configblob — کل اطلاعات خوانده‌شدهٔ دستگاهبی‌درنگ
read_sideloadاطلاعات دستگاه را در حالت Mi Assistant می‌خواند.configblob — فقط به توکن دستگاه نیاز استبی‌درنگ
read_fastbootاطلاعات دستگاه را در حالت fastboot می‌خواند.configblob — فقط به توکن دستگاه نیاز استبی‌درنگ
read_imeiIMEI را در پایگاه دادهٔ سازنده جست‌وجو می‌کند.imei — پانزده رقم IMEI۱ تا ۵ دقیقه؛ poll کنید
read_lockcodeرکورد دستگاه پشتِ یک lock code را برمی‌گرداند.imei — IMEI برای ثبت سفارشچند دقیقه؛ poll کنید

این خواندن‌ها فقط برای حساب‌های «صاحب ابزار» است. read_imei فقط وقتی فهرست می‌شود که برای API باز باشد؛ در غیر این صورت داخل ابزار XST در دسترس است.

فرستادن یک خواندن

یک خواندن دقیقاً مثل frp و fdl فرستاده و بررسی می‌شود: token.php یک request_id می‌دهد، نخستین فراخوان status.php آن را آغاز می‌کند و تا done شدن poll می‌کنید. هیچ سروری گرفته نمی‌شود و هزینهٔ سرور ندارد.

token.php · read
# A DEVICE-TOKEN READ (Mi Assistant) -- soc = read_sideload. No serverid: a read
# uses no server. Only the device token inside configblob is needed.
POST /api/reseller/v1/token.php
{ "api_key":"…", "email":"…", "password":"…",
  "soc":"read_sideload", "configblob":"eyJ0b2tlbiI6IjhmMjFj…" }

-> HTTP 202
   { "status":202, "data":{ "request_id":"WT-API-3D7B19F0A4", "soc":"read_sideload",
                            "kind":"read", "state":"waiting", "confirm_within":30,
                            "price":0, "currency":"USD" } }

# read_fastboot is the same, with the token read in fastboot mode.

# AN IMEI LOOKUP -- soc = read_imei. No configblob: the caller types the IMEI.
POST /api/reseller/v1/token.php
{ "api_key":"…", "email":"…", "password":"…", "soc":"read_imei", "imei":"862127050000000" }

-> HTTP 202
   { "status":202, "data":{ "request_id":"WT-API-B82E6C0D51", "soc":"read_imei",
                            "kind":"read", "state":"waiting", "confirm_within":30, … } }

# read_lockcode is the same shape, with the IMEI used for the shop order.

آنچه یک خواندنِ تمام‌شده برمی‌گرداند

به‌جای response_token، یک خواندن با یک شیء fields پاسخ می‌دهد — اطلاعات دستگاه به‌صورت جفت‌های برچسب/مقدار. برچسب‌ها به سرویس بستگی دارند؛ فیلدی که منبع خالی گذاشته باشد حذف می‌شود.

status.php · read done
POST /api/reseller/v1/status.php
{ "api_key":"…", "email":"…", "password":"…", "request_id":"WT-API-3D7B19F0A4" }

# 1. the first call, within 30 seconds -- your receipt: the read starts now
-> HTTP 202  { "status":202, "data":{ "request_id":"WT-API-3D7B19F0A4", "soc":"read_sideload",
                                      "kind":"read", "state":"pending", "retry_after":5 } }

# 2. ask again every retry_after seconds, until state is "done"
-> HTTP 200
   {
     "status": 200,
     "data": {
       "request_id":     "WT-API-3D7B19F0A4",
       "soc":            "read_sideload",
       "kind":           "read",
       "state":          "done",
       "fields": {
         "Product":        "fleur",
         "IMEI":           "862127050000000",
         "IMEI 2":         "862127050000001",
         "Serial (SN)":    "fb4d921c",
         "Region":         "Iran (IR)",
         "Find My Device": "OFF"
       },
       "amount_charged": 0,
       "credit":         38,
       "currency":       "USD"
     }
   }

# A read answers with `fields` -- label/value pairs -- not a response_token.
# Asked again later with the same request_id: the same fields, at no extra cost.
read_imei · done
# read_imei: the answer takes about 1 to 5 minutes. Keep polling status.php until
# state is "done"; every call is "pending" with a retry_after until then.
# `fields` is a label->value map; which labels come back depends on the device and
# which info sources are enabled for your account, so treat it generically (loop
# over it) -- never assume a fixed set. Any of these may appear:
-> HTTP 200
   { "status":200, "data":{ "request_id":"WT-API-B82E6C0D51", "soc":"read_imei", "kind":"read", "state":"done",
       "fields": {
         "IMEI":            "862127050000000",
         "IMEI 2":          "862127050000001",
         "Product name":    "Xiaomi 14 12GB+512GB Black",
         "Brand":           "Xiaomi",
         "Model":           "Xiaomi 14",
         "Model code":      "2405CPX3DG",
         "Manufacturer":    "Xiaomi",
         "RAM":             "12 GB",
         "Storage":         "512 GB",
         "Color":           "Black",
         "Sold in":         "Global (MI)",
         "Region":          "Global",
         "Serial (SN)":     "fb4d921c",
         "SKU":             "MZB0ABCIN",
         "Wi-Fi MAC":       "A4:FF:9F:71:0E:EE",
         "Factory date":    "2024-02-14",
         "Activation":      "Never activated",
         "Repair":          "Available",
         "Flash status":    "Clean",
         "Production date": "2024-02-20 08:14 UTC",
         "Find My Device":  "OFF"
       },
       "amount_charged":0, "credit":38, "currency":"USD" } }
read_lockcode · done
# read_lockcode: an order placed at the shop. The answer takes a few minutes; keep
# polling status.php. Our own cron also follows the order, so it finishes even if
# you stop asking.
-> HTTP 200
   { "status":200, "data":{ "request_id":"WT-API-47A0F3E9C2", "soc":"read_lockcode", "kind":"read", "state":"done",
       "fields": {
         "Lock code":      "4YYZ-F7CO-FPDJ-GAU",
         "Product":        "fleur",
         "Serial Number":  "58583/65QU09211",
         "IMEI":           "862127050000000",
         "Find My Device": "ON"
       },
       "amount_charged":0, "credit":38, "currency":"USD" } }

servers.php خواندن‌هایی را که مجازید در یک آرایهٔ reads فهرست می‌کند؛ هر کدام با soc، نام، needs و price، و time (زمان تحویل؛ برای read_lockcode همان زمانِ سرویس فروشگاه، خالی وقتی معلوم نیست) و field (نام کادر ورودی برای مشتری، مثلاً Lock Code). خواندن‌های read_imei و read_lockcode غیرهم‌زمان‌اند (poll).

بخش ۳ · کردیت و قیمت‌های شما

12تاریخچهٔ کارهای شما

POSThttps://xiaomi.source.af/api/reseller/v1/history.php

کارهای شما، از جدید به قدیم: هر کدام کی فرستاده شد، به کدام سرور، و چطور تمام شد — بر اساس تاریخ و سرویس. همان چهار اعتبارنامه؛ کردیتی مصرف نمی‌کند و از سهمیهٔ ساعتی شما حساب می‌شود.

فیلدنوعالزامیچیست
fromstringخیریک روز، 2026-10-08 (یا 2026-Oct-08)، به وقت UTC: کارهایی که در آن روز یا بعد از آن فرستاده شده‌اند.
tostringخیریک روز: کارهایی که در آن روز یا پیش از آن فرستاده شده‌اند، با کل همان روز.
socstringخیرfrp یا fdl: فقط کارهای همان سرویس.
limitnumberخیرتعداد کارهایی که فهرست می‌شوند، از ۱ تا ۱۰۰. پیش‌فرض ۱.
beforestringخیریک request_id: کارهای قدیمی‌تر از آن. next_before هر پاسخ را بفرستید تا صفحهٔ بعد را بگیرید.
history.php
curl -X POST https://xiaomi.source.af/api/reseller/v1/history.php \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer rst_YOUR_ACCOUNT_TOKEN' \
  -d '{"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD",
       "from":"2026-10-08","to":"2026-10-09","soc":"frp","limit":2}'

-> {
  "status": 200,
  "data": {
    "from":     "2026-10-08",
    "to":       "2026-10-09",
    "soc":      "frp",
    "total":    14,
    "counts":   { "done":11, "error":2, "expired":1, "pending":0, "waiting":0 },
    "spent":    13.2,
    "currency": "USD",
    "jobs": [
      { "request_id":"WT-API-6AF684545B", "door":"api", "soc":"frp", "serverid":"server1", "server_name":"Server 1",
        "state":"done", "error":null, "message":null, "amount":1.2, "currency":"USD",
        "device":{ "product_model":"fleur", "device_name":"fleur_global", "serial_number":"fb4d921c" },
        "created_at":"2026-10-09T14:51:52Z", "updated_at":"2026-10-09T14:52:00Z" },
      { "request_id":"WT-API-9F04A2C6E1", "door":"api", "soc":"frp", "serverid":"server2", "server_name":"Server 2",
        "state":"error", "error":"server_offline", "message":"The selected server is off right now (FRP). …",
        "amount":0, "currency":"USD", "device":{ … },
        "created_at":"2026-10-09T14:40:10Z", "updated_at":"2026-10-09T14:40:11Z" }
    ],
    "next_before": "WT-API-9F04A2C6E1"
  }
}

total و counts کل بازه را در بر می‌گیرند، نه فقط همین صفحه را: چند درخواست فرستادید، و چند تا done، error، expired، pending یا waiting تمام شدند؛ spent هزینهٔ آن‌ها برای شماست. هر کار زیر jobs request_id خودش را دارد — همان WorkID: WT-API-6AF684545B برای کاری که از این API فرستاده شده، و WT-WEB-… برای کاری که در ابزار خود ما انجام شده، همان‌طور که door می‌گوید — به‌همراه soc، serverid و server_name، state، error و message وقتی توکنی نداده، amount (هزینه‌اش برای شما)، device، و زمان ارسال و آخرین تغییرش. خود توکن فهرست نمی‌شود: status.php آن را با request_id می‌دهد.

13کردیت و مصرف

POSThttps://xiaomi.source.af/api/reseller/v1/balance.php

چقدر کردیت مانده و بقیه کجا خرج شده: همان اعداد کارت‌های بالای پنل شما. همان چهار اعتبارنامهٔ درخواست توکن را می‌گیرد، کردیتی مصرف نمی‌کند و هر ۱۰ ثانیه یک بار پاسخ می‌دهد.

balance.php
curl -X POST https://xiaomi.source.af/api/reseller/v1/balance.php \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer rst_YOUR_ACCOUNT_TOKEN' \
  -d '{"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD"}'

-> {
  "status": 200,
  "data": {
    "username": "you",
    "credit":   38,
    "currency": "USD",
    "usage": {
      "bought":        50,
      "spent":         12,
      "spent_frp":     10.8,
      "spent_fdl":     1.2,
      "spent_api":     9,
      "spent_xst":     3,
      "sent_to_users": 0,
      "left":          38
    },
    "prices": {
      "frp": [
        { "serverid":"server1", "name":"Server 1", "online":true,  "price":1.2 },
        { "serverid":"server2", "name":"Server 2", "online":true,  "price":1.5 },
        { "serverid":"server3", "name":"Server 3", "online":false, "price":1.4 }
      ],
      "fdl": [
        { "serverid":"server1", "name":"Server 1", "online":true,  "price":0.3 }
      ]
    }
  }
}

زیر usage: bought همهٔ کردیتی است که به حساب شما اضافه شده، منهای آنچه ادمین پس گرفته؛ spent هزینهٔ کارهای شماست، منهای بازپرداخت‌ها — به تفکیک سرویس در spent_frp و spent_fdl، و به تفکیک مسیر در spent_api (از این API) و spent_xst (در ابزار خود ما)؛ sent_to_users آن است که اگر روزی فروشنده بوده‌اید به کاربران خودتان داده‌اید؛ left باقی‌مانده است، همان credit. با هم جمع می‌شوند: bought − sent_to_users − spent = left، و spent_frp + spent_fdl = spent. prices هزینهٔ یک کار روی هر سرور برای شماست، به تفکیک سرویس: serverid، name، اینکه online است یا نه، و price، به ارز خودتان.

اگر زودتر از ۱۰ ثانیه دوباره بپرسید، پاسخ 429 too_soon با retry_after می‌گیرید: همان تعداد ثانیه صبر کنید. هیچ چیزی مسدود نمی‌شود.

14سرورها و قیمت‌ها

POSThttps://xiaomi.source.af/api/reseller/v1/servers.php

همان چهار اعتبارنامهٔ درخواست توکن را می‌گیرد و کردیتی مصرف نمی‌کند. هر فراخوانی از سهمیهٔ ساعتی شما حساب می‌شود.

چه چیزی می‌توانید استفاده کنید و هر کار چقدر برایتان تمام می‌شود.

servers.php
curl -X POST https://xiaomi.source.af/api/reseller/v1/servers.php \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer rst_YOUR_ACCOUNT_TOKEN' \
  -d '{"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD"}'

-> {
  "status": 200,
  "data": {
    "currency": "USD",
    "services": {
      "frp": {
        "price": 1.2,
        "providers": [
          { "serverid":"server1", "name":"Server 1", "online":true,  "price":1.2, "currency":"USD",
            "region_support":[], "region_not_support":["CN","IN"] },
          { "serverid":"server6-3", "name":"Server 6.3", "online":true,  "price":1.5, "currency":"USD",
            "region_support":["CN"], "region_not_support":["IN"] },
          { "serverid":"server3", "name":"Server 3", "online":false, "price":1.4, "currency":"USD",
            "region_support":["CN","IN"], "region_not_support":[] }
        ]
      },
      "fdl": { "price":0.3, "providers":[ … ] }
    }
  }
}

هر ردیف زیر providers یک سرور است که می‌توانید استفاده کنید — همهٔ آن‌ها، حتی آن‌هایی که همین حالا خاموش‌اند (online برابر false)؛ سرورهای فعال اول و ارزان‌ترها اول. serverid و name همان‌هایی‌اند که می‌فرستید و هر پاسخ برمی‌گرداند، price هزینهٔ یک کار روی آن برای شماست، و online می‌گوید آیا درخواستی که به آن نام برده شود همین حالا پذیرفته می‌شود. انتخاب سرور خاموش با خودتان است: token.php آن را پیش از دادن هر request_id با server_offline رد می‌کند — از سرور دیگری استفاده کنید یا بعداً امتحان کنید. price کنار فهرست، هزینهٔ درخواستی بدون serverid است: ارزان‌ترین سروری که کار می‌گیرد.

هر ردیف همچنین می‌گوید آن سرور دستگاه‌های کدام کشورها را می‌پذیرد، بر اساس region دستگاه: region_support — کشورهایی که این سرور می‌پذیرد هرچند بعضی از سرورهای ما نمی‌پذیرند (یا ما پذیرفتنشان را آنجا اعلام کرده‌ایم)، region_not_support — کشورهایی که نمی‌پذیرد. هر دو خالی: همهٔ کشورها. آن‌ها را برای یادآوری به مشتری‌تان نشان دهید، مثلاً «سرور 6.3 — چین: بله، هند: نه». فقط کشور منتشر می‌شود: بقیهٔ شرط‌های ما (مدل، بیلد، CPU ID…) فهرست نمی‌شوند و نزد ما می‌مانند. تصمیم همیشه همین‌جا و پیش از هر ارسال گرفته می‌شود — token.php دستگاهی را که سرور نمی‌پذیرد با unsupported (422) رد می‌کند و check.php برای یک دستگاه جوابش را می‌دهد.

پاسخ servers را با خیال راحت می‌توانید به مشتری خودتان نشان بدهید: نام عمومی سرورهای ما و قیمت شما در آن هست، نه هزینهٔ ما و نه تأمین‌کنندهٔ بالادست.

15کدام سرورها یک دستگاه را می‌پذیرند

POSThttps://xiaomi.source.af/api/reseller/v1/check.php

یک بررسی خشک: همان اعتبارنامه‌ها و همان بدنهٔ token.php (soc، configblob)، همان بررسی‌های configblob و همان خطاها — و بعد هیچ: نه request_idای، نه کاری، نه رزرو یا کسری، نه ارسالی به هیچ سروری. بعضی سرورها بعضی دستگاه‌ها را نمی‌پذیرند (یک بیلد، یک کشور…)؛ این فراخوانی برای همین دستگاه می‌گوید کدام سرورهای شما آن را می‌پذیرند. محدودیت جدای خودش را دارد، ۶۰ فراخوانی در دقیقه، و از سهمیهٔ ساعتی شما کم نمی‌کند.

check.php
curl -X POST https://xiaomi.source.af/api/reseller/v1/check.php \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer rst_YOUR_ACCOUNT_TOKEN' \
  -d '{"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD",
       "soc":"frp","configblob":"eyJ0b2tlbiI6IjhmMjFj…"}'

-> {
  "status": 200,
  "data": {
    "soc": "frp",
    "refused_everywhere": false,
    "suggested": "server6-3",
    "device": { "model":"fleur", "device":"fleur_global", "version":"OS2.0.207.0.VMTMIXM", "region":"US", "cpuid":"0x000460E1" },
    "servers": [
      { "serverid":"server1",   "name":"Server 1",   "online":true,  "price":1.2, "currency":"USD", "region_support":[],     "region_not_support":["CH","CN"], "takes":false, "reason":"China devices are not supported on this server" },
      { "serverid":"server6-3", "name":"Server 6.3", "online":true,  "price":2.0, "currency":"USD", "region_support":["CH","CN"], "region_not_support":[], "takes":true },
      { "serverid":"server5",   "name":"Server 5",   "online":false, "price":1.4, "currency":"USD", "region_support":[],     "region_not_support":["CH","CN"], "takes":false, "reason":"…" }
    ],
    "region": "CN",
    "region_checked": true,
    "flash_status": "CLEAN",
    "premium": [ { "serverid":"server6-3", "name":"Server 6.3", "online":true, "price":2.0, "currency":"USD" } ],
    "slots_full": false,
    "message": "Your device's region is CN. This device must be done with ★ Server 6.3 — a premium server: its FRP removal success rate for this device is very high."
  }
}

ردیف‌های زیر servers همان‌هایی‌اند که servers.php فهرست می‌کند، با همان ترتیب، حتی خاموش‌ها. takes می‌گوید آن سرور این دستگاه را می‌پذیرد یا نه؛ اگر نپذیرد، reason دلیلش را می‌گوید. سروری می‌تواند خاموش باشد (online برابر false) و باز هم دستگاه را بپذیرد: به مشتری‌تان بگویید بعداً امتحان کند. suggested اولین سروری است که دستگاه را می‌پذیرد و روشن است (ارزان‌ترها اول)، یا null؛ refused_everywhere وقتی true است که هیچ‌کدام از سرورهای شما آن را نپذیرد. device آن چیزی است که از configblob خواندیم. وقتی token.php دستگاهی را با unsupported (422) رد می‌کند، پاسخش takes_on را دارد: serverid سرورهایی که آن را می‌پذیرند.

این پاسخ ریجنِ خودِ دستگاه را هم با همان پیش‌بررسی اطلاعات دستگاه که token.php اجرا می‌کند می‌خواند — گوشی می‌تواند ریجنی را گزارش دهد که مال آن نیست. region ریجنی است که سرورها بر اساس آن سنجیده شدند: اگر region_checked برابر true باشد همان چیزی که پیش‌بررسی خواند، وگرنه آنچه configblob گفت. flash_status وضعیت فلشی است که خوانده شد (اگر معلوم نباشد خالی). premium سرورهای شما را می‌آورد که این دستگاه را می‌پذیرند و برای ریجن آن پریمیوم هستند (برای دستگاه‌های آن کشور ساخته شده‌اند، پس درصد موفقیت‌شان برای آن بسیار بالاست)؛ آن‌وقت suggested یکی از آن‌هاست و message جمله‌ای است که می‌توانید به مشتری نشان دهید، مثلاً «ریجن دستگاه شما CN است. این دستگاه باید با Server 6.3 انجام شود — این سرور پریمیوم است …» (اگر نباشد خالی). همان سرور را برای مشتری از پیش انتخاب کنید، دلیلش را بگویید و بگذارید سرور را عوض کند، لغو کند یا ادامه دهد. پاسخ پیش‌بررسی ۱۵ دقیقه نگه داشته می‌شود، پس token.php بعدی دوباره نمی‌پرسد.

آن را بعد از خواندن دستگاه بپرسید تا سرورهایی را که ردش می‌کنند کم‌رنگ کنید، یا بعد از اینکه token.php برای سرورِ انتخاب‌شدهٔ مشتری unsupported داد تا سروری را که آن را می‌پذیرد پیشنهاد دهید. درخواستی بدون serverid خودش به ارزان‌ترین سروری فرستاده می‌شود که دستگاه را می‌پذیرد.

بخش ۴ · کدهای خطا

16کدهای خطا

هر خطا یک شکل دارد: یک کد error که رویش شرط بگذارید و یک message برای آدم. روی کد شرط بگذارید، نه روی متن پیام — متن عوض می‌شود، کد نه. خطاهای token.php پس از بررسی‌های ورود، بلوک‌های زمانی را هم دارند، پس یک شکست کند به‌اندازهٔ یک موفقیت کند قابل اندازه‌گیری است. بعضی‌ها فیلدهای خودشان را هم دارند: incomplete_configblob نام فیلدها را در missing و invalid همراه با mode می‌آورد؛ rate_limited هم limit و used را. کد هرچه باشد، کاری که توکن نداد هزینه‌ای ندارد — ردها پیش از هر رزروی انجام می‌شوند، و کاری که پس از ارسال شکست بخورد، مبلغ رزروشده‌اش کامل برمی‌گردد.

کدHTTPیعنی چه، و چه کار کنید
unauthorized401یکی از چهار اعتبارنامه غلط است، یا حساب غیرفعال است. عمداً نمی‌گوییم کدام.
ip_not_allowed403هر چهار اعتبارنامه درست است، اما درخواست از نشانی‌ای آمده که در فهرست IPهای مجاز حساب شما نیست. پاسخ آن را در ip نام می‌برد. آن را در پنل خودتان (حساب ← IPهای مجاز) اضافه کنید، یا از یک نشانی مجاز بفرستید. هیچ کاری انجام نشد و هزینه‌ای کسر نشد.
too_many_failures429تلاش‌های ناموفق زیاد از آدرس شما. صبر کنید و پیش از تلاش دوباره اعتبارنامه را درست کنید.
rate_limited429از یک محدودیت عبور کردید: سهمیهٔ ساعتی شما (token.php، history.php، balance.php، servers.php) یا ۱۲۰ بررسی وضعیت در دقیقه. پاسخ limit، used و per را دارد.
too_soon429balance.php زودتر از ۱۰ ثانیه دوباره پرسیده شد. پاسخ می‌گوید چند ثانیه صبر کنید (retry_after و هدر Retry-After)؛ هیچ چیزی مسدود نمی‌شود.
method_not_allowed405از GET استفاده کرده‌اید. همهٔ اندپوینت‌ها POST هستند.
bad_json400بدنه آبجکت JSON نبود. Content-Type: application/json بگذارید.
body_too_large413بدنه بیش از ۲۵۶ کیلوبایت است.
missing_soc400soc فرستاده نشد. عمداً پیش‌فرض ندارد.
bad_service400soc باید دقیقاً frp یا fdl باشد.
not_entitled403آن سرویس به حساب شما فروخته نشده. از ما بخواهید فعال کنیم.
disabled503آن سرویس را همین حالا خاموش کرده‌ایم. موقتی است.
missing_configblob400configblob فرستاده نشد.
bad_configblob400configblob نه base64 درست است نه آبجکت JSON درست.
missing_token400token دستگاه داخل بلاب نیست.
incomplete_configblob400فیلدی که سرورها لازم دارند فرستاده نشده (missing)، null فرستاده شده (nulls) یا خوانشی ناموفق دارد (invalid)؛ mode حالتی است که گوشی باید در آن باشد. گوشی را دوباره بخوانید و اطلاعات کامل را بفرستید؛ چیزی کسر نشد.
use_serverid400شما services یا server_id را فرستادید، روش قدیمی انتخاب سرور بر اساس جایگاهش. دیگر پذیرفته نمی‌شود: serverid را بفرستید (از servers.php)، یا نفرستید تا ما انتخاب کنیم.
use_status400یک request_id به token.php فرستادید، که فقط درخواست تازه شروع می‌کند. request_id را به status.php بفرستید.
unknown_serverid404هیچ سروری این serverid را ندارد. فهرست را از servers.php یا از بخش سرورها در پنل‌تان بگیرید.
server_not_allowed403سروری که نام بردید برای حساب شما فعال نیست. شما را به سرور دیگری منتقل نمی‌کنیم: یکی از فهرست خودتان انتخاب کنید، یا serverid را نفرستید.
service_not_allowed403سروری نام نبردید و هیچ سروری برای حساب شما فعال نیست. از ما بخواهید یکی را فعال کنیم.
server_offline503سروری که نام بردید همین حالا نمی‌تواند این سرویس را بگیرد: خاموش است، آفلاین است، یا از سمت ما آماده نیست. token.php پیش از دادن request_id آن را بررسی می‌کند و کار هنگام شروع دوباره بررسی‌اش می‌کند؛ اگر در این فاصله یا هنگام اجرای کار خاموش شده باشد، مبلغ رزروشده برمی‌گردد. چیزی کسر نشد. از سرور دیگری از servers.php استفاده کنید، یا بعداً دوباره امتحان کنید.
service_offline503سروری نام نبردید و همین حالا هیچ سروری برای این سرویس کار نمی‌گیرد. چیزی کسر نشد. کمی بعد دوباره بفرستید.
no_credit402کردیت برای یک کار روی آن سرور کافی نیست — یا token.php پیش از دادن request_id رد کرده، یا اگر کردیت شما در این فاصله کم شده، هنگام شروع کار. چیزی کسر نشد. حساب را شارژ کنید، یا سرور ارزان‌تری انتخاب کنید.
bad_imei400imei نبود یا نامعتبر بود: read_imei به پانزده رقم IMEI نیاز دارد؛ read_lockcode به IMEI برای ثبت سفارش نیاز دارد.
read_failed502یک خواندن (read_sideload یا read_fastboot یا read_imei یا read_lockcode) کامل نشد. چیزی کسر نشد. دوباره بفرستید یا بعداً تلاش کنید.
missing_request_id400status.php بدون request_id فراخوانده شد.
not_found404هیچ درخواستی با این request_id به حساب شما تعلق ندارد.
request_expired410request_id در ۳۰ ثانیه با status.php تأیید نشد، پس لغو شد. چیزی فرستاده یا کسر نشد. درخواست را دوباره به token.php بفرستید تا request_id تازه بگیرید.
unsupported422این دستگاه قابل سرویس نیست. اگر در فهرست دستگاه‌هایی باشد که سرویس نمی‌دهیم، token.php آن را رد می‌کند: نه request_idای داده می‌شود و نه چیزی کسر می‌شود. اگر سروری که انتخاب کردید بگوید این دستگاه را پشتیبانی نمی‌کند، هزینهٔ کار کسر می‌شود و بازگردانده نمی‌شود — پیش از ارسال از ما بپرسید کدام بیلدها و کشورها پشتیبانی می‌شوند (به دستگاه‌های پشتیبانی‌شده نگاه کنید). روی همان سرور دوباره نفرستید.
account_restricted403حساب شما چند دقیقه محدود است: یک دستگاه در ۵ دقیقه بیش از ۳ بار به‌عنوان پشتیبانی‌نشده رد شد و بعد از هشدار دوباره فرستاده شد. تا آن موقع هر درخواست تازه رد می‌شود؛ status.php برای کارهایی که قبلاً شروع شده‌اند همچنان جواب می‌دهد. پاسخ reason (unsupported_device_repeated)، retry_after (ثانیه)، restricted_until و note (جمله‌ای برای پنل شما) را دارد. اگر اشتباهی شده با ما تماس بگیرید.
device_reboot409سرور می‌گوید این توکن دستگاه قبلاً استفاده شده است. چیزی کسر نشد. گوشی را ریبوت کنید، دوباره به حالت سایدلود ببرید تا توکن تازه بدهد، و درخواست تازه بفرستید.
server_unavailable503سرور به‌موقع پاسخ نداد، یا — وقتی سروری نام نبرده بودید — هیچ سروری در دسترس نبود. چیزی کسر نشد. همان درخواست را دوباره بفرستید.
failed400سروری که انتخاب کردید کار را اجرا کرد اما برای این دستگاه توکنی نداد — شکستی در مرحلهٔ آخر. چیزی کسر نشد: مبلغ رزروشده کامل برمی‌گردد. خواندن گوشی را بررسی کنید، یا سرور دیگری را امتحان کنید.
bad_before400before در history.php یک request_id نیست.
bad_date400from یا to در history.php روزی مثل 2026-10-08 نیست، یا from بعد از to است.
بخش ۵ · امنیت

17امنیت

همیشه از HTTPS استفاده کنید

رمز و کلید شما در بدنهٔ هر درخواست است. روی HTTP ساده هرکسی در مسیر می‌تواند آن‌ها را بخواند و دوباره استفاده کند.

توکن حساب شما فقط یک بار نشان داده می‌شود

این توکن حساب شماست — مقدار rst_… در هدر Authorization — نه توکن‌های آنلاک. ما فقط یک هش از آن نگه می‌داریم، پس نمی‌توانیم بعداً برایتان ایمیل کنیم. آن را جایی نگه دارید که بقیهٔ اسرارتان را نگه می‌دارید. اگر لو رفت، در پنل خود یک توکن تازه بسازید — قبلی بلافاصله از کار می‌افتد. توکن‌های آنلاکی که کارهای شما می‌آورند چیز دیگری‌اند: هر کدام همراه کار خودش نگه داشته می‌شود و status.php آن را با request_id دوباره به شما می‌دهد.

اعتبارنامه‌ها را از چیزی که منتشر می‌کنید بیرون نگه دارید

از سرور خودتان ما را صدا بزنید، نه از ابزاری که به کاربر نهایی می‌دهید. هر چیزی که منتشر کنید خوانده می‌شود.

API را به نشانی‌های خودتان قفل کنید

در پنل خودتان (حساب ← IPهای مجاز) می‌توانید API را به نشانی‌هایی که سرورتان از آن‌ها وصل می‌شود قفل کنید، تا اعتبارنامهٔ دزدیده‌شده از هر جای دیگر بی‌فایده باشد. درخواست از هر نشانی دیگر با ip_not_allowed رد می‌شود. ما هم می‌توانیم آن را برایتان تنظیم کنیم.

ما هرگز رمز شما را لاگ نمی‌کنیم

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

request_id رسید شماست

فقط حساب شما می‌تواند یک request_id را بخواند؛ هر حساب دیگری not_found می‌گیرد. کار فقط وقتی شروع می‌شود که request_idاش را در ۳۰ ثانیه تأیید کنید، پس پاسخی که در راه گم شود هرگز کار پولی‌ای را که از آن خبر ندارید در جریان نمی‌گذارد.

محدودیت‌ها

سهمیهٔ ساعتی شما token.php، history.php، balance.php و servers.php را در بر می‌گیرد؛ status.php جداگانه ۱۲۰ فراخوانی در دقیقه می‌پذیرد؛ balance.php هر ۱۰ ثانیه یک بار پاسخ می‌دهد؛ و پس از بیش از ۴۰ ورود ناموفق از یک نشانی در ۱۵ دقیقه، آن نشانی مدتی با too_many_failures رد می‌شود.

بخش ۶ · نمونهٔ کد

18نمونهٔ کد

برای هر کار یک برنامهٔ کامل، به چهار زبان — ارسال درخواست، بررسی آن با request_id، تاریخچهٔ کارها، کردیت، و سرورها. اعتبارنامه‌های خودتان را بگذارید و اجرا کنید؛ انتخاب یک زبان آن را در همهٔ بخش‌ها نشان می‌دهد.

1ارسال درخواست توکن

خوانش گوشی را به token.php می‌فرستد و request_id را چاپ می‌کند. هنوز چیزی اجرا نشده: آن request_id را ظرف ۳۰ ثانیه به برنامهٔ بعدی بدهید.

send.sh
#!/bin/sh
# 1. Send a token request. Prints the answer with the request_id; nothing runs
#    until you confirm it with status.sh within 30 seconds.
BASE='https://xiaomi.source.af/api/reseller/v1'
TOKEN='rst_YOUR_ACCOUNT_TOKEN'
AUTH='"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD"'
post() { curl -s -X POST "$BASE/$1" -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" -d "{$AUTH$2}"; }

# The complete Mi Assistant reading, exactly as the phone answered
DEVICE='{"token":"8f21c0b4e9d7","deviceName":"fleur_global","version":"OS2.0.207.0.VMTMIXM","serial":"fb4d921c","codebase":"15","region":"IR","cpuid":"0x000460E1","recovery":"2","branch":"F","language":"fa"}'
BLOB=$(printf '%s' "$DEVICE" | base64 | tr -d '\n')

post token.php ',"soc":"frp","serverid":"server1","configblob":"'"$BLOB"'"'
echo
# -> {"status":202,"data":{"request_id":"WT-API-6AF684545B","state":"waiting","confirm_within":30,…}}
# next, within 30 seconds:  sh status.sh WT-API-6AF684545B
send.php
<?php
/* 1. Send a token request. Prints the request_id; nothing runs until you
      confirm it with status.php within 30 seconds. */
const BASE  = 'https://xiaomi.source.af/api/reseller/v1';
const TOKEN = 'rst_YOUR_ACCOUNT_TOKEN';
const AUTH  = ['api_key' => 'YOUR_API_KEY', 'email' => 'you@example.com', 'password' => 'YOUR_PASSWORD'];

function xst(string $endpoint, array $body): array
{
    $ch = curl_init(BASE . '/' . $endpoint);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(AUTH + $body),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json', 'Authorization: Bearer ' . TOKEN],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
    ]);
    $raw = curl_exec($ch);
    curl_close($ch);
    return json_decode((string)$raw, true) ?: ['error' => 'no_answer', 'message' => 'no answer from the server'];
}

/* What your tool read in Mi Assistant mode, exactly as the phone answered. */
$device = [
    'token'      => '8f21c0b4e9d7…',          // getmitoken:
    'deviceName' => 'fleur_global',           // getdevice:
    'version'    => 'OS2.0.207.0.VMTMIXM',    // getversion:
    'serial'     => 'fb4d921c',               // getsn:
    'codebase'   => '14',                     // getcodebase:
    'branch'     => 'F',                      // getbranch:
    'region'     => 'global',                 // getregion:
    'cpuid'      => '0x000460E1',             // getcpuid:  optional
];

$r = xst('token.php', [
    'soc'        => 'frp',
    'serverid'   => 'server1',                // the server that must run it
    'configblob' => base64_encode(json_encode($device)),
]);
if (isset($r['error'])) {
    exit("refused: {$r['error']} - {$r['message']}\n");     // nothing was created or charged
}
$rid = $r['data']['request_id'];
echo "request_id $rid\n";
echo "confirm it within {$r['data']['confirm_within']} seconds:  php status.php $rid\n";
send.py
"""1. Send a token request. Prints the request_id; nothing runs until you
   confirm it with status.py within 30 seconds."""
import base64, json, sys, time, requests

BASE  = "https://xiaomi.source.af/api/reseller/v1"
TOKEN = "rst_YOUR_ACCOUNT_TOKEN"
AUTH  = {"api_key": "YOUR_API_KEY", "email": "you@example.com", "password": "YOUR_PASSWORD"}

def xst(endpoint, body):
    try:
        r = requests.post(f"{BASE}/{endpoint}", json={**AUTH, **body},
                          headers={"Authorization": f"Bearer {TOKEN}"}, timeout=30)
        return r.json()
    except (requests.RequestException, ValueError):
        return {"error": "no_answer", "message": "no answer from the server"}

# What your tool read in Mi Assistant mode, exactly as the phone answered.
device = {
    "token":      "8f21c0b4e9d7…",          # getmitoken:
    "deviceName": "fleur_global",           # getdevice:
    "version":    "OS2.0.207.0.VMTMIXM",    # getversion:
    "serial":     "fb4d921c",               # getsn:
    "codebase":   "14",                     # getcodebase:
    "branch":     "F",                      # getbranch:
    "region":     "global",                 # getregion:
    "cpuid":      "0x000460E1",             # getcpuid:  optional
}

r = xst("token.php", {"soc": "frp", "serverid": "server1",      # the server that must run it
                      "configblob": base64.b64encode(json.dumps(device).encode()).decode()})
if "error" in r:
    sys.exit(f"refused: {r['error']} - {r.get('message')}")    # nothing was created or charged
rid = r["data"]["request_id"]
print("request_id", rid)
print(f"confirm it within {r['data']['confirm_within']} seconds:  python status.py {rid}")
Program.cs
// 1. Send a token request. Prints the request_id; nothing runs until you
//    confirm it with the status program within 30 seconds.
// .NET 6 or later: dotnet new console, then replace Program.cs with this file.
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json.Nodes;

const string BASE  = "https://xiaomi.source.af/api/reseller/v1";
const string TOKEN = "rst_YOUR_ACCOUNT_TOKEN";

var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", TOKEN);

async Task<JsonNode> Xst(string endpoint, JsonObject body)
{
    body["api_key"]  = "YOUR_API_KEY";
    body["email"]    = "you@example.com";
    body["password"] = "YOUR_PASSWORD";
    try
    {
        var res = await http.PostAsync($"{BASE}/{endpoint}",
            new StringContent(body.ToJsonString(), Encoding.UTF8, "application/json"));
        return JsonNode.Parse(await res.Content.ReadAsStringAsync())!;
    }
    catch (Exception)
    {
        return new JsonObject { ["error"] = "no_answer", ["message"] = "no answer from the server" };
    }
}

// What your tool read in Mi Assistant mode, exactly as the phone answered.
var device = new JsonObject
{
    ["token"]      = "8f21c0b4e9d7…",          // getmitoken:
    ["deviceName"] = "fleur_global",           // getdevice:
    ["version"]    = "OS2.0.207.0.VMTMIXM",    // getversion:
    ["serial"]     = "fb4d921c",               // getsn:
    ["codebase"]   = "14",                     // getcodebase:
    ["branch"]     = "F",                      // getbranch:
    ["region"]     = "global",                 // getregion:
    ["cpuid"]      = "0x000460E1",             // getcpuid:  optional
};
var blob = Convert.ToBase64String(Encoding.UTF8.GetBytes(device.ToJsonString()));

var r = await Xst("token.php", new JsonObject { ["soc"] = "frp", ["serverid"] = "server1", ["configblob"] = blob });
if (r["error"] is not null)
{
    Console.WriteLine($"refused: {r["error"]} - {r["message"]}");   // nothing was created or charged
    return;
}
var rid = (string)r["data"]!["request_id"]!;
Console.WriteLine($"request_id {rid}");
Console.WriteLine($"confirm it within {r["data"]!["confirm_within"]} seconds:  dotnet run -- {rid}");

2بررسی درخواست و گرفتن توکن

request_id را از برنامهٔ اول می‌گیرد. اولین فراخوانی آن به status.php کار را شروع می‌کند؛ سپس هر ۳ ثانیه می‌پرسد تا توکن بیاید — یا دلیل نیامدنش.

status.sh
#!/bin/sh
# 2. Confirm a request and follow it to the token:  sh status.sh WT-API-6AF684545B
#    The first call starts the job (within 30 seconds of send.sh).
BASE='https://xiaomi.source.af/api/reseller/v1'
TOKEN='rst_YOUR_ACCOUNT_TOKEN'
AUTH='"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD"'
post() { curl -s -X POST "$BASE/$1" -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" -d "{$AUTH$2}"; }
RID="${1:-WT-API-6AF684545B}"

while :; do
  ANSWER=$(post status.php ',"request_id":"'"$RID"'"')
  echo "$ANSWER"
  case "$ANSWER" in
    *'"state":"pending"'*|*'"state":"waiting"'*) sleep 3 ;;
    *) break ;;
  esac
done
# The last answer: "state":"done" with "response_token" -- write it to the phone --
# or "error" with the reason ("expired": send a new request).
status.php
<?php
/* 2. Confirm a request and follow it to the token:  php status.php WT-API-6AF684545B
      The first call starts the job (within 30 seconds of send.php). */
const BASE  = 'https://xiaomi.source.af/api/reseller/v1';
const TOKEN = 'rst_YOUR_ACCOUNT_TOKEN';
const AUTH  = ['api_key' => 'YOUR_API_KEY', 'email' => 'you@example.com', 'password' => 'YOUR_PASSWORD'];

function xst(string $endpoint, array $body): array
{
    $ch = curl_init(BASE . '/' . $endpoint);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(AUTH + $body),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json', 'Authorization: Bearer ' . TOKEN],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
    ]);
    $raw = curl_exec($ch);
    curl_close($ch);
    return json_decode((string)$raw, true) ?: ['error' => 'no_answer', 'message' => 'no answer from the server'];
}

$rid = $argv[1] ?? 'WT-API-6AF684545B';        // the request_id token.php gave you

for ($i = 0; $i < 100; $i++) {
    $r = xst('status.php', ['request_id' => $rid]);
    if (($r['error'] ?? '') === 'no_answer') { sleep(3); continue; }   // the network, not the job: ask again
    $state = $r['data']['state'] ?? 'error';
    if ($state !== 'pending' && $state !== 'waiting') { break; }
    echo "pending...\n";
    sleep((int)($r['data']['retry_after'] ?? 3));
}

if (($r['data']['state'] ?? '') === 'done') {
    $d = $r['data'];
    echo "token {$d['response_token']}\n";              // write this to the phone
    echo "from {$d['server_name']}, charged {$d['amount_charged']} {$d['currency']}, credit left {$d['credit']}\n";
} else {
    echo 'no token: ' . ($r['error'] ?? '?') . ' - ' . ($r['message'] ?? '') . "\n";
}
status.py
"""2. Confirm a request and follow it to the token:  python status.py WT-API-6AF684545B
   The first call starts the job (within 30 seconds of send.py)."""
import base64, json, sys, time, requests

BASE  = "https://xiaomi.source.af/api/reseller/v1"
TOKEN = "rst_YOUR_ACCOUNT_TOKEN"
AUTH  = {"api_key": "YOUR_API_KEY", "email": "you@example.com", "password": "YOUR_PASSWORD"}

def xst(endpoint, body):
    try:
        r = requests.post(f"{BASE}/{endpoint}", json={**AUTH, **body},
                          headers={"Authorization": f"Bearer {TOKEN}"}, timeout=30)
        return r.json()
    except (requests.RequestException, ValueError):
        return {"error": "no_answer", "message": "no answer from the server"}

rid = sys.argv[1] if len(sys.argv) > 1 else "WT-API-6AF684545B"     # the request_id token.php gave you

for _ in range(100):
    r = xst("status.php", {"request_id": rid})
    if r.get("error") == "no_answer":
        time.sleep(3)                    # the network, not the job: ask again
        continue
    if r.get("data", {}).get("state") not in ("pending", "waiting"):
        break
    print("pending...")
    time.sleep(r["data"].get("retry_after", 3))

d = r.get("data", {})
if d.get("state") == "done":
    print("token", d["response_token"])  # write this to the phone
    print("from", d["server_name"], "charged", d["amount_charged"], d["currency"], "credit left", d["credit"])
else:
    print("no token:", r.get("error"), "-", r.get("message"))
Program.cs
// 2. Confirm a request and follow it to the token:  dotnet run -- WT-API-6AF684545B
//    The first call starts the job (within 30 seconds of sending).
// .NET 6 or later: dotnet new console, then replace Program.cs with this file.
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json.Nodes;

const string BASE  = "https://xiaomi.source.af/api/reseller/v1";
const string TOKEN = "rst_YOUR_ACCOUNT_TOKEN";

var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", TOKEN);

async Task<JsonNode> Xst(string endpoint, JsonObject body)
{
    body["api_key"]  = "YOUR_API_KEY";
    body["email"]    = "you@example.com";
    body["password"] = "YOUR_PASSWORD";
    try
    {
        var res = await http.PostAsync($"{BASE}/{endpoint}",
            new StringContent(body.ToJsonString(), Encoding.UTF8, "application/json"));
        return JsonNode.Parse(await res.Content.ReadAsStringAsync())!;
    }
    catch (Exception)
    {
        return new JsonObject { ["error"] = "no_answer", ["message"] = "no answer from the server" };
    }
}

var rid = args.Length > 0 ? args[0] : "WT-API-6AF684545B";      // the request_id token.php gave you

JsonNode r = new JsonObject();
for (var i = 0; i < 100; i++)
{
    r = await Xst("status.php", new JsonObject { ["request_id"] = rid });
    if ((string?)r["error"] == "no_answer") { await Task.Delay(3000); continue; }   // the network: ask again
    var state = (string?)r["data"]?["state"];
    if (state != "pending" && state != "waiting") break;
    Console.WriteLine("pending...");
    await Task.Delay(3000);
}

var d = r["data"];
if ((string?)d?["state"] == "done")
{
    Console.WriteLine($"token {d!["response_token"]}");   // write this to the phone
    Console.WriteLine($"from {d["server_name"]}, charged {d["amount_charged"]} {d["currency"]}, credit left {d["credit"]}");
}
else
{
    Console.WriteLine($"no token: {r["error"]} - {r["message"]}");
}

3تاریخچهٔ کارهای شما

کارهای شما را میان دو روز، برای یک سرویس فهرست می‌کند: چند تا فرستادید، هر کدام چطور تمام شد، و هزینه‌شان.

history.sh
#!/bin/sh
# 3. Your job history: the FRP jobs sent from 8 to 9 October, newest first.
BASE='https://xiaomi.source.af/api/reseller/v1'
TOKEN='rst_YOUR_ACCOUNT_TOKEN'
AUTH='"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD"'
post() { curl -s -X POST "$BASE/$1" -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" -d "{$AUTH$2}"; }

post history.php ',"from":"2026-10-08","to":"2026-10-09","soc":"frp","limit":20'
echo
history.php
<?php
/* 3. Your job history: the FRP jobs sent from 8 to 9 October, newest first. */
const BASE  = 'https://xiaomi.source.af/api/reseller/v1';
const TOKEN = 'rst_YOUR_ACCOUNT_TOKEN';
const AUTH  = ['api_key' => 'YOUR_API_KEY', 'email' => 'you@example.com', 'password' => 'YOUR_PASSWORD'];

function xst(string $endpoint, array $body): array
{
    $ch = curl_init(BASE . '/' . $endpoint);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(AUTH + $body),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json', 'Authorization: Bearer ' . TOKEN],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
    ]);
    $raw = curl_exec($ch);
    curl_close($ch);
    return json_decode((string)$raw, true) ?: ['error' => 'no_answer', 'message' => 'no answer from the server'];
}

$r = xst('history.php', ['from' => '2026-10-08', 'to' => '2026-10-09', 'soc' => 'frp', 'limit' => 20]);
if (isset($r['error'])) { exit("refused: {$r['error']} - {$r['message']}\n"); }

$d = $r['data'];
echo "{$d['total']} requests: {$d['counts']['done']} done, {$d['counts']['error']} failed, "
   . "{$d['counts']['expired']} expired; spent {$d['spent']} {$d['currency']}\n";
foreach ($d['jobs'] as $j) {
    printf("#%-9s %s %s %-10s %-8s %-6s %s\n", $j['request_id'], $j['created_at'], strtoupper($j['soc']),
           $j['server_name'], $j['state'], $j['amount'], $j['error'] ?? '');
}
history.py
"""3. Your job history: the FRP jobs sent from 8 to 9 October, newest first."""
import base64, json, sys, time, requests

BASE  = "https://xiaomi.source.af/api/reseller/v1"
TOKEN = "rst_YOUR_ACCOUNT_TOKEN"
AUTH  = {"api_key": "YOUR_API_KEY", "email": "you@example.com", "password": "YOUR_PASSWORD"}

def xst(endpoint, body):
    try:
        r = requests.post(f"{BASE}/{endpoint}", json={**AUTH, **body},
                          headers={"Authorization": f"Bearer {TOKEN}"}, timeout=30)
        return r.json()
    except (requests.RequestException, ValueError):
        return {"error": "no_answer", "message": "no answer from the server"}

r = xst("history.php", {"from": "2026-10-08", "to": "2026-10-09", "soc": "frp", "limit": 20})
if "error" in r:
    sys.exit(f"refused: {r['error']} - {r.get('message')}")

d = r["data"]
c = d["counts"]
print(f"{d['total']} requests: {c['done']} done, {c['error']} failed, {c['expired']} expired; spent {d['spent']} {d['currency']}")
for j in d["jobs"]:
    print(f"#{j['request_id']:<9} {j['created_at']} {j['soc'].upper()} {j['server_name']:<10} {j['state']:<8} {j['amount']:<6} {j['error'] or ''}")
Program.cs
// 3. Your job history: the FRP jobs sent from 8 to 9 October, newest first.
// .NET 6 or later: dotnet new console, then replace Program.cs with this file.
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json.Nodes;

const string BASE  = "https://xiaomi.source.af/api/reseller/v1";
const string TOKEN = "rst_YOUR_ACCOUNT_TOKEN";

var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", TOKEN);

async Task<JsonNode> Xst(string endpoint, JsonObject body)
{
    body["api_key"]  = "YOUR_API_KEY";
    body["email"]    = "you@example.com";
    body["password"] = "YOUR_PASSWORD";
    try
    {
        var res = await http.PostAsync($"{BASE}/{endpoint}",
            new StringContent(body.ToJsonString(), Encoding.UTF8, "application/json"));
        return JsonNode.Parse(await res.Content.ReadAsStringAsync())!;
    }
    catch (Exception)
    {
        return new JsonObject { ["error"] = "no_answer", ["message"] = "no answer from the server" };
    }
}

var r = await Xst("history.php", new JsonObject { ["from"] = "2026-10-08", ["to"] = "2026-10-09", ["soc"] = "frp", ["limit"] = 20 });
if (r["error"] is not null) { Console.WriteLine($"refused: {r["error"]} - {r["message"]}"); return; }

var d = r["data"]!;
var c = d["counts"]!;
Console.WriteLine($"{d["total"]} requests: {c["done"]} done, {c["error"]} failed, {c["expired"]} expired; spent {d["spent"]} {d["currency"]}");
foreach (var j in d["jobs"]!.AsArray())
    Console.WriteLine($"#{j!["request_id"],-9} {j["created_at"]} {((string)j["soc"]!).ToUpper()} {j["server_name"],-10} {j["state"],-8} {j["amount"],-6} {j["error"]}");

4کردیت شما

کردیت شما، هزینه‌ای که برای FRP و FDL کرده‌اید، و قیمت شما روی هر سرور را چاپ می‌کند.

balance.sh
#!/bin/sh
# 4. Your credit, what you spent on FRP and FDL, and your price on each server.
BASE='https://xiaomi.source.af/api/reseller/v1'
TOKEN='rst_YOUR_ACCOUNT_TOKEN'
AUTH='"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD"'
post() { curl -s -X POST "$BASE/$1" -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" -d "{$AUTH$2}"; }

post balance.php ''
echo
balance.php
<?php
/* 4. Your credit, what you spent on FRP and FDL, and your price on each server. */
const BASE  = 'https://xiaomi.source.af/api/reseller/v1';
const TOKEN = 'rst_YOUR_ACCOUNT_TOKEN';
const AUTH  = ['api_key' => 'YOUR_API_KEY', 'email' => 'you@example.com', 'password' => 'YOUR_PASSWORD'];

function xst(string $endpoint, array $body): array
{
    $ch = curl_init(BASE . '/' . $endpoint);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(AUTH + $body),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json', 'Authorization: Bearer ' . TOKEN],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
    ]);
    $raw = curl_exec($ch);
    curl_close($ch);
    return json_decode((string)$raw, true) ?: ['error' => 'no_answer', 'message' => 'no answer from the server'];
}

$r = xst('balance.php', []);
if (isset($r['error'])) { exit("refused: {$r['error']} - {$r['message']}\n"); }

$d = $r['data'];
$u = $d['usage'];
echo "credit {$d['credit']} {$d['currency']}\n";
echo "spent {$u['spent']}: FRP {$u['spent_frp']}, FDL {$u['spent_fdl']}\n";
foreach ($d['prices'] as $soc => $servers) {
    foreach ($servers as $s) {
        printf("  %s %-10s %-12s %-7s %s\n", strtoupper($soc), $s['serverid'], $s['name'], $s['online'] ? 'online' : 'offline', $s['price']);
    }
}
balance.py
"""4. Your credit, what you spent on FRP and FDL, and your price on each server."""
import base64, json, sys, time, requests

BASE  = "https://xiaomi.source.af/api/reseller/v1"
TOKEN = "rst_YOUR_ACCOUNT_TOKEN"
AUTH  = {"api_key": "YOUR_API_KEY", "email": "you@example.com", "password": "YOUR_PASSWORD"}

def xst(endpoint, body):
    try:
        r = requests.post(f"{BASE}/{endpoint}", json={**AUTH, **body},
                          headers={"Authorization": f"Bearer {TOKEN}"}, timeout=30)
        return r.json()
    except (requests.RequestException, ValueError):
        return {"error": "no_answer", "message": "no answer from the server"}

r = xst("balance.php", {})
if "error" in r:
    sys.exit(f"refused: {r['error']} - {r.get('message')}")

d = r["data"]
u = d["usage"]
print("credit", d["credit"], d["currency"])
print(f"spent {u['spent']}: FRP {u['spent_frp']}, FDL {u['spent_fdl']}")
for soc, servers in d["prices"].items():
    for s in servers:
        print(f"  {soc.upper()} {s['serverid']:<10} {s['name']:<12} {'online' if s['online'] else 'offline':<7} {s['price']}")
Program.cs
// 4. Your credit, what you spent on FRP and FDL, and your price on each server.
// .NET 6 or later: dotnet new console, then replace Program.cs with this file.
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json.Nodes;

const string BASE  = "https://xiaomi.source.af/api/reseller/v1";
const string TOKEN = "rst_YOUR_ACCOUNT_TOKEN";

var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", TOKEN);

async Task<JsonNode> Xst(string endpoint, JsonObject body)
{
    body["api_key"]  = "YOUR_API_KEY";
    body["email"]    = "you@example.com";
    body["password"] = "YOUR_PASSWORD";
    try
    {
        var res = await http.PostAsync($"{BASE}/{endpoint}",
            new StringContent(body.ToJsonString(), Encoding.UTF8, "application/json"));
        return JsonNode.Parse(await res.Content.ReadAsStringAsync())!;
    }
    catch (Exception)
    {
        return new JsonObject { ["error"] = "no_answer", ["message"] = "no answer from the server" };
    }
}

var r = await Xst("balance.php", new JsonObject());
if (r["error"] is not null) { Console.WriteLine($"refused: {r["error"]} - {r["message"]}"); return; }

var d = r["data"]!;
var u = d["usage"]!;
Console.WriteLine($"credit {d["credit"]} {d["currency"]}");
Console.WriteLine($"spent {u["spent"]}: FRP {u["spent_frp"]}, FDL {u["spent_fdl"]}");
foreach (var (soc, servers) in d["prices"]!.AsObject())
    foreach (var s in servers!.AsArray())
        Console.WriteLine($"  {soc.ToUpper()} {s!["serverid"],-10} {s["name"],-12} {((bool)s["online"]! ? "online" : "offline"),-7} {s["price"]}");

5سرورها

سرورهایی را که می‌توانید استفاده کنید، قیمت شما روی هر کدام، و اینکه همین حالا کار می‌گیرد یا نه، فهرست می‌کند.

servers.sh
#!/bin/sh
# 5. The servers you may use, your price on each, and whether they take jobs now.
BASE='https://xiaomi.source.af/api/reseller/v1'
TOKEN='rst_YOUR_ACCOUNT_TOKEN'
AUTH='"api_key":"YOUR_API_KEY","email":"you@example.com","password":"YOUR_PASSWORD"'
post() { curl -s -X POST "$BASE/$1" -H 'Content-Type: application/json' -H "Authorization: Bearer $TOKEN" -d "{$AUTH$2}"; }

post servers.php ''
echo
servers.php
<?php
/* 5. The servers you may use, your price on each, and whether they take jobs now. */
const BASE  = 'https://xiaomi.source.af/api/reseller/v1';
const TOKEN = 'rst_YOUR_ACCOUNT_TOKEN';
const AUTH  = ['api_key' => 'YOUR_API_KEY', 'email' => 'you@example.com', 'password' => 'YOUR_PASSWORD'];

function xst(string $endpoint, array $body): array
{
    $ch = curl_init(BASE . '/' . $endpoint);
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => json_encode(AUTH + $body),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json', 'Authorization: Bearer ' . TOKEN],
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 30,
    ]);
    $raw = curl_exec($ch);
    curl_close($ch);
    return json_decode((string)$raw, true) ?: ['error' => 'no_answer', 'message' => 'no answer from the server'];
}

$r = xst('servers.php', []);
if (isset($r['error'])) { exit("refused: {$r['error']} - {$r['message']}\n"); }

foreach ($r['data']['services'] as $soc => $svc) {
    echo strtoupper($soc) . " -- without serverid: {$svc['price']}\n";
    foreach ($svc['providers'] as $s) {
        printf("  %-10s %-12s %-7s %s %s\n", $s['serverid'], $s['name'], $s['online'] ? 'online' : 'offline', $s['price'], $s['currency']);
    }
}
servers.py
"""5. The servers you may use, your price on each, and whether they take jobs now."""
import base64, json, sys, time, requests

BASE  = "https://xiaomi.source.af/api/reseller/v1"
TOKEN = "rst_YOUR_ACCOUNT_TOKEN"
AUTH  = {"api_key": "YOUR_API_KEY", "email": "you@example.com", "password": "YOUR_PASSWORD"}

def xst(endpoint, body):
    try:
        r = requests.post(f"{BASE}/{endpoint}", json={**AUTH, **body},
                          headers={"Authorization": f"Bearer {TOKEN}"}, timeout=30)
        return r.json()
    except (requests.RequestException, ValueError):
        return {"error": "no_answer", "message": "no answer from the server"}

r = xst("servers.php", {})
if "error" in r:
    sys.exit(f"refused: {r['error']} - {r.get('message')}")

for soc, svc in r["data"]["services"].items():
    print(f"{soc.upper()} -- without serverid: {svc['price']}")
    for s in svc["providers"]:
        print(f"  {s['serverid']:<10} {s['name']:<12} {'online' if s['online'] else 'offline':<7} {s['price']} {s['currency']}")
Program.cs
// 5. The servers you may use, your price on each, and whether they take jobs now.
// .NET 6 or later: dotnet new console, then replace Program.cs with this file.
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json.Nodes;

const string BASE  = "https://xiaomi.source.af/api/reseller/v1";
const string TOKEN = "rst_YOUR_ACCOUNT_TOKEN";

var http = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", TOKEN);

async Task<JsonNode> Xst(string endpoint, JsonObject body)
{
    body["api_key"]  = "YOUR_API_KEY";
    body["email"]    = "you@example.com";
    body["password"] = "YOUR_PASSWORD";
    try
    {
        var res = await http.PostAsync($"{BASE}/{endpoint}",
            new StringContent(body.ToJsonString(), Encoding.UTF8, "application/json"));
        return JsonNode.Parse(await res.Content.ReadAsStringAsync())!;
    }
    catch (Exception)
    {
        return new JsonObject { ["error"] = "no_answer", ["message"] = "no answer from the server" };
    }
}

var r = await Xst("servers.php", new JsonObject());
if (r["error"] is not null) { Console.WriteLine($"refused: {r["error"]} - {r["message"]}"); return; }

foreach (var (soc, svc) in r["data"]!["services"]!.AsObject())
{
    Console.WriteLine($"{soc.ToUpper()} -- without serverid: {svc!["price"]}");
    foreach (var s in svc["providers"]!.AsArray())
        Console.WriteLine($"  {s!["serverid"],-10} {s["name"],-12} {((bool)s["online"]! ? "online" : "offline"),-7} {s["price"]} {s["currency"]}");
}

چیزی کار نمی‌کند؟

request_id و کد error را برای ما بفرستید. با همین دو تا دقیقاً می‌بینیم بر سر آن کار چه آمده؛ بدون آن‌ها فقط حدس می‌زنیم.

Xiaomi Source Tool · API توکن · 2026-10-27