ملی ای‌پی‌آی

مستندات API استعلام

یک کلید، یک نشانی، و پاسخ JSON. آنچه در ادامه آمده توصیف رفتار واقعی سامانه است، نه فهرست وعده‌ها.

ارائهٔ API در حال حاضر فعال نیست. مستندات زیر معتبر است، ولی فراخوان‌ها فعلاً پذیرفته نمی‌شوند. برای اطلاع از زمان شروع تماس بگیرید.

سند OpenAPI OAS 3.0.3

فایل را در Postman یا Swagger وارد کنید، یا از رویش کلاینت تولید کنید. ⚠️ سند در لحظهٔ دانلود ساخته می‌شود، پس فهرست سرویس‌ها و قیمت‌ها همانی است که همان لحظه فعال است.

دانلود سند OpenAPI

برای چه کسی

برای کسب‌وکارهایی که می‌خواهند استعلام را داخل محصول خودشان انجام دهند، نه اینکه کاربرشان را به سایت دیگری بفرستند. مثلاً تطبیق کد ملی با شمارهٔ موبایل در لحظهٔ ثبت‌نام، یا تبدیل کد پستی به نشانی در فرم سفارش.

حساب کسب‌وکار فعلاً دستی ثبت می‌شود؛ پس از ثبت، خودتان از پنل کلید می‌سازید و می‌چرخانید.

شروع در سه گام

  1. حساب کسب‌وکار را از صفحهٔ تماس درخواست می‌دهید و می‌گویید کدام استعلام‌ها را لازم دارید.
  2. پس از ثبت و شارژ، در پنل کسب‌وکار کلید می‌سازید. متن کلید فقط یک بار نشان داده می‌شود.
  3. کلید را در هدر می‌گذارید و فراخوان می‌زنید.

احراز هویت

کلید را در یکی از این دو هدر بفرستید، هر دو پذیرفته می‌شوند:

Authorization: Bearer melli_live_…
# یا
X-API-Key: melli_live_…

⚠️ کلید را هرگز در کد سمت مرورگر نگذارید. هر کسی که کلید را ببیند می‌تواند از موجودی شما خرج کند. اگر نشت کرد، از پنل باطلش کنید؛ ابطال بی‌درنگ اثر می‌کند.

اگر IP سرورتان ثابت است، هنگام ساخت کلید فهرست IP مجاز را پر کنید. خالی‌گذاشتنش یعنی کلید از هر جای دنیا کار می‌کند.

نشانی و قالب درخواست

هر سرویس یک نشانی دارد و فقط POST می‌پذیرد. ورودی این سرویس‌ها کد ملی و شمارهٔ کارت است؛ فرستادنش در نشانی یعنی نشستنش در لاگ سرور، تاریخچهٔ مرورگر و هدر Referer، پس GET عمداً پشتیبانی نمی‌شود.

POST https://melliapi.net/api/v1/{slug}/
Content-Type: application/json

اسلش پایانی را بگذارید. شکل بدون اسلش هم کار می‌کند، ولی شکل بالا شکل قطعی است و هیچ هدایتی نمی‌گیرد، و بعضی کتابخانه‌ها بدنهٔ POST را پس از هدایت دوباره نمی‌فرستند.

پاسخ موفق

{
  "ok": true,
  "requestId": "req_1a2b3c…",
  "service": "sana-inquiry",
  "data": { … },
  "source": { "cached": false, "stale": false, "fetchedAt": "2026-09-23T10:00:00.000Z" },
  "billing": { "amountRial": 51000, "balanceRial": 9949000 }
}
  • data، پاسخ سرویس مرجع، بدون دست‌کاری.
  • source.cached، پاسخ از کش آمد یا از سرویس مرجع. stale یعنی سرویس مرجع در دسترس نبود و آخرین پاسخ معتبر برگردانده شد؛ fetchedAt می‌گوید مال چه زمانی است.
  • billing.amountRial، همان مبلغی که همین حالا کسر شد. صفر یعنی رایگان بود.
  • requestId، برای پیگیری در پشتیبانی. نگهش دارید.

خطاها

هر پاسخ ناموفق همین شکل را دارد و error.code ماشین‌خوان است. به کد تکیه کنید و نه به متن پیام؛ متن ممکن است بهتر شود.

{ "ok": false, "requestId": "req_…", "error": { "code": "insufficient_funds", "message": "…" } }
کدHTTPیعنیهزینه
unauthorized۴۰۱کلید نیست، غلط است یا باطل شدهندارد
ip_not_allowed۴۰۳IP شما در فهرست مجاز کلید نیستندارد
organization_inactive۴۰۳حساب کسب‌وکار فعال نیستندارد
service_not_granted۴۰۳این سرویس برای شما باز نشدهندارد
service_not_enabled۴۰۳این سرویس فعلاً از API ارائه نمی‌شودندارد
unknown_service۴۰۴چنین slugی وجود نداردندارد
async_not_supported۵۰۱این سرویس چندمرحله‌ای است و از API ارائه نمی‌شودندارد
invalid_json۴۰۰بدنهٔ درخواست JSON معتبر نیستندارد
method_not_allowed۴۰۵فقط POST پذیرفته می‌شودندارد
invalid_input۴۰۰فیلدها ناقص یا نامعتبرند، جزئیات در fieldsندارد
insufficient_funds۴۰۲موجودی کافی نیستندارد
rate_limited۴۲۹از سقف نرخ گذشتید، Retry-After را ببینیدندارد
not_found۲۰۰استعلام انجام شد و رکوردی نبوددارد
provider_failed۵۰۲سرویس مرجع پاسخ قطعی منفی داد، تکرارش همان جواب را می‌دهددارد
provider_failed_retryable۵۰۲خطای گذرای سرویس مرجع، دوباره تلاش کنیدندارد
not_inquirable۴۲۲سامانهٔ مرجع استعلام همین مورد را نمی‌پذیرد، مثلاً «استعلام این کارت امکان‌پذیر نیست.»؛ تکرارش بی‌فایده استندارد
temporarily_unavailable۵۰۳سرویس مرجع در دسترس نبود، بعداً تلاش کنیدندارد
api_disabled۵۰۳ارائهٔ API موقتاً خاموش استندارد
no_tariff۵۰۳تعرفهٔ این سرویس تعیین نشدهندارد
internal_error۵۰۰خطای داخلی ما، با requestId به پشتیبانی بگوییدندارد

⚠️ not_found با HTTP ۲۰۰ برمی‌گردد و ok:false دارد. «رکوردی نیست» یک پاسخ معتبر است که ما بابتش به سرویس مرجع پول داده‌ایم، پس هزینه دارد، ولی ۴۰۴ نمی‌دهیم چون با «چنین سرویسی نداریم» قاطی می‌شود.

هر پاسخی که به مرحلهٔ تسویه رسیده باشد، چه موفق چه ناموفق، فیلد billing دارد و می‌گوید همین حالا چقدر کسر شد و موجودی‌تان چقدر مانده. نبودنِ این فیلد یعنی هیچ مبلغی جابه‌جا نشده؛ پس برای تطبیق حساب لازم نیست حدس بزنید.

نمونهٔ کد

curl

curl -X POST 'https://melliapi.net/api/v1/sana-inquiry/' \
  -H 'Authorization: Bearer melli_live_…' \
  -H 'Content-Type: application/json' \
  -d '{"nationalCode":"0013542419","mobile":"09120000000"}'

PHP / وردپرس

$response = wp_remote_post( 'https://melliapi.net/api/v1/sana-inquiry/', array(
    'timeout' => 30,
    'headers' => array(
        'Authorization' => 'Bearer ' . MELLIAPI_API_KEY,
        'Content-Type'  => 'application/json',
    ),
    'body' => wp_json_encode( array(
        'nationalCode' => $national_code,
        'mobile'       => $mobile,
    ) ),
) );

if ( is_wp_error( $response ) ) {
    // شبکه قطع بود، دوباره تلاش کنید.
    return;
}

$body = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! empty( $body['ok'] ) ) {
    // $body['data'] پاسخ استعلام است.
}

Node.js

const response = await fetch('https://melliapi.net/api/v1/sana-inquiry/', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${process.env.MELLIAPI_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ nationalCode, mobile }),
});

const body = await response.json();
if (body.ok) {
  // body.data
}

Python

import os, requests

response = requests.post(
    "https://melliapi.net/api/v1/sana-inquiry/",
    headers={"Authorization": f"Bearer {os.environ['MELLIAPI_API_KEY']}"},
    json={"nationalCode": national_code, "mobile": mobile},
    timeout=30,
)
body = response.json()
if body.get("ok"):
    data = body["data"]

⚠️ مهلت (timeout) را دست‌کم ۳۰ ثانیه بگذارید. برخی سرویس‌های مرجع کند پاسخ می‌دهند و مهلت کوتاه یعنی شما پاسخ را نمی‌بینید در حالی که صورتحسابش صادر شده.

سرویس‌ها و ورودی‌هایشان

فهرست سرویس‌های فعال هنوز منتشر نشده است. بپرسید کدام استعلام‌ها موجودند.

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

صورتحساب

  • مبلغ پیش از تماس با سرویس مرجع از موجودی شما قفل می‌شود و پس از پاسخ تسویه. اگر پاسخی نیاید، کل مبلغ همان لحظه برمی‌گردد.
  • فراخوانی که به سرویس مرجع نرسد، موجودی ناکافی، ورودی نامعتبر، قطعی، هیچ هزینه‌ای ندارد.
  • کف شارژ حساب ۱٬۰۰۰٬۰۰۰ تومان است.

سقف نرخ

پیش‌فرض ۶۰ فراخوان در دقیقه برای هر سرویس است. عبور از آن پاسخ 429 با هدر Retry-After می‌گیرد و هیچ هزینه‌ای ندارد. اگر حجم بیشتری لازم دارید، بگویید تا برای حساب شما بالا ببریم.

⚠️ فراخوان ۴۲۹ در سابقهٔ مصرف شما ثبت نمی‌شود. سقف نرخ برای ریختن بار است و نوشتن یک ردیف به‌ازای هر درخواست ردشده، همان چیزی را می‌سازد که قرار بود جلویش را بگیرد. اگر شمارش لازم دارید، سمت خودتان پاسخ‌های ۴۲۹ را بشمارید.

آنچه نگه می‌داریم

درخواست و پاسخ هر فراخوان ذخیره می‌شود تا در پنل کسب‌وکارتان، کنار همان ردیف، ببینیدش و به‌صورت JSON دانلودش کنید. برای عیب‌یابی همین لازم است: بدون آن، «کدام ورودی غلط بود» فقط با تیکت درمی‌آمد.

این داده رمزشده در پایگاه داده می‌نشیند و فقط از حساب خودتان دیده می‌شود. نه در گزارش‌های ما جمع زده می‌شود، نه به کسی داده می‌شود، و نه برای کار دیگری به کار می‌رود.

پاسخ استعلام‌ها در کشی مشترک نگهداری می‌شود که کلیدش hash کل ورودی است: به پاسخ کش کسی می‌رسد که بتواند دقیقاً همان ورودی را بسازد، یعنی همان چیزی را بداند که پرسندهٔ اول می‌دانست.

سیاست حریم خصوصی و اقدامات امنیتی

شروع کنیم

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