معماری و تضمینهای API
- هر توکن مشتری فقط به یک شرکت متصل است و در هر درخواست وضعیت اشتراک همان شرکت بررسی میشود.
- توکن کامل در دیتابیس ذخیره نمیشود؛ فقط هش غیرقابلبازیابی آن نگهداری میشود.
- هر ارسال به
Idempotency-Keyنیاز دارد تا retry شبکه هیچگاه صورتحساب تکراری نسازد. - مبالغ مالیات، تخفیف و جمع کل روی سرور محاسبه میشوند و به جمع ارسالی کلاینت اعتماد نمیشود.
- شناسههای کالا و خدمات قبل از ثبت، یکجا از کاتالوگ فعال کنترل میشوند.
- ثبت صورتحساب، خریدار و ردیفها در transaction انجام و ارسال واقعی از طریق صف پردازش میشود.
API از HTTPS استفاده میکند. توکن را در کد سمت مرورگر، اپ موبایل عمومی یا Git ذخیره نکنید؛ آن را فقط در backend یا secret manager نگه دارید.
احراز هویت با Bearer Token
از پنل مشتری ← «API صورتحساب» توکن بسازید. مقدار کامل فقط یکبار نمایش داده میشود.
Authorization: Bearer mdm_company_xxxxxxxxxxxxxxxx.YOUR_SECRET
برای بررسی اتصال:
GEThttps://mizan-hesab.ir/api/v2/health
curl "https://mizan-hesab.ir/api/v2/health" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
ارسال صورتحساب
POSThttps://mizan-hesab.ir/api/v2/invoices
curl -X POST "https://mizan-hesab.ir/api/v2/invoices" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Idempotency-Key: accounting-invoice-1405-000123" \
-H "Content-Type: application/json" \
--data @invoice.json
Idempotency-Key را برای هر صورتحساب یکتا و ثابت نگه دارید. در retry همان صورتحساب دقیقاً همان کلید و همان JSON را ارسال کنید.نمونه کامل invoice.json
{
"external_id": "INV-1405-000123",
"invoice_type": 1,
"invoice_subject": 1,
"issue_date": "2026-07-20T10:30:00+03:30",
"settlement_type": 1,
"buyer": {
"type": "legal",
"name": "شرکت خریدار نمونه",
"national_id": "10101234567",
"economic_code": "41111111111111",
"postal_code": "1234567890"
},
"items": [
{
"stuff_id": "2330004397645",
"description": "خدمات نرمافزاری",
"unit_code": "1627",
"quantity": 1,
"unit_price": 15000000,
"discount_amount": 0,
"vat_rate": 10
}
],
"notes": "ثبت خودکار از نرمافزار حسابداری",
"auto_send": true
}
کدهای عددی اصلی
| فیلد | ۱ | ۲ | ۳ |
|---|---|---|---|
| invoice_type | نوع اول B2B | نوع دوم B2C | نوع سوم صادراتی |
| invoice_subject | اصلی | اصلاحی | ابطالی |
| settlement_type | نقدی | نسیه | — |
نوع خریدار
real حقیقی، legal حقوقی، civil_partnership مشارکت مدنی، foreign خارجی و final_consumer مصرفکننده نهایی است. برای مصرفکننده نهایی نیازی به شناسه خریدار نیست و نوع صورتحساب بهطور خودکار B2C میشود.
برای اصلاحی و ابطالی، مقدار
original_tax_id را برابر شناسه مالیاتی صورتحساب مرجع بفرستید. برای نسیه نیز settlement_date الزامی است.پاسخ پذیرش
کد HTTP برابر 202 Accepted یعنی صورتحساب ثبت و وارد صف شده است؛ به معنی تأیید نهایی سازمان نیست.
{
"message": "صورتحساب در صف ارسال قرار گرفت.",
"code": "invoice_accepted",
"invoice": {
"external_id": "INV-1405-000123",
"uid": "...",
"tax_id": null,
"reference_number": null,
"status": "pending",
"grand_total": 16500000
}
}
در تکرار امن درخواست، هدر Idempotent-Replayed: true برگردانده میشود.
استعلام وضعیت
GEThttps://mizan-hesab.ir/api/v2/invoices/{external_id}
curl "https://mizan-hesab.ir/api/v2/invoices/INV-1405-000123" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
| وضعیت | معنی |
|---|---|
| pending / sending | در صف یا در حال ارسال |
| sent | به سازمان ارسال و شماره پیگیری دریافت شده |
| success | تأیید نهایی |
| failed | ناموفق؛ جزئیات در error |
نمونه پیادهسازی
PHP با Laravel HTTP Client
$response = Http::withToken(config('services.modiam.token'))
->acceptJson()
->withHeaders(['Idempotency-Key' => $invoice->number])
->timeout(15)
->retry(3, 300)
->post('https://mizan-hesab.ir/api/v2/invoices', $payload);
$response->throw();
$result = $response->json();
Node.js / TypeScript
const response = await fetch('https://mizan-hesab.ir/api/v2/invoices', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.MODIAM_TOKEN}`,
'Idempotency-Key': invoice.externalId,
'Content-Type': 'application/json'
},
body: JSON.stringify(invoice)
});
if (!response.ok) throw new Error(await response.text());
const result = await response.json();
کدهای پاسخ و خطا
| HTTP | code | اقدام |
|---|---|---|
| 401 | unauthenticated | توکن را بررسی یا توکن جدید صادر کنید. |
| 402 | subscription_required | اشتراک شرکت را فعال کنید. |
| 403 | forbidden | scope توکن برای عملیات کافی نیست. |
| 409 | idempotency_conflict | برای بدنه جدید کلید جدید بسازید. |
| 422 | invalid_request | فیلدهای errors/details را اصلاح کنید. |
| 429 | rate_limit_exceeded | طبق Retry-After با backoff تلاش کنید. |
| 500/503 | server_error | با همان Idempotency-Key مجدداً تلاش کنید. |