🔑 توثيق API — شراء الأرقام

تحكّم بالشراء وطلب الأكواد ومعرفة الرصيد والتوفر برمجياً، بنفس حسابك ورصيدك في البوت.

البدء السريع

  1. افتح البوت واضغط 🔑 API ثم إنشاء مفتاح. سيظهر المفتاح مرة واحدة فقط، احفظه في مكان آمن.
  2. تأكد من رصيدك: GET https://api.manarh.fun/api/v1/balance
  3. اختر السيرفر ثم الخدمة ثم الدولة (/servers ← /services ← /countries).
  4. اشترِ الرقم: POST /buy، ثم اطلب الكود: GET /code وكرر الطلب كل 5–10 ثوانٍ حتى يصل.

الرابط الأساسي لكل الطلبات:

https://api.manarh.fun/api/v1

كل الردود بصيغة JSON، وفيها دائماً الحقل ok (true أو false). الأسعار بالدولار (USD).

المصادقة

أرسل مفتاحك في ترويسة الطلب (الطريقة المفضلة):

X-API-Key: nb_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

أو بالشكل المعتاد: Authorization: Bearer nb_xxx

ويمكن أيضاً تمريره كمعامل ?api_key=nb_xxx للتجربة السريعة من المتصفح فقط.

أمان: المفتاح يعمل كرصيدك تماماً، فمن عرفه يستطيع الشراء بحسابك. لا تضعه في كود يعمل عند المستخدم (متصفح/تطبيق جوال)، ولا تشاركه. استخدم دائماً HTTPS، ولو شككت بتسريبه أنشئ مفتاحاً جديداً من البوت وسيتوقف القديم فوراً.

الحدود

لحمايتك وحماية الخدمة يوجد حدّان:

1) حد الشراء

عدد الأرقام التي يمكنك شراؤها عبر API خلال فترة زمنية محددة، ولا يمكن شراء كل المخزون دفعة واحدة. الحد الافتراضي حالياً: 10 رقم كل 60 دقيقة وقد تضبط الإدارة حداً مختلفاً لحسابك. الفترة منزلقة: كل رقم تشتريه يُحسب عليك حتى يمر عليه زمن الفترة كاملاً. اعرف حدّك واستهلاكك من GET /limits.

عند بلوغ الحد يرجع الخطأ purchase_limit_reached (HTTP 429) مع retry_after بالثواني.

2) حد عدد الطلبات

الحد العام 60 طلب بالدقيقة لكل مفتاح، وعند تجاوزه يرجع rate_limited (HTTP 429) مع ترويسة Retry-After. عند انتظار الكود لا تستعلم أسرع من مرة كل 5 ثوانٍ.

الطلبات

الرصيد

GET/balance
{"ok": true, "user_id": 123456, "balance": 12.5, "currency": "USD"}

الحدود والاستهلاك

GET/limits
{
  "ok": true,
  "purchase_limit": 10,        // أقصى عدد أرقام في الفترة
  "window_minutes": 60,        // طول الفترة
  "used": 3,                   // ما اشتريته داخل الفترة الحالية
  "remaining": 7,
  "reset_in_seconds": 1800,    // بعد كم ثانية يتحرر أقدم رقم محسوب عليك (0 لو لا يوجد)
  "requests_per_minute": 60
}

السيرفرات

GET/servers
{"ok": true, "servers": [
  {"id": 1, "name": "سيرفر 1", "kind": "api"},
  {"id": 2, "name": "سيرفر 2", "kind": "manual"}
]}

الخدمات (التطبيقات)

GET/services?server_id=1

المعامل server_id اختياري، وبدونه تُعرض خدمات كل السيرفرات.

{"ok": true, "services": [
  {"id": 1, "name": "✈️ تيليجرام", "server_id": 1, "server_name": "سيرفر 1"}
]}

الدول والأسعار والتوفر

GET/countries?service_id=1&lang=en

lang اختياري: en (الافتراضي) أو ar لأسماء الدول. الدول غير المتوفرة لا تظهر.

{"ok": true,
 "service": {"id": 1, "name": "✈️ تيليجرام", "server_id": 1, "server_name": "سيرفر 1"},
 "countries": [
   {"code": "EG", "name": "Egypt", "price": 0.6, "available": 5, "in_stock": true},
   {"code": "US", "name": "United States", "price": 2.2, "available": null, "in_stock": true}
 ]}

available هي الكمية المتوفرة، وتكون null إذا كانت الكمية غير معروفة لكن الدولة متوفرة (in_stock = true).

هل في أرقام على هذا السيرفر؟

GET/stock?server_id=1

ملخص سريع لكل خدمات السيرفر: كم دولة متوفرة وكم رقماً إجمالاً.

{"ok": true,
 "server": {"id": 1, "name": "سيرفر 1"},
 "has_stock": true,
 "services": [
   {"id": 1, "name": "✈️ تيليجرام", "countries": 12, "total": 340},
   {"id": 2, "name": "💬 واتساب", "countries": 3, "total": null}
 ]}

total تكون null لو المزود لا يعطي الكميات. لو تعذر جلب خدمة معينة يظهر فيها "error": "provider_error" بدل الأرقام.

شراء رقم

POST/buy
المعاملالوصف
service_idرقم الخدمة (من /services)
countryرمز الدولة (من /countries) مثل EG
Idempotency-Keyاختياري (ترويسة أو حقل idempotency_key): نص فريد لكل عملية شراء، انظر الملاحظة أدناه
curl -X POST https://api.manarh.fun/api/v1/buy \
  -H "X-API-Key: nb_xxx" -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-2024-0001" \
  -d '{"service_id": 1, "country": "EG"}'
{"ok": true,
 "order_id": 4521, "number": "+201000000001", "country": "EG",
 "service": {"id": 1, "name": "✈️ تيليجرام"}, "server": {"id": 1, "name": "سيرفر 1"},
 "price": 0.6, "balance": 11.9, "code": null, "status": "waiting_code",
 "created": "2026-11-03 12:00:00"}
مهم — منع الشراء المكرر: لو انقطع الاتصال قبل وصول الرد فلا تعيد الطلب بدون مفتاح، لأنك قد تشتري رقمين. أرسل Idempotency-Key فريداً مع كل عملية؛ إذا أعدت نفس الطلب بنفس المفتاح تحصل على نفس الرقم (مع "replayed": true) ولا يُخصم رصيد مرة ثانية.

الرصيد يُخصم فقط عند نجاح الشراء. وإذا فشل الشراء لدى المزود لا يُخصم شيء.

طلب الكود

GET/code?order_id=4521

اطلب الكود بعد أن تطلبه من التطبيق، وكرر الطلب كل 5–10 ثوانٍ حتى status = received.

statusالمعنى
receivedوصل الكود، وهو في الحقل code
waitingلم يصل بعد، أعد المحاولة بعد قليل
pendingرقم من مخزون يدوي: طُلب الكود من الإدارة وسيُرسل لك، أعد الاستعلام لاحقاً
{"ok": true, "order_id": 4521, "status": "received", "code": "55555"}

تفاصيل طلب

GET/order?order_id=4521

يرجع نفس بيانات الشراء مع الحقل status: waiting_code أو code_received (والكود إن وُجد).

قائمة طلباتك

GET/orders?limit=20&offset=0

limit من 1 إلى 100 (الافتراضي 20)، والأحدث أولاً.

{"ok": true, "total": 57, "orders": [ { "order_id": 4521, "number": "+2010...", ... } ]}

الأخطاء

عند الفشل يرجع "ok": false مع error (رمز ثابت للبرمجة) وmessage (شرح):

{"ok": false, "error": "insufficient_balance", "message": "Insufficient balance", "price": 0.6, "balance": 0.2}
HTTPerrorالمعنى
400bad_requestمعامل ناقص أو غير صالح
401invalid_api_keyالمفتاح مفقود أو خاطئ أو ملغى
402insufficient_balanceالرصيد لا يكفي (يرجع price وbalance)
403api_disabled / api_blocked / bannedالـ API متوقف، أو محظور على حسابك
404service_not_found / order_not_found / server_not_found / not_foundالعنصر غير موجود أو غير متاح
405method_not_allowedطريقة الطلب خاطئة (مثلاً GET بدل POST للشراء)
409out_of_stockلا توجد أرقام متوفرة لهذه الدولة
429purchase_limit_reached / rate_limitedتجاوزت حد الشراء أو حد الطلبات، انتظر retry_after ثانية
502provider_error / purchase_failedمشكلة عند المزود الخارجي، لم يُخصم رصيد ويمكنك المحاولة لاحقاً
500internal_errorخطأ داخلي، أعد المحاولة وإن تكرر تواصل مع الدعم

مثال كامل (Python)

import time, uuid, requests

BASE = "https://api.manarh.fun/api/v1"
H = {"X-API-Key": "nb_xxx"}

def call(method, path, **kw):
    r = requests.request(method, BASE + path, headers=H, timeout=40, **kw)
    data = r.json()
    if not data["ok"]:
        raise RuntimeError(f'{data["error"]}: {data["message"]}')
    return data

print("الرصيد:", call("GET", "/balance")["balance"])

countries = call("GET", "/countries", params={"service_id": 1})["countries"]
cheapest = min(countries, key=lambda c: c["price"])
print("أرخص دولة:", cheapest["name"], cheapest["price"])

# Idempotency-Key يمنع الشراء المكرر لو أعدت الطلب بعد انقطاع الاتصال
order = call("POST", "/buy",
             json={"service_id": 1, "country": cheapest["code"]},
             headers={**H, "Idempotency-Key": str(uuid.uuid4())})
print("الرقم:", order["number"])

# ... اطلب الكود من التطبيق الآن ...
for _ in range(30):
    res = call("GET", "/code", params={"order_id": order["order_id"]})
    if res["status"] == "received":
        print("الكود:", res["code"])
        break
    time.sleep(7)

مثال JavaScript (Node.js)

const BASE = "https://api.manarh.fun/api/v1";
const headers = { "X-API-Key": "nb_xxx", "Content-Type": "application/json" };

const r = await fetch(BASE + "/buy", {
  method: "POST",
  headers: { ...headers, "Idempotency-Key": crypto.randomUUID() },
  body: JSON.stringify({ service_id: 1, country: "EG" }),
});
const data = await r.json();
if (!data.ok) throw new Error(data.error + ": " + data.message);
console.log(data.number);
نصيحة: عالج دائماً الخطأين rate_limited وpurchase_limit_reached بالانتظار retry_after ثانية بدل إعادة المحاولة فوراً.