01كيف يعمل
تقرأ الهاتف بأداتك الخاصة وترسل ما قرأته. تحصل على request_id فورًا. تعيده إلى status.php، فيبدأ ذلك المهمة على الخادم الذي اخترته؛ ثم يخبرك الاستدعاء نفسه بحال المهمة، ويسلّمك توكن فك القفل لتكتبه على الهاتف. نحن لا نلمس الهاتف أبدًا، وأنت لا تتعامل مع الخادم أبدًا.
يتحقق token.php من كل شيء ويرد فورًا بـ request_id مثل WT-API-6AF684545B. لم يُرسل شيء بعد إلى أي خادم، ولم يُخصم شيء.
أرسل request_id إلى status.php. هذا الاستدعاء الأول هو إيصالك: الآن فقط تبدأ المهمة. أي request_id لا يؤكده أحد خلال 30 ثانية يُلغى.
اسأل 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 | توكن الحساب — خاص بك وحدك. أنشئه من لوحتك ضمن «بيانات الاعتماد الخاصة بك»، أو اطلبه منا. نخزّن قيمة hash له فقط، لذا يُعرض مرة واحدة ولا يمكن استعادته — وإنشاء توكن جديد يُنهي القديم فورًا. |
| 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 — راجع blob الجهاز. |
| serverid | string | لا | المعرّف العام للخادم الذي يجب أن ينفذ المهمة، مثل server1 — من servers.php، أو من لوحتك ضمن الخوادم. صارم: إما أن ينفذها ذلك الخادم، أو يُرفض الطلب مع ذكر السبب. إن لم ترسله نختار أرخص خادم يستقبل المهام. مالكو الأدوات: أرسلوه دائمًا. راجع اختيار الخادم. |
| request_date | string | لا | اختياري. وقت إرسال خادمك أنت لهذا الطلب، بصيغة ISO-8601 مع Z أو فارق توقيت. يُعاد كما هو دون تعديل في client_sent، ولا يُستخدم أبدًا في حساباتنا. إذا لم ترسله فلن يتغير شيء، باستثناء أن client_sent وclient_clock_offset_seconds يعودان بالقيمة null. |
| request_language | string | لا | Optional. The language for the customer-facing message of a refusal: one of English, Persian, Spanish, French, Turkish, Arabic (or a 2-letter code like en/fa). Omitted or unrecognised → the reply is in English. Send it on every call (token.php, status.php and the reads). The structured fields (such as flash_status, region, takes_on) come back regardless, so you can also build your own sentence in any language. |
04blob الجهاز
الـ blob هو ترميز base64 لكائن JSON يحمل القراءة الكاملة لبيانات الهاتف — كل ما تقرؤه أداتك في ذلك الوضع، وليس التوكن وحده. ما هو مطلوب يعتمد على soc: في frp يكون الهاتف في وضع Mi Assistant (sideload / recovery)، وفي fdl يكون في وضع Fastboot. أرسل كل قيمة تمامًا كما أجاب بها الهاتف — دون اختصار، ودون إعادة تنسيق.
frp — الهاتف في وضع Mi Assistant (sideload / recovery)
| الحقل | أمر القراءة | مطلوب | ما هو | مثال |
|---|---|---|---|---|
| token | getmitoken: | نعم — يُرفض null | قيمة تحدّي FRP، تمامًا كما قُرئت | 8f21c0b4e9d7… |
| deviceName | getdevice: | نعم — يُرفض null | الاسم الرمزي مع لاحقة المنطقة | fleur_global |
| version | getversion: | نعم — يُرفض null | رقم بناء ROM | OS2.0.207.0.VMTMIXM |
| serial | getsn: | نعم — يُرفض null | الرقم التسلسلي | fb4d921c |
| codebase | getcodebase: | نعم — null إن لم يُقرأ | إصدار أندرويد | 15 |
| region | getregion: | نعم — null إن لم يُقرأ | منطقة ROM | IR |
| cpuid | getcpuid: | نعم — null إن لم يُقرأ | قيمة CPU ID، إذا أجاب الهاتف بها | 0x000460E1 |
| recovery | getrecoveryversion: | نعم — null إن لم يُقرأ | إصدار الريكفري — تستخدمه فقط قائمتنا للأجهزة غير المدعومة | 2 |
| branch | getbranch: | لا — null مقبول | فرع ROM | 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)، تمامًا كما تفعل أداتنا. يوضع رقم بناء ROM في version. ذكرت نسخة سابقة من هذه الصفحة أن رقم بناء ROM يوضع في productName — فإذا كان تكاملك يفعل ذلك، فانقله إلى version.
fdl — الهاتف في وضع Fastboot
| الحقل | أمر القراءة | مطلوب | ما هو | مثال |
|---|---|---|---|---|
| token | oem get_token (getvar:token) | نعم — يُرفض null | توكن fastboot، تمامًا كما قُرئ | VQHzN2Ib… |
| product | getvar:product | نعم — يُرفض null | الاسم الرمزي، دون المنطقة | fleur |
| serial | getvar:serialno | نعم — يُرفض null | الرقم التسلسلي | fb4d921c |
| cpuid | getvar:cpuid | نعم — null إن لم يُقرأ | قيمة CPU ID، إذا أجاب الهاتف بها | 0x000460E1 |
{
"token": "VQHzN2Ib…",
"product": "fleur",
"serial": "fb4d921c",
"cpuid": "0x000460E1"
}يمكن إرسال أي حقل بالقيمة null (null في JSON أو النص "null") عندما لا يستطيع الهاتف قراءته — ولا ترسل أبدًا unknown أو N/A أو نصًا فارغًا. ما يحدث بعد ذلك يعتمد على الحقل: الحقل المعلَّم نعم — يُرفض null تبني الخوادم المهمة عليه، لذا يُرفض الطلب بـ incomplete_configblob ويُذكر الحقل في nulls ولا يُخصم شيء — أعد قراءة الهاتف وأرسل المعلومات كاملة؛ والحقل المعلَّم نعم — null إن لم يُقرأ يجب أن يكون دائمًا في الـ blob، ومع null تُنفَّذ المهمة كالمعتاد (وإذا حُذف كليًا يُرفض)؛ والحقل المعلَّم لا — null مقبول أرسله بالقيمة null أو احذفه — تُنفَّذ المهمة. المهمة المرسلة بحقول null تُنفَّذ بما أرسلته: إذا لم يعمل التوكن بعد ذلك على الهاتف لأن حقلًا لم يُقرأ، فلا يمكن استرداد المبلغ. أرسل كل حقل يجيب عنه الهاتف.
تحتاج بعض الخوادم إلى 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 400 والخطأ incomplete_configblob، مع الوضع الذي يجب أن يكون فيه الهاتف في mode: Mi Assistant أو Fastboot. أرسل الحقول الاختيارية كلما أجاب عنها الهاتف؛ والحقل المفقود أو الذي قيمته null أو الذي يحتوي على قراءة فاشلة يُستبعد ببساطة ولا يُمرَّر أبدًا — ولا يوقف المهمة. أما الـ blob الذي يكون توكنه مفقودًا أو 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 | رقم بناء ROM (frp) |
| serial | serial_number | الرقم التسلسلي |
| codebase | codebase | إصدار أندرويد (frp) |
| branch | branch | فرع ROM (frp) |
| region | region | منطقة ROM (frp) |
| cpuid | cpu_id | قيمة CPU ID، إذا أجاب الهاتف بها |
| token | — | لا يُكرَّر في device |
الحقل الذي لا ينطبق على الخدمة يعود بالقيمة null بدلًا من أن يغيب عن الرد، لذا يقرأ محلّل واحد ردود الخدمتين كلتيهما.
05الأجهزة المدعومة
بعض أرقام البناء (build) غير مدعومة، وقد لا تكون بعض الدول مدعومة أيضًا. لمعرفة أيها، اسأل المسؤول عبر تلغرام أو واتساب بعد حصولك على API مالك الأداة.
الجهاز الموجود في قائمتنا الخاصة بالأجهزة غير المدعومة يرفضه token.php فورًا بـ unsupported (422): لا request_id، ولا إرسال إلى أي خادم، ولا أي خصم. يمكن للقائمة فحص كل حقل في configblob — الطراز والبرنامج الثابت وإصدار أندرويد والفرع واللغة والمنطقة وإصدار الريكفري وROM zone والرقم التسلسلي وCPU id — لذا أرسل كل ما قرأته أداتك.
انتبه: إرسال طراز غير مدعوم يكلّفك رصيده — ولا يُسترد — وقد يؤدي أحيانًا إلى حظر حسابك.
الجهاز نفسه غير المدعوم مرة بعد مرة: كل رفض لجهاز على أنه غير مدعوم (unsupported) يُحتسب لحسابك ولذلك الجهاز خلال 5 دقائق. الرفض الرابع يحمل تحذيرًا في message وقيمة true في strike.warning (يوجد strike = {count, max, window_seconds, warning} في كل رفض من هذا النوع): إعادة إرسال هذا الجهاز ستحظر حسابك. رفض آخر له خلال تلك الدقائق الخمس يقيّد حسابك لمدة 5 دقائق: يُجاب كل طلب جديد بـ account_restricted (403). توقّف عند التحذير واعرض على عميلك خادمًا يقبل الجهاز.
عندما يُرفض جهاز بسبب منطقته ويكون أحد خوادمك مميّزًا (premium) لتلك المنطقة، يحمل رفض 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 (404) عندما لا يوجد خادم بهذا المعرّف، وserver_not_allowed (403) عندما لا يكون مفعّلًا لحسابك، وserver_offline (503) عندما لا يستطيع تولّي هذه الخدمة حاليًا. ولا ننقلك أبدًا إلى خادم آخر من دون علمك.
تتكوّن بعض الخوادم من عدة أجهزة يمكن اختيارها واحدًا واحدًا. يسرد 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 لا يتجاوز 256 كيلوبايت. | method_not_allowed 405bad_json 400body_too_large 413 |
| 2 | بيانات اعتمادك الأربع تشير إلى الحساب النشط نفسه: توكن الحساب وapi_key وemail وpassword. | unauthorized 401too_many_failures 429 |
| 3 | يأتي الطلب من عنوان موجود في قائمة العناوين المسموح بها لحسابك، إن كنت قد حددت واحدة. | 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 | لم يُرسل الجهاز نفسه — توكن الجهاز نفسه، للخدمة نفسها والخادم نفسه — خلال آخر 30 دقيقة. وإن أُرسل وبدأت تلك المهمة، تحصل على تلك المهمة نفسها: request_id وحالتها، أو توكنها — ولا مهمة ثانية ولا خصم ثانٍ أبدًا. والمهمة التي فشلت، أو التي لم يُؤكَّد request_id الخاص بها، تُستبدل بمهمة جديدة. | — |
| 10 | رصيدك يغطي سعر مهمة على ذلك الخادم — قيمة price التي يعرضها servers.php له. يُفحص ذلك هنا؛ ولا يُحجز السعر إلا عند بدء المهمة. | no_credit 402 |
نجحت كل الفحوصات: تحصل على request_id فورًا، مع state بقيمة waiting. لم يُرسل شيء إلى أي خادم، ولا يُحجز شيء حتى تؤكده عبر status.php. | ||
08معرّف request_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.أكّده خلال 30 ثانية. أرسله إلى status.php: هذا الاستدعاء هو إيصالك ويبدأ المهمة. أي request_id لا يؤكده أحد خلال 30 ثانية يُلغى — لم يُرسل شيء إلى أي خادم ولم يُخصم شيء — وأي استدعاء لاحق به يتلقى request_expired: أعد إرسال الطلب لتحصل على request_id جديد. وهكذا إن لم يصلك رد أبدًا، فلا توجد مهمة قيد التشغيل لا يمكنك متابعتها.
| الحقل | ما هو |
|---|---|
| request_id | معرّفنا لهذه المهمة — WorkID الخاص بها، مثل WT-API-6AF684545B. تؤكد المهمة وتتابعها وتستلمها به، واذكره لنا في أي سؤال عنها. |
| state | waiting |
| confirm_within | الثواني المتبقية لتأكيده عبر status.php. |
| price | كلفة المهمة عليك على ذلك الخادم — تُحجز عند البدء، ولا تُخصم إلا إذا جاء التوكن. |
| serverid | المعرّف العام للخادم الذي نفّذ المهمة — وهو نفسه serverid الذي يمكنك إرساله. |
| server_name | الاسم العام لذلك الخادم، مثل Server 1. |
لم يُرسل الجهاز نفسه — توكن الجهاز نفسه، للخدمة نفسها والخادم نفسه — خلال آخر 30 دقيقة. وإن أُرسل وبدأت تلك المهمة، تحصل على تلك المهمة نفسها: request_id وحالتها، أو توكنها — ولا مهمة ثانية ولا خصم ثانٍ أبدًا. والمهمة التي فشلت، أو التي لم يُؤكَّد request_id الخاص بها، تُستبدل بمهمة جديدة.
09التأكيد والمتابعة
أرسل request_id إلى status.php ببيانات الاعتماد الأربع نفسها. أول استدعاء خلال 30 ثانية يبدأ المهمة ويرد بـ pending فورًا؛ بعد ذلك اسأل من جديد كل retry_after ثانية حتى لا تعود state بقيمة pending. تستغرق المهمة عادةً 15–25 ثانية.
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 | لم يُؤكَّد خلال 30 ثانية: أُلغي، ولم يُرسل شيء، ولم يُخصم شيء. أعد إرسال الطلب لتحصل على request_id جديد. |
not_found | 404 | لا يوجد طلب بهذا request_id يخص حسابك. |
يُحفظ التوكن مع المهمة على خادمنا. إن لم يصلك رد أبدًا، فاسأل status.php من جديد بالـ request_id نفسه: ما دامت المهمة قيد التشغيل تحصل على 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 حدّه الخاص — 120 استدعاءً في الدقيقة لكل حساب — ولا يُحتسب من حصتك الساعية، فمتابعة المهمة لا تستهلك طلبات التوكن لديك أبدًا.
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 تمامًا، لأن الثلاث مشتقة من اللحظات نفسها.
في المثال التطبيقي أدناه، استغرقت المهمة 5 ثوانٍ للجلب و3 ثوانٍ للتسليم، أي 8 ثوانٍ إجمالًا.
| الحقل | ما هو |
|---|---|
| start_date — الحصول على التوكن | |
| client_sent | وقت إرسال خادمك للطلب — كما أرسلته تمامًا |
| server_received | وقت وصول الطلب إلى خادمنا |
| upstream_sent | وقت إرسالنا الطلب إلى خادم التوكن |
| upstream_received | وقت وصول رد خادم التوكن إلينا |
| elapsed_seconds | من الوصول حتى الحصول على التوكن — 5 ثوانٍ في المثال |
| end_date — تسليمه إليك | |
| upstream_answered | وقت رد خادم التوكن علينا |
| server_answered | وقت رد خادمنا عليك |
| elapsed_seconds | مرحلة التسليم وحدها — 3 ثوانٍ في المثال |
| response_date — العملية بأكملها | |
| total_seconds | 5 + 3 = 8 ثوانٍ |
| client_clock_offset_seconds | الفرق بين ساعتك وساعتنا |
تُقاس كتل التوقيت من لحظة استلام token.php للطلب. وتنتهي end_date عندما يغادرنا الرد الذي يحمل التوكن، لذا تشمل ما انتظرته بين استدعاءاتك لـ status.php.
لماذا لا يُستخدم طابعك الزمني في المجاميع
تُعاد هذه القيمة في client_sent، وهي قيمتك وليست قيمتنا — فإذا كانت ساعة خادمك متقدمة بدقيقة، فإن الحساب بالاعتماد عليها سيُظهر مدة سالبة. كل قيمة للوقت المنقضي مأخوذة من ساعتنا، ويُبلَّغ عن الفرق بين الساعتين بشكل منفصل في client_clock_offset_seconds لكي تراه، بدلًا من أن يُدمج بصمت في رقم تعتمد عليه في الفوترة.
11قراءات معلومات الجهاز (soc)
إلى جانب frp و fdl، يمكن لحسابات مالكي الأداة أيضًا قراءة معلومات الجهاز. تعمل هذه الخدمات عبر المسار نفسه token.php ثم status.php، لكنها لا تستخدم أي خادم، وبدلًا من رمز، تُعيد معلومات الجهاز على شكل حقول (fields). وهي مجانية حاليًا (قد يُحدَّد سعر لاحقًا).
قيم soc
| soc | ماذا تفعل | المدخل | الرد خلال |
|---|---|---|---|
| frp | فتح FRP؛ تُعيد رمز استجابة. | configblob — القراءة الكاملة للجهاز | في الحال |
| fdl | تفويض FDL؛ تُعيد رمز استجابة. | configblob — القراءة الكاملة للجهاز | في الحال |
| read_sideload | تقرأ معلومات الجهاز في وضع Mi Assistant. | configblob — يلزم رمز الجهاز فقط | في الحال |
| read_fastboot | تقرأ معلومات الجهاز في وضع fastboot. | configblob — يلزم رمز الجهاز فقط | في الحال |
| read_imei | تبحث عن IMEI في قاعدة بيانات الشركة المصنّعة. | imei — رقم IMEI المكوّن من 15 رقمًا | من 1 إلى 5 دقائق؛ استمر في الاستعلام |
| read_lockcode | تُعيد سجل الجهاز خلف رمز القفل. | imei — رقم IMEI للطلب | بضع دقائق؛ استمر في الاستعلام |
هذه القراءات مخصّصة لحسابات مالكي الأداة. لا تُدرج read_imei إلا ما دامت مفتوحة للـ API؛ وإلا فهي متاحة داخل أداة XST.
إرسال قراءة
تُرسَل القراءة وتُفحَص تمامًا مثل frp و fdl: يمنحك token.php رقم request_id، ويبدؤها أول استدعاء لـ status.php، وتستعلم حتى تنتهي. لا تستخدم أي خادم ولا تتقاضى سعر خادم.
# 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 lists the reads you may use in a reads array, each with its soc, name, needs and price, plus time (the delivery time; for read_lockcode the shop service's own, empty when not known) and field (the name of the input to show your customer, e.g. Lock Code). read_imei and read_lockcode are asynchronous (poll).
12سجل مهامك
مهامك من الأحدث إلى الأقدم: متى أُرسلت كل منها، وإلى أي خادم، وكيف انتهت — حسب التاريخ والخدمة. بيانات الاعتماد الأربع نفسها؛ لا يستهلك رصيدًا ويُحتسب من حصتك الساعية.
| الحقل | النوع | مطلوب | ما هو |
|---|---|---|---|
| from | string | لا | يوم، 2026-10-08 (أو 2026-Oct-08)، بتوقيت UTC: المهام المرسلة في ذلك اليوم أو بعده. |
| to | string | لا | يوم: المهام المرسلة في ذلك اليوم أو قبله، مع اليوم كاملًا. |
| soc | string | لا | frp أو fdl: مهام تلك الخدمة فقط. |
| limit | number | لا | عدد المهام المعروضة، 1–100. الافتراضي 1. |
| 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الرصيد والاستخدام
كم تبقّى من الرصيد، وأين ذهب الباقي: الأرقام نفسها الظاهرة في البطاقات أعلى لوحتك. يستخدم بيانات الاعتماد الأربع نفسها التي يستخدمها طلب التوكن، ولا يستهلك أي رصيد، ويُجيب مرة واحدة كل 10 ثوانٍ.
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، بعملتك.
إذا استُعلم عنه مرة أخرى خلال 10 ثوانٍ، يُرجع 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 بـ server_offline قبل أي request_id — استخدم خادمًا آخر أو حاول لاحقًا. أما price بجانب القائمة فهي كلفة طلب دون serverid: أرخص خادم يستقبل المهام.
يذكر كل صف أيضًا أي البلدان يقبلها ذلك الخادم حسب region الجهاز: region_support — بلدان يقبلها مع أن بعض خوادمنا لا تقبلها (أو التي نعلن قبولها هناك)، وregion_not_support — بلدان لا يقبلها. كلاهما فارغ: كل البلدان. اعرضها على عميلك للتذكير، مثلًا «Server 6.3 — الصين: نعم، الهند: لا». لا يُنشر إلا البلد: شروطنا الأخرى (طراز، إصدار، CPU ID…) لا تُدرج وتبقى لدينا. القرار يُتخذ دائمًا هنا قبل إرسال أي شيء — يرفض token.php جهازًا لا يقبله الخادم بـ unsupported (422)، ويجيب check.php عن ذلك لجهاز واحد.
يمكنك عرض رد servers على عملائك بأمان: فهو يتضمن أسماء خوادمنا العامة وسعرك، ولا يتضمن أبدًا تكلفتنا ولا المزوّد الأصلي.
15أي الخوادم تقبل جهازًا
فحص تجريبي: بيانات الاعتماد نفسها والجسم نفسه الذي يأخذه token.php (soc، configblob)، والفحوص نفسها على configblob والأخطاء نفسها — ثم لا شيء: لا request_id، ولا مهمة، ولا حجز أو خصم، ولا إرسال إلى أي خادم. بعض الخوادم لا تقبل بعض الأجهزة (إصدار ما، بلد ما…)؛ يخبرك هذا الاستدعاء، لهذا الجهاز، أي خوادمك تقبله. له حدّه الخاص، 60 استدعاءً في الدقيقة، ولا يُحسب من حصتك الساعية.
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 يسرد خوادمك التي تقبل هذا الجهاز وتكون مميّزة (premium) لمنطقته (صُمّمت لأجهزة ذلك البلد، لذا نسبة نجاحها معه عالية جدًا)؛ وعندها يكون suggested أحدها، وmessage جملة يمكنك عرضها على عميلك، مثلًا “منطقة جهازك هي CN. يجب تنفيذ هذا الجهاز عبر Server 6.3 — خادم مميّز …” (فارغة إن لم يوجد). اختر ذلك الخادم مسبقًا لعميلك، واذكر السبب، ودعه يغيّر الخادم أو يلغي أو يتابع. تُحفظ إجابة الفحص المسبق 15 دقيقة، فلا يسأل 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 المسموح بها)، أو أرسل الطلب من عنوان مسموح به. لم يُنفَّذ أو يُخصم أي شيء. |
| too_many_failures | 429 | محاولات فاشلة كثيرة جدًا من عنوانك. انتظر، ثم صحّح بيانات الاعتماد قبل إعادة المحاولة. |
| rate_limited | 429 | تجاوزت حدًّا: حصتك الساعية (token.php وhistory.php وbalance.php وservers.php) أو 120 استعلام حالة في الدقيقة. يحمل الرد limit وused وper. |
| too_soon | 429 | تم استدعاء balance.php مرة أخرى خلال 10 ثوانٍ. يذكر الرد عدد الثواني التي يجب انتظارها (retry_after وترويسة Retry-After)؛ ولا يُحظر أي شيء. |
| method_not_allowed | 405 | استخدمت GET. جميع نقاط النهاية تعمل بطريقة POST. |
| bad_json | 400 | لم يكن المتن كائن JSON. عيّن Content-Type: application/json. |
| body_too_large | 413 | حجم المتن يتجاوز 256 KB. |
| 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 الخاص بالجهاز مفقود داخل الـ blob. |
| 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 المكوّن من 15 رقمًا؛ ويحتاج 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 خلال 30 ثانية، لذا أُلغي. لم يُرسل أو يُخصم أي شيء. أعد إرسال الطلب إلى token.php لتحصل على request_id جديد. |
| unsupported | 422 | لا يمكن خدمة هذا الجهاز. إن كان ضمن قائمة الأجهزة التي لا نخدمها، يرفضه token.php: لا request_id ولا خصم. وإن قال الخادم الذي اخترته إنه لا يدعم الجهاز، تُحتسب كلفة المهمة ولا تُسترد — اسألنا قبل الإرسال عن أرقام البناء والدول المدعومة (راجع الأجهزة المدعومة). لا تُعِد المحاولة على الخادم نفسه. |
| account_restricted | 403 | حسابك مقيَّد لبضع دقائق: رُفض جهاز واحد على أنه غير مدعوم أكثر من 3 مرات خلال 5 دقائق وأُعيد إرساله بعد التحذير. حتى ذلك الحين يُرفض كل طلب جديد؛ ويظل status.php يجيب عن الأعمال التي بدأت بالفعل. تحمل الإجابة reason (unsupported_device_repeated) وretry_after (بالثواني) وrestricted_until وnote، وهي جملة للوحتك. تواصل معنا إن كان ذلك خطأ. |
| device_reboot | 409 | يقول الخادم إن رمز هذا الجهاز استُخدم من قبل. لم يُخصم أي شيء. أعد تشغيل الهاتف، وأدخله في وضع sideload من جديد ليعطي رمزًا جديدًا، ثم أرسل طلبًا جديدًا. |
| 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 الخاص بها خلال 30 ثانية، لذا فالرد الذي يضيع في الطريق لا يترك أبدًا مهمة مدفوعة قيد التشغيل لا تعلم بها.
تشمل حصتك الساعية token.php وhistory.php وbalance.php وservers.php؛ ويسمح status.php وحده بـ 120 استدعاءً في الدقيقة؛ ويرد balance.php مرة كل 10 ثوانٍ؛ وبعد أكثر من 40 محاولة دخول فاشلة من عنوان واحد خلال 15 دقيقة، يُرفض ذلك العنوان لفترة بـ too_many_failures.
18أمثلة برمجية
برنامج كامل لكل مهمة، بأربع لغات — إرسال طلب، والتحقق منه بـ request_id، وسجل مهامك، ورصيدك، والخوادم. ضع بيانات اعتمادك وشغّله؛ واختيار لغة يعرضها في كل الأقسام.
1إرسال طلب توكن
يرسل قراءة الهاتف إلى token.php ويطبع request_id. لا يعمل شيء بعد: أعطِ ذلك request_id للبرنامج التالي خلال 30 ثانية.
#!/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 يبدأ المهمة؛ ثم يسأل كل 3 ثوانٍ حتى يأتي التوكن — أو سبب عدم مجيئه.
#!/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. بهذين نستطيع أن نرى بالضبط ما حدث لتلك المهمة؛ ومن دونهما نكون مجرد مخمّنين.