01چطور کار میکند
شما گوشی را با ابزار خودتان میخوانید و آنچه خواندید را میفرستید. همان لحظه یک request_id میگیرید. آن را به status.php برمیگردانید و همین، کار را روی سروری که انتخاب کردهاید شروع میکند؛ همان فراخوانی بعد از آن میگوید کار در چه حالی است و توکن آنلاک را برای نوشتن روی گوشی به شما میدهد. ما هرگز به گوشی دست نمیزنیم و شما هرگز با سرور سروکار ندارید.
token.php همه چیز را بررسی میکند و همان لحظه با یک request_id مثل WT-API-6AF684545B پاسخ میدهد. هنوز چیزی به هیچ سروری فرستاده نشده و چیزی کسر نشده است.
request_id را به status.php بفرستید. همین اولین فراخوانی رسید شماست: کار فقط از این لحظه شروع میشود. request_idای که در ۳۰ ثانیه تأیید نشود لغو میشود.
هر چند ثانیه دوباره از 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 — در بدنه، روی هر درخواست. |
| ایمیل — آدرس روی حساب شما. اگر عوض شد به ما بگویید، وگرنه فراخوانیها متوقف میشوند. | |
| password | رمز API — رمز API حساب شما. بهطور پیشفرض همان رمز ورود شماست. اگر رمز جداگانهای میخواهید، در پنلتان از حساب کاربری ← رمز API تنظیمش کنید؛ با دکمهٔ استفاده از رمز ورود من به حالت قبل برمیگردید و رمز جداگانه همان لحظه از کار میافتد. ما هم میتوانیم آن را برایتان تنظیم کنیم. در هر حال، هرگز در لاگهای ما نوشته نمیشود و هرگز همراه کار ذخیره نمیشود. |
هر اندپوینت POST روی HTTPS است. GET با method_not_allowed رد میشود؛ بدنهای که JSON نباشد با bad_json.
03درخواست
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_key | string | بله | کلید API شما. |
| string | بله | ایمیل روی حساب شما. | |
| password | string | بله | رمز API شما — بهطور پیشفرض همان رمز ورود شما، مگر اینکه در پنلتان از حساب کاربری ← رمز API رمز جداگانهای گذاشته باشید. به اعتبارنامهها نگاه کنید. |
| soc | string | بله | کدام سرویس. frp یعنی حذف FRP، fdl یعنی Fastboot به EDL. پیشفرض ندارد — نفرستادنش خطاست، نه حدسی که میتواند بابت سرویس اشتباه از شما پول بگیرد. |
| configblob | string | بله | خوانش کامل گوشی، بهصورت base64 یک آبجکت JSON. اینکه چه چیزهایی باید در آن باشد به soc بستگی دارد — به بلاب دستگاه نگاه کنید. |
| serverid | string | خیر | شناسهٔ عمومی سروری که باید کار را انجام دهد، مثلاً server1 — از servers.php، یا از بخش سرورها در پنلتان. سختگیرانه است: یا همان سرور کار را انجام میدهد، یا درخواست با ذکر دلیل رد میشود. اگر نفرستید، ارزانترین سروری را که کار میگیرد انتخاب میکنیم. صاحبان ابزار: همیشه آن را بفرستید. به انتخاب سرور نگاه کنید. |
| request_date | string | خیر | اختیاری. اینکه سرور شما چه زمانی این درخواست را فرستاده، ISO-8601 با Z یا آفست. دستنخورده در client_sent برگردانده میشود و هرگز در محاسبات ما به کار نمیرود. اگر نفرستید چیزی عوض نمیشود، جز اینکه client_sent و client_clock_offset_seconds با مقدار null برمیگردند. |
| request_language | string | خیر | اختیاری. زبانِ 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 (سایدلود / ریکاوری)
| فیلد | خواندن با | الزامی | چیست | نمونه |
|---|---|---|---|---|
| token | getmitoken: | بله — null رد میشود | چالش FRP، دقیقاً همانطور که خوانده شد | 8f21c0b4e9d7… |
| deviceName | getdevice: | بله — null رد میشود | کدنام همراه با پسوند منطقه | fleur_global |
| version | getversion: | بله — null رد میشود | بیلد رام | OS2.0.207.0.VMTMIXM |
| serial | getsn: | بله — null رد میشود | شمارهٔ سریال | fb4d921c |
| codebase | getcodebase: | بله — اگر خوانده نشد null | نسخهٔ اندروید | 15 |
| region | getregion: | بله — اگر خوانده نشد null | منطقهٔ رام | IR |
| cpuid | getcpuid: | بله — اگر خوانده نشد null | شناسهٔ CPU، اگر گوشی جواب دهد | 0x000460E1 |
| recovery | getrecoveryversion: | بله — اگر خوانده نشد null | نسخهٔ ریکاوری — فقط فهرست دستگاههای پشتیبانینشدهٔ ما آن را میخواند | 2 |
| branch | getbranch: | خیر — null مشکلی ندارد | شاخهٔ رام | F |
| language | getlanguage: | خیر — null مشکلی ندارد | زبان دستگاه — فقط فهرست دستگاههای پشتیبانینشدهٔ ما آن را میخواند | fa |
| romzone | getromzone: | خیر — null مشکلی ندارد | ROM Zone — فقط فهرست دستگاههای پشتیبانینشدهٔ ما آن را میخواند | 2 |
{
"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
| فیلد | خواندن با | الزامی | چیست | نمونه |
|---|---|---|---|---|
| token | oem get_token (getvar:token) | بله — null رد میشود | توکن فستبوت، دقیقاً همانطور که خوانده شد | VQHzN2Ib… |
| product | getvar:product | بله — null رد میشود | کدنام، بدون منطقه | fleur |
| serial | getvar:serialno | بله — null رد میشود | شمارهٔ سریال | fb4d921c |
| cpuid | getvar:cpuid | بله — اگر خوانده نشد null | شناسهٔ CPU، اگر گوشی جواب دهد | 0x000460E1 |
{
"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 در نظر گرفته میشود و کار ادامه پیدا میکند.
{
"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 میگیرد.
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 هیچ چیزی در آنچه میفرستید عوض نمیشود.
چه میفرستید و چه میگیرید:
| شما میفرستید | ما برمیگردانیم | معنی |
|---|---|---|
| deviceName | device_name | کدنام همراه با پسوند منطقه (frp) |
| — | product_model | کدنام، بدون منطقه — خودمان آن را از deviceName درمیآوریم (frp) |
| product | product_model device_name | کدنام، بدون منطقه (fdl) |
| version | device_version | بیلد رام (frp) |
| serial | serial_number | شمارهٔ سریال |
| codebase | codebase | نسخهٔ اندروید (frp) |
| branch | branch | شاخهٔ رام (frp) |
| region | region | منطقهٔ رام (frp) |
| cpuid | cpu_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 را نفرستید تا ما انتخاب کنیم.
{ "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 405bad_json 400body_too_large 413 |
| 2 | هر چهار اعتبارنامهٔ شما یک حساب فعال را نشان میدهند: توکن حساب، api_key، email و password. | unauthorized 401too_many_failures 429 |
| 3 | درخواست از نشانیای میآید که در فهرست IPهای مجاز حساب شماست، اگر فهرستی گذاشته باشید. | ip_not_allowed 403 |
| 4 | از سقف تعداد درخواست در ساعت عبور نکردهاید. | rate_limited 429 |
| حساب به خاطر ارسال پشتسرهمِ یک دستگاه پشتیبانینشده محدود نشده باشد (به دستگاههای پشتیبانیشده نگاه کنید). | account_restricted 403 | |
| 5 | soc برابر frp یا fdl است، این سرویس به حساب شما فروخته میشود، و روشن است. | missing_soc 400bad_service 400not_entitled 403disabled 503 |
| 6 | configblob معتبر است و خواندن کاملی را که حالت گوشی لازم دارد در خود دارد. | missing_configblob 400bad_configblob 400missing_token 400incomplete_configblob 400 |
| 7 | دستگاه در فهرست دستگاههایی که سرویس نمیدهیم نیست. | unsupported 422 |
| 8 | سروری که در serverid نام بردید وجود دارد، برای حساب شما فعال است، و همین حالا کار میگیرد: روشن، با قیمت مشخص، آنلاین و از سمت ما آماده. | unknown_serverid 404server_not_allowed 403server_offline 503 |
| سروری نام نبردید: ارزانترین سروری را که کار میگیرد و حساب شما اجازهٔ استفاده از آن را دارد برمیداریم، و پاسخ نامش را میآورد. | service_not_allowed 403service_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، همهجا هنوز کار میکند و با همان شکل پاسخ داده میشود.
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. کار را با آن تأیید کنید، دنبال کنید و تحویل بگیرید، و در هر سؤالی دربارهٔ آن، همین را به ما بگویید. |
| state | waiting |
| confirm_within | ثانیههای باقیمانده برای تأیید آن با status.php. |
| price | هزینهٔ این کار برای شما روی همان سرور — هنگام شروع نگه داشته میشود و فقط اگر توکن بیاید کسر میشود. |
| serverid | شناسهٔ عمومی سروری که کار را انجام داد — همان serverid که خودتان میتوانید بفرستید. |
| server_name | نام عمومی همان سرور، مثلاً Server 1. |
همین دستگاه — همان توکن دستگاه، برای همان سرویس و همان سرور — در ۳۰ دقیقهٔ گذشته فرستاده نشده باشد. اگر فرستاده شده و آن کار شروع شده، همان کار را پس میگیرید: request_id و وضعیتش، یا توکنش — هرگز کار دوم یا کسر دوم. کاری که شکست خورده، یا request_idاش هرگز تأیید نشده، با یک کار تازه جایگزین میشود.
09تأیید و پیگیری
request_id را با همان چهار اعتبارنامه به status.php بفرستید. اولین فراخوانی در ۳۰ ثانیه کار را شروع میکند و همان لحظه pending پاسخ میدهد؛ پس از آن هر retry_after ثانیه دوباره بپرسید تا state دیگر pending نباشد. یک کار معمولاً ۱۵ تا ۲۵ ثانیه طول میکشد.
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 | یعنی چه، و چه کار کنید |
|---|---|---|
pending | 202 | کار نزد سرور است. پس از retry_after ثانیه دوباره بپرسید. |
done | 200 | توکن در response_token است: آن را روی گوشی بنویسید. هزینهٔ کار کسر شده؛ پاسخ مبلغ و کردیت باقیماندهٔ شما را میگوید. |
error | 4xx · 5xx | توکنی نیامد. error دلیلش را میگوید — server_offline، unsupported، server_unavailable، failed یا no_credit. مبلغ کامل به کردیت شما برمیگردد، مگر وقتی سرور بگوید این دستگاه را پشتیبانی نمیکند (unsupported): هزینهٔ آن کار کسر میشود، همانطور که amount_charged نشان میدهد. |
expired | 410 | در ۳۰ ثانیه تأیید نشد: لغو شد، چیزی فرستاده نشد، چیزی کسر نشد. درخواست را دوباره بفرستید تا request_id تازه بگیرید. |
not_found | 404 | هیچ درخواستی با این request_id به حساب شما تعلق ندارد. |
توکن همراه کار، روی سرور ما نگه داشته میشود. اگر پاسخی هرگز به دستتان نرسید، با همان request_id دوباره از status.php بپرسید: تا وقتی کار در جریان است pending میگیرید و وقتی تمام شد توکن را — هر چند بار که بپرسید، بدون هزینهٔ اضافه. کاری که شکست خورده دلیلش را میگوید.
# 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 | دستگاه، باز شده. همیشه هست. |
| state | waiting، pending، done، error یا expired. |
| response_token | توکن آنلاک. همین را روی گوشی مینویسید. |
| provider_ref | شمارهٔ کار خود سرور، به درد پیگیری میخورد. |
| amount_charged | این کار چقدر برای شما تمام شد. |
| credit | کردیت شما بعد از کسر. |
| currency | واحد پول هر دو عدد. |
یک خطا
# 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_imei | IMEI را در پایگاه دادهٔ سازنده جستوجو میکند. | imei — پانزده رقم IMEI | ۱ تا ۵ دقیقه؛ poll کنید |
| read_lockcode | رکورد دستگاه پشتِ یک lock code را برمیگرداند. | imei — IMEI برای ثبت سفارش | چند دقیقه؛ poll کنید |
این خواندنها فقط برای حسابهای «صاحب ابزار» است. read_imei فقط وقتی فهرست میشود که برای API باز باشد؛ در غیر این صورت داخل ابزار XST در دسترس است.
فرستادن یک خواندن
یک خواندن دقیقاً مثل frp و fdl فرستاده و بررسی میشود: token.php یک request_id میدهد، نخستین فراخوان status.php آن را آغاز میکند و تا done شدن poll میکنید. هیچ سروری گرفته نمیشود و هزینهٔ سرور ندارد.
# 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 پاسخ میدهد — اطلاعات دستگاه بهصورت جفتهای برچسب/مقدار. برچسبها به سرویس بستگی دارند؛ فیلدی که منبع خالی گذاشته باشد حذف میشود.
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: 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: 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تاریخچهٔ کارهای شما
کارهای شما، از جدید به قدیم: هر کدام کی فرستاده شد، به کدام سرور، و چطور تمام شد — بر اساس تاریخ و سرویس. همان چهار اعتبارنامه؛ کردیتی مصرف نمیکند و از سهمیهٔ ساعتی شما حساب میشود.
| فیلد | نوع | الزامی | چیست |
|---|---|---|---|
| from | string | خیر | یک روز، 2026-10-08 (یا 2026-Oct-08)، به وقت UTC: کارهایی که در آن روز یا بعد از آن فرستاده شدهاند. |
| to | string | خیر | یک روز: کارهایی که در آن روز یا پیش از آن فرستاده شدهاند، با کل همان روز. |
| soc | string | خیر | frp یا fdl: فقط کارهای همان سرویس. |
| limit | number | خیر | تعداد کارهایی که فهرست میشوند، از ۱ تا ۱۰۰. پیشفرض ۱. |
| before | string | خیر | یک request_id: کارهای قدیمیتر از آن. next_before هر پاسخ را بفرستید تا صفحهٔ بعد را بگیرید. |
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کردیت و مصرف
چقدر کردیت مانده و بقیه کجا خرج شده: همان اعداد کارتهای بالای پنل شما. همان چهار اعتبارنامهٔ درخواست توکن را میگیرد، کردیتی مصرف نمیکند و هر ۱۰ ثانیه یک بار پاسخ میدهد.
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سرورها و قیمتها
همان چهار اعتبارنامهٔ درخواست توکن را میگیرد و کردیتی مصرف نمیکند. هر فراخوانی از سهمیهٔ ساعتی شما حساب میشود.
چه چیزی میتوانید استفاده کنید و هر کار چقدر برایتان تمام میشود.
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کدام سرورها یک دستگاه را میپذیرند
یک بررسی خشک: همان اعتبارنامهها و همان بدنهٔ token.php (soc، configblob)، همان بررسیهای configblob و همان خطاها — و بعد هیچ: نه request_idای، نه کاری، نه رزرو یا کسری، نه ارسالی به هیچ سروری. بعضی سرورها بعضی دستگاهها را نمیپذیرند (یک بیلد، یک کشور…)؛ این فراخوانی برای همین دستگاه میگوید کدام سرورهای شما آن را میپذیرند. محدودیت جدای خودش را دارد، ۶۰ فراخوانی در دقیقه، و از سهمیهٔ ساعتی شما کم نمیکند.
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 | یعنی چه، و چه کار کنید |
|---|---|---|
| unauthorized | 401 | یکی از چهار اعتبارنامه غلط است، یا حساب غیرفعال است. عمداً نمیگوییم کدام. |
| ip_not_allowed | 403 | هر چهار اعتبارنامه درست است، اما درخواست از نشانیای آمده که در فهرست IPهای مجاز حساب شما نیست. پاسخ آن را در ip نام میبرد. آن را در پنل خودتان (حساب ← IPهای مجاز) اضافه کنید، یا از یک نشانی مجاز بفرستید. هیچ کاری انجام نشد و هزینهای کسر نشد. |
| too_many_failures | 429 | تلاشهای ناموفق زیاد از آدرس شما. صبر کنید و پیش از تلاش دوباره اعتبارنامه را درست کنید. |
| rate_limited | 429 | از یک محدودیت عبور کردید: سهمیهٔ ساعتی شما (token.php، history.php، balance.php، servers.php) یا ۱۲۰ بررسی وضعیت در دقیقه. پاسخ limit، used و per را دارد. |
| too_soon | 429 | balance.php زودتر از ۱۰ ثانیه دوباره پرسیده شد. پاسخ میگوید چند ثانیه صبر کنید (retry_after و هدر Retry-After)؛ هیچ چیزی مسدود نمیشود. |
| method_not_allowed | 405 | از GET استفاده کردهاید. همهٔ اندپوینتها POST هستند. |
| bad_json | 400 | بدنه آبجکت JSON نبود. Content-Type: application/json بگذارید. |
| body_too_large | 413 | بدنه بیش از ۲۵۶ کیلوبایت است. |
| missing_soc | 400 | soc فرستاده نشد. عمداً پیشفرض ندارد. |
| bad_service | 400 | soc باید دقیقاً frp یا fdl باشد. |
| not_entitled | 403 | آن سرویس به حساب شما فروخته نشده. از ما بخواهید فعال کنیم. |
| disabled | 503 | آن سرویس را همین حالا خاموش کردهایم. موقتی است. |
| missing_configblob | 400 | configblob فرستاده نشد. |
| bad_configblob | 400 | configblob نه base64 درست است نه آبجکت JSON درست. |
| missing_token | 400 | token دستگاه داخل بلاب نیست. |
| incomplete_configblob | 400 | فیلدی که سرورها لازم دارند فرستاده نشده (missing)، null فرستاده شده (nulls) یا خوانشی ناموفق دارد (invalid)؛ mode حالتی است که گوشی باید در آن باشد. گوشی را دوباره بخوانید و اطلاعات کامل را بفرستید؛ چیزی کسر نشد. |
| use_serverid | 400 | شما services یا server_id را فرستادید، روش قدیمی انتخاب سرور بر اساس جایگاهش. دیگر پذیرفته نمیشود: serverid را بفرستید (از servers.php)، یا نفرستید تا ما انتخاب کنیم. |
| use_status | 400 | یک request_id به token.php فرستادید، که فقط درخواست تازه شروع میکند. request_id را به status.php بفرستید. |
| unknown_serverid | 404 | هیچ سروری این serverid را ندارد. فهرست را از servers.php یا از بخش سرورها در پنلتان بگیرید. |
| server_not_allowed | 403 | سروری که نام بردید برای حساب شما فعال نیست. شما را به سرور دیگری منتقل نمیکنیم: یکی از فهرست خودتان انتخاب کنید، یا serverid را نفرستید. |
| service_not_allowed | 403 | سروری نام نبردید و هیچ سروری برای حساب شما فعال نیست. از ما بخواهید یکی را فعال کنیم. |
| server_offline | 503 | سروری که نام بردید همین حالا نمیتواند این سرویس را بگیرد: خاموش است، آفلاین است، یا از سمت ما آماده نیست. token.php پیش از دادن request_id آن را بررسی میکند و کار هنگام شروع دوباره بررسیاش میکند؛ اگر در این فاصله یا هنگام اجرای کار خاموش شده باشد، مبلغ رزروشده برمیگردد. چیزی کسر نشد. از سرور دیگری از servers.php استفاده کنید، یا بعداً دوباره امتحان کنید. |
| service_offline | 503 | سروری نام نبردید و همین حالا هیچ سروری برای این سرویس کار نمیگیرد. چیزی کسر نشد. کمی بعد دوباره بفرستید. |
| no_credit | 402 | کردیت برای یک کار روی آن سرور کافی نیست — یا token.php پیش از دادن request_id رد کرده، یا اگر کردیت شما در این فاصله کم شده، هنگام شروع کار. چیزی کسر نشد. حساب را شارژ کنید، یا سرور ارزانتری انتخاب کنید. |
| bad_imei | 400 | imei نبود یا نامعتبر بود: read_imei به پانزده رقم IMEI نیاز دارد؛ read_lockcode به IMEI برای ثبت سفارش نیاز دارد. |
| read_failed | 502 | یک خواندن (read_sideload یا read_fastboot یا read_imei یا read_lockcode) کامل نشد. چیزی کسر نشد. دوباره بفرستید یا بعداً تلاش کنید. |
| missing_request_id | 400 | status.php بدون request_id فراخوانده شد. |
| not_found | 404 | هیچ درخواستی با این request_id به حساب شما تعلق ندارد. |
| request_expired | 410 | request_id در ۳۰ ثانیه با status.php تأیید نشد، پس لغو شد. چیزی فرستاده یا کسر نشد. درخواست را دوباره به token.php بفرستید تا request_id تازه بگیرید. |
| unsupported | 422 | این دستگاه قابل سرویس نیست. اگر در فهرست دستگاههایی باشد که سرویس نمیدهیم، token.php آن را رد میکند: نه request_idای داده میشود و نه چیزی کسر میشود. اگر سروری که انتخاب کردید بگوید این دستگاه را پشتیبانی نمیکند، هزینهٔ کار کسر میشود و بازگردانده نمیشود — پیش از ارسال از ما بپرسید کدام بیلدها و کشورها پشتیبانی میشوند (به دستگاههای پشتیبانیشده نگاه کنید). روی همان سرور دوباره نفرستید. |
| account_restricted | 403 | حساب شما چند دقیقه محدود است: یک دستگاه در ۵ دقیقه بیش از ۳ بار بهعنوان پشتیبانینشده رد شد و بعد از هشدار دوباره فرستاده شد. تا آن موقع هر درخواست تازه رد میشود؛ status.php برای کارهایی که قبلاً شروع شدهاند همچنان جواب میدهد. پاسخ reason (unsupported_device_repeated)، retry_after (ثانیه)، restricted_until و note (جملهای برای پنل شما) را دارد. اگر اشتباهی شده با ما تماس بگیرید. |
| device_reboot | 409 | سرور میگوید این توکن دستگاه قبلاً استفاده شده است. چیزی کسر نشد. گوشی را ریبوت کنید، دوباره به حالت سایدلود ببرید تا توکن تازه بدهد، و درخواست تازه بفرستید. |
| server_unavailable | 503 | سرور بهموقع پاسخ نداد، یا — وقتی سروری نام نبرده بودید — هیچ سروری در دسترس نبود. چیزی کسر نشد. همان درخواست را دوباره بفرستید. |
| failed | 400 | سروری که انتخاب کردید کار را اجرا کرد اما برای این دستگاه توکنی نداد — شکستی در مرحلهٔ آخر. چیزی کسر نشد: مبلغ رزروشده کامل برمیگردد. خواندن گوشی را بررسی کنید، یا سرور دیگری را امتحان کنید. |
| bad_before | 400 | before در history.php یک request_id نیست. |
| bad_date | 400 | from یا to در history.php روزی مثل 2026-10-08 نیست، یا from بعد از to است. |
17امنیت
رمز و کلید شما در بدنهٔ هر درخواست است. روی HTTP ساده هرکسی در مسیر میتواند آنها را بخواند و دوباره استفاده کند.
این توکن حساب شماست — مقدار rst_… در هدر Authorization — نه توکنهای آنلاک. ما فقط یک هش از آن نگه میداریم، پس نمیتوانیم بعداً برایتان ایمیل کنیم. آن را جایی نگه دارید که بقیهٔ اسرارتان را نگه میدارید. اگر لو رفت، در پنل خود یک توکن تازه بسازید — قبلی بلافاصله از کار میافتد. توکنهای آنلاکی که کارهای شما میآورند چیز دیگریاند: هر کدام همراه کار خودش نگه داشته میشود و status.php آن را با request_id دوباره به شما میدهد.
از سرور خودتان ما را صدا بزنید، نه از ابزاری که به کاربر نهایی میدهید. هر چیزی که منتشر کنید خوانده میشود.
در پنل خودتان (حساب ← IPهای مجاز) میتوانید API را به نشانیهایی که سرورتان از آنها وصل میشود قفل کنید، تا اعتبارنامهٔ دزدیدهشده از هر جای دیگر بیفایده باشد. درخواست از هر نشانی دیگر با ip_not_allowed رد میشود. ما هم میتوانیم آن را برایتان تنظیم کنیم.
پیش از ذخیرهٔ درخواست همراه کار حذف میشود، پس نه در دیتابیس ما هست، نه در لاگ کار، نه در صفحههای ادمین.
فقط حساب شما میتواند یک 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 را ظرف ۳۰ ثانیه به برنامهٔ بعدی بدهید.
#!/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<?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";"""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}")// 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 کار را شروع میکند؛ سپس هر ۳ ثانیه میپرسد تا توکن بیاید — یا دلیل نیامدنش.
#!/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).<?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";
}"""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"))// 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تاریخچهٔ کارهای شما
کارهای شما را میان دو روز، برای یک سرویس فهرست میکند: چند تا فرستادید، هر کدام چطور تمام شد، و هزینهشان.
#!/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<?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'] ?? '');
}"""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 ''}")// 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 کردهاید، و قیمت شما روی هر سرور را چاپ میکند.
#!/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<?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']);
}
}"""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']}")// 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سرورها
سرورهایی را که میتوانید استفاده کنید، قیمت شما روی هر کدام، و اینکه همین حالا کار میگیرد یا نه، فهرست میکند.
#!/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<?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']);
}
}"""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']}")// 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 را برای ما بفرستید. با همین دو تا دقیقاً میبینیم بر سر آن کار چه آمده؛ بدون آنها فقط حدس میزنیم.