MailLandDocs
حساب کاربری

صورتحساب

مدیریت اشتراک، مشاهده فاکتورها و نظارت بر مصرف

MailLand از Stripe برای مدیریت اشتراک و صورتحساب استفاده می‌کند. هر فضای کاری اشتراک مستقل خود را با قیمت‌گذاری مبتنی بر مصرف یا مبتنی بر طرح دارد. هر عضوی می‌تواند وضعیت صورتحساب را بخواند؛ فقط مالک فضای کاری می‌تواند آن را تغییر دهد (فراخوانی‌های تغییردهنده 403 INSUFFICIENT_PERMISSIONS برمی‌گردانند و کلیدهای API همیشه در آن نقاط پایانی رد می‌شوند).

وضعیت‌های پرداخت

paymentStatus به‌صورت یک رشته‌ی snake_case بازگردانده می‌شود، نه یک enum عددی:

وضعیتتوضیحات
currentاشتراک فعال، پرداخت به‌روز است
grace_periodپرداخت ناموفق، دوره مهلت فعال است
overdueپرداخت معوق، ویژگی‌ها محدود شده‌اند
blockedحساب به دلیل عدم پرداخت مسدود شده است

دریافت جزئیات اشتراک

GET https://api.mail.land/v1/account/subscription
Get subscription details
curl https://api.mail.land/v1/account/subscription \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Subscription response
{
  "planName": "Pro",
  "monthlyEmailLimit": 100000,
  "rateLimitPerSecond": 10,
  "pricePerMonth": 49.00,
  "startDate": "2026-01-15T08:00:00Z",
  "endDate": "2026-03-01T00:00:00Z",
  "status": "Active",
  "paymentStatus": "current",
  "marketingPausedDueToPayment": false,
  "sendingBlockedDueToPayment": false,
  "transactionalDailyLimit": 5000,
  "daysUntilBlocked": null,
  "cancelAtPeriodEnd": false,
  "planFamilyId": "fam_pro",
  "planTierPublicId": "tier_pro_monthly",
  "usage": {
    "emailsSentThisMonth": 45000,
    "monthlyLimit": 100000,
    "percentageUsed": 45.0,
    "transactionalCount": 30000,
    "marketingCount": 12000,
    "apiCount": 40000,
    "smtpCount": 5000,
    "campaignCount": 3000,
    "automationCount": 2000,
    "inboundForwardCount": 500
  }
}

هیچ id، planId، interval، currentPeriodStart/currentPeriodEnd، یا فیلدهای عددی تودرتوی paymentStatus/مصرف اعتبارسنجی/دامنه/تیم/اتوماسیون در این پاسخ وجود ندارد: از نام‌های فیلد بالا استفاده کنید. paymentStatus یک رشته‌ی snake_case است: "current"، "grace_period"، "overdue" یا "blocked". status به‌صورت PascalCase است ("Active"، "Suspended"، "Cancelled"): تنها استثنا حالت بدون اشتراک است که "active" با حروف کوچک برمی‌گرداند.

فیلدهای مصرف

فیلدتوضیحات
emailsSentThisMonthایمیل‌های ارسال‌شده در دوره‌ی صورتحساب جاری
monthlyLimitحداکثر ایمیل در هر دوره
percentageUsedدرصد emailsSentThisMonth از monthlyLimit
transactionalCountایمیل‌های تراکنشی ارسال‌شده
marketingCountایمیل‌های بازاریابی ارسال‌شده
apiCountایمیل‌های ارسال‌شده از طریق API
smtpCountایمیل‌های ارسال‌شده از طریق SMTP relay
campaignCountایمیل‌های ارسال‌شده توسط کمپین‌ها
automationCountایمیل‌های ارسال‌شده توسط اتوماسیون‌ها
inboundForwardCountایمیل‌های ارسال‌شده توسط قوانین بازارسال ورودی

هیچ شمارنده‌ی مصرف برای اعتبارسنجی، دامنه، اعضای تیم یا اتوماسیون در این پاسخ وجود ندارد، فقط شمارنده‌های ارسال ایمیل.

چه زمانی مصرف ایمیل شمارش می‌شود

گیرندگان در لحظه‌ای که پذیرش به‌طور پایدار ثبت می‌شود، در برابر مصرف و سهمیه‌ی شما (emailsSentThisMonth / monthlyLimit) شمارش می‌شوند. گیرندگانی که پیش از پذیرش رد یا سرکوب شوند، هرگز شمارش نمی‌شوند. یک بازگشت (bounce)، سرکوب پایین‌دستی، شکست تحویل یا هر نوع عدم‌تحویل دیگر که پس از پذیرش رخ دهد، به‌طور خودکار مصرف یا سهمیه را بازیابی یا پس نمی‌گیرد، شمارش به‌صورت گذشته‌نگر تعدیل نمی‌شود. این بخش تنها حسابداری مصرف را توصیف می‌کند؛ و بیانگر یا تلویحاً بیانگر قیمت‌گذاری Stripe به ازای هر ایمیل یا هرگونه حق استرداد نیست، که این‌ها جداگانه توسط شرایط اشتراک شما اداره می‌شوند.

سهمیه در هر دوره‌ی صورتحساب Stripe برای پلن‌های صورتحساب‌شده از طریق Stripe، یا در روز اول هر ماه تقویمی UTC برای پلن‌های غیر Stripe (Free و پلن‌های اعطاشده توسط مدیر) بازنشانی می‌شود، و همیشه به معنای Stripe از «هر دوره» نیست.

پلن‌ها و نگه‌داری داده

پلن‌ها عبارتند از Free، Pro و Max. لاگ‌های پیام به مدت ۳۰ روز در Free، ۹۰ روز در Pro و ۱۸۰ روز در Max نگه‌داری می‌شوند.

خلاصه سیاست

وضعیت تأیید فضای کاری و سیاست ارسال را دریافت کنید:

GET https://api.mail.land/v1/account/subscription/policy-summary
Get policy summary
curl https://api.mail.land/v1/account/subscription/policy-summary \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

پاسخ واقعی یک شیء تودرتو است، نه مسطح (SubscriptionController.cs:137-200):

Policy summary response
{
  "subscription": {
    "planFamilyId": "fam_pro",
    "planFamilyName": "Pro",
    "planTierId": "tier_pro_monthly",
    "monthlyQuota": 100000,
    "pricePerMonth": 49.00
  },
  "usage": {
    "usedThisMonth": 45000,
    "remainingThisMonth": 55000,
    "percentUsed": 45.0
  },
  "effectiveRates": {
    "transactionalRatePerMin": 600,
    "marketingRatePerMin": 300,
    "isOverridden": false
  },
  "domainWarmup": [
    {
      "domainId": "h4k7m1n9w2p5x8",
      "domainName": "example.com",
      "currentStage": 2,
      "totalStages": 5,
      "todaySentCount": 350,
      "dailyLimit": 500,
      "progressPercent": 70.0,
      "completed": false,
      "bypassed": false
    }
  ],
  "alerts": [
    {
      "type": "warning",
      "code": "QUOTA_WARNING",
      "message": "You have used 80% of your monthly quota. Consider upgrading your plan.",
      "actionUrl": "/billing"
    }
  ],
  "dailySendingLimit": {
    "limit": 5000,
    "usedToday": 1200,
    "remainingToday": 3800,
    "resetsAt": "2026-02-18T00:00:00Z"
  },
  "verification": {
    "level": 2,
    "levelName": "SenderVerified",
    "limits": {},
    "progress": {},
    "nextSteps": []
  }
}
فیلدتوضیحات
subscriptionخانواده‌ی پلن، سطح آن و سهمیه/قیمت ماهانه
usageایمیل‌های مصرف‌شده، باقی‌مانده و درصد مصرف در این ماه
effectiveRatesنرخ‌های ارسال مؤثر در هر دقیقه و اینکه آیا بازنویسی شده‌اند
domainWarmupپیشرفت گرم‌کردن هر دامنه، یک ورودی برای هر دامنه در حال گرم‌شدن
alertsهشدارهای فعال این فضای کاری (سهمیه، محدودیت روزانه و مشابه)
dailySendingLimitمحدودیت روزانه‌ی ارسال و سهمیه‌ی باقی‌مانده، در صورت وجود
verificationسطح تأیید فعلی، محدودیت‌ها، پیشرفت و گام‌های بعدی آن

ایجاد جلسه پرداخت

یک جلسه Stripe Checkout برای اشتراک یا ارتقا شروع کنید:

POST https://api.mail.land/v1/account/billing/checkout
Checkout request
{
  "planTierId": "tier_pro_monthly",
  "locale": "en",
  "businessAttested": true,
  "businessAttestationKey": "business-use-v3-button"
}
فیلدنوعالزامیتوضیحات
planTierIdstringبلهشناسه‌ی عمومی سطح پلن
localestringخیرزبان صفحه‌ی پرداخت میزبانی‌شده
businessAttestedbooleanبلهtrue تأیید می‌کند که MailLand را برای استفاده‌ی کسب‌وکاری یا حرفه‌ای می‌خرید (از جمله به‌عنوان فریلنسر، کاسب مستقل یا برای وب‌سایت شخصی خودتان). داشبورد آن را روی دکمه‌ی پرداخت می‌فرستد: برچسب دکمه «پرداخت برای استفاده‌ی کسب‌وکاری» (Pay for business use) است و یادداشتی یک‌خطی زیر آن توضیح می‌دهد که این کلیک چه چیزی را تأیید می‌کند
businessAttestationKeystringبلهنسخه‌ی متنی که تأیید به آن اشاره دارد؛ در حال حاضر business-use-v3-button (business-use-v1، متن قبلی، هنوز پذیرفته می‌شود)

درخواستی که businessAttested: true و یک businessAttestationKey پذیرفته‌شده نداشته باشد، پیش از هر پرداختی با 400 BUSINESS_ATTESTATION_REQUIRED رد می‌شود. MailLand ثبت می‌کند چه کسی، چه زمانی، با کدام متن (کلیدی که فرستاده‌اید) و با کدام زبان تأیید کرده است. در Stripe Checkout می‌توانید شناسه‌ی مالیاتی وارد کنید؛ این کار اختیاری است. قیمت‌ها بدون VAT هستند و MailLand مالیات بر ارزش افزوده دریافت نمی‌کند؛ شناسه‌ی VAT تأییدشده‌ی اتحادیه‌ی اروپا (خارج از بریتانیا) یادداشت reverse-charge را به صورت‌حساب‌های شما اضافه می‌کند.

هیچ فیلد successUrl یا cancelUrl وجود ندارد: آدرس‌های موفقیت/لغو توسط فراخواننده ارسال نمی‌شوند.

Create checkout session
curl -X POST https://api.mail.land/v1/account/billing/checkout \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{ "planTierId": "tier_pro_monthly", "locale": "en", "businessAttested": true, "businessAttestationKey": "business-use-v3-button" }'
Checkout response
{
  "upgraded": false,
  "sessionId": "cs_live_abc123...",
  "url": "https://checkout.stripe.com/c/pay/cs_live_abc123..."
}

کاربر را به url هدایت کنید تا پرداخت را در صفحه پرداخت میزبانی‌شده Stripe تکمیل کند. اگر فضای کاری از قبل اشتراک فعالی داشته باشد، پلن به‌جای باز شدن یک checkout جدید، در همان جا تغییر می‌کند: پاسخ { "upgraded": true } بدون sessionId/url است و هدایتی وجود ندارد. فقط زمانی هدایت کنید که url وجود داشته باشد.

پورتال صورتحساب

پورتال مشتری Stripe را برای مدیریت خودسرویس باز کنید (به‌روزرسانی روش پرداخت، لغو، مشاهده فاکتورها):

POST https://api.mail.land/v1/account/billing/portal
Portal request
{
  "locale": "en"
}

locale اختیاری است.

Open billing portal
curl -X POST https://api.mail.land/v1/account/billing/portal \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..." \
  -H "Content-Type: application/json" \
  -d '{ "locale": "en" }'
Portal response
{
  "url": "https://billing.stripe.com/p/session/abc123..."
}

کاربر را به url هدایت کنید تا به پورتال Stripe دسترسی داشته باشد.

فهرست فاکتورها

GET https://api.mail.land/v1/account/billing/invoices
پارامترنوعپیش‌فرضتوضیحات
limitint20تعداد فاکتورهایی که باید بازگردانده شوند
cursorstring-نشانگر مبهم از nextCursor در پاسخ قبلی
List invoices
curl https://api.mail.land/v1/account/billing/invoices \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
Invoices response
{
  "items": [
    {
      "publicId": "inv_abc123",
      "invoiceNumber": "INV-2026-0015",
      "stripeInvoiceId": "in_1AbCdEfGhIjKlMn",
      "status": "Paid",
      "amountDue": 4900,
      "amountPaid": 4900,
      "currency": "eur",
      "periodStart": "2026-01-01T00:00:00Z",
      "periodEnd": "2026-02-01T00:00:00Z",
      "paidAt": "2026-01-01T00:05:00Z",
      "hostedInvoiceUrl": "https://pay.stripe.com/invoice/inv_abc123",
      "invoicePdfUrl": "https://pay.stripe.com/invoice/inv_abc123/pdf",
      "createdAt": "2026-01-01T00:00:00Z"
    },
    {
      "publicId": "inv_def456",
      "invoiceNumber": "INV-2026-0014",
      "stripeInvoiceId": "in_2BcDeFgHiJkLmNo",
      "status": "Paid",
      "amountDue": 4900,
      "amountPaid": 4900,
      "currency": "eur",
      "periodStart": "2025-12-01T00:00:00Z",
      "periodEnd": "2026-01-01T00:00:00Z",
      "paidAt": "2025-12-01T00:05:00Z",
      "hostedInvoiceUrl": "https://pay.stripe.com/invoice/inv_def456",
      "invoicePdfUrl": "https://pay.stripe.com/invoice/inv_def456/pdf",
      "createdAt": "2025-12-01T00:00:00Z"
    }
  ],
  "nextCursor": null,
  "hasMore": false
}

این یک پاسخ صفحه‌بندی‌شده با cursor است، نه { "invoices": [...] }: برای دریافت صفحه‌ی بعدی، nextCursor را به‌عنوان پارامتر cursor ارسال کنید، و زمانی که hasMore برابر false بود متوقف شوید. اندازه‌ی پیش‌فرض صفحه ۲۰ است، نه ۱۰؛ نام فیلدها invoiceNumber، amountDue، amountPaid، hostedInvoiceUrl و invoicePdfUrl هستند (نه number، amount، invoiceUrl، invoicePdf).

مبالغ فاکتور بر حسب کوچک‌ترین واحد currency همان فاکتور هستند (سنت برای EUR). برای نمایش بر 100 تقسیم کنید. قیمت پلن‌ها به یورو (EUR) و بدون احتساب مالیات بر ارزش افزوده است.

پاسخ‌های خطا

وضعیتکدتوضیحات
400VALIDATION_FAILEDبدنه‌ی درخواست نامعتبر است
400INVALID_REQUESTسطح پلن وجود دارد اما با Stripe همگام‌سازی نشده است
403INSUFFICIENT_PERMISSIONSفقط مالک فضای کاری می‌تواند این تغییر را انجام دهد (خواندن صورتحساب برای هر عضوی باز است)
404RESOURCE_NOT_FOUNDسطح پلن ناشناخته یا غیرفعال
502STRIPE_ERRORدرخواست Stripe ناموفق بود

سایر Endpointهای صورتحساب

همچنین در دسترس‌اند و در بالا توضیح داده نشده‌اند: POST /v1/account/billing/cancel، POST /v1/account/billing/reactivate، و endpoint عمومی GET /public/plans/catalog.

مراحل بعدی

در این صفحه