مستندات APIv1

مستندات API

نسخه‌ی ۱

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

آدرس پایه

https://api.tpinta.com/v1
  • همه‌ی درخواست‌ها فقط روی HTTPS پذیرفته می‌شوند.
  • بدنه‌ی درخواست و پاسخ JSON با کدگذاری UTF-8 است؛ در درخواست‌های دارای بدنه، هدر Content-Type: application/json بفرستید.
  • نام فیلدها camelCase است. زمان‌ها به‌صورت UTC و در قالب ISO 8601 برگردانده می‌شوند.

شروع سریع

  1. وارد پنل شوید و از منوی «کلید API» یک کلید بسازید (برای ساخت، رمز پنل لازم است). کلید فقط یک بار نمایش داده می‌شود؛ آن را جای امن ذخیره کنید.
  2. با موبایل، رمز پنل و کلید API یک توکن بگیرید.
  3. توکن را در هدر Authorization: Bearer ... همه‌ی درخواست‌های بعدی بفرستید.
# ۱) دریافت توکن
curl -X POST https://api.tpinta.com/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{"mobile":"09120000000","password":"رمز-پنل","apiKey":"ei_..."}'

# ۲) استفاده از توکن
curl https://api.tpinta.com/v1/credit/balance \
  -H "Authorization: Bearer ACCESS_TOKEN"
const base = 'https://api.tpinta.com/v1';
const r = await fetch(base + '/auth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ mobile: '09120000000', password: 'رمز-پنل', apiKey: 'ei_...' })
});
const { data } = await r.json();

const bal = await fetch(base + '/credit/balance', {
  headers: { Authorization: 'Bearer ' + data.accessToken }
});
console.log(await bal.json());
using System.Net.Http.Json;
using System.Net.Http.Headers;

var http = new HttpClient { BaseAddress = new Uri("https://api.tpinta.com/v1/") };
var res = await http.PostAsJsonAsync("auth/token",
    new { mobile = "09120000000", password = "رمز-پنل", apiKey = "ei_..." });
var doc = await res.Content.ReadFromJsonAsync<System.Text.Json.JsonElement>();
var token = doc.GetProperty("data").GetProperty("accessToken").GetString();

http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
Console.WriteLine(await http.GetStringAsync("credit/balance"));
import requests

base = "https://api.tpinta.com/v1"
r = requests.post(base + "/auth/token", json={
    "mobile": "09120000000", "password": "رمز-پنل", "apiKey": "ei_..."})
token = r.json()["data"]["accessToken"]

b = requests.get(base + "/credit/balance", headers={"Authorization": "Bearer " + token})
print(b.json())

احراز هویت

هویت شما با سه مورد تأیید می‌شود: موبایل پنل، رمز پنل و کلید API. این سه فقط برای دریافت توکن لازم‌اند؛ بعد از آن فقط توکن می‌فرستید.

موردتوضیح
کلید APIبا پیشوند ei_ و ۴۶ نویسه. از پنل ساخته می‌شود؛ حداکثر ۵ کلید فعال برای هر حساب. با ابطال کلید در پنل، توکن‌های آن حداکثر ظرف حدود ۳۰ ثانیه از کار می‌افتند.
توکن (Bearer)پیش‌فرض ۶۰ دقیقه اعتبار دارد (مقدار دقیق در فیلد expiresIn بر حسب ثانیه می‌آید). پس از انقضا یا خطای 401 دوباره توکن بگیرید.
تغییر رمز پنلهمه‌ی توکن‌های قبلی را باطل می‌کند.
نکته‌ی امنیتی: رمز و کلید API را فقط در سمت سرور خود نگه دارید؛ هرگز در برنامه‌ی موبایل، کد جاوااسکریپت سمت کاربر یا مخزن کد (Git) قرار ندهید. در صورت لو رفتن، کلید را در پنل ابطال و رمز را عوض کنید.
پنج بار تلاش ناموفق برای یک کلید در ۱۵ دقیقه، آن کلید را موقتاً مسدود می‌کند (429 too_many_attempts). این مسدودسازی ورود به پنل را تحت تأثیر قرار نمی‌دهد.

قالب پاسخ‌ها

همه‌ی پاسخ‌ها (موفق یا ناموفق) یک قالب ثابت دارند.

موفق

{ "success": true, "data": { ... } }

ناموفق

{
  "success": false,
  "error": { "code": "validation_failed", "message": "نام مؤدی / شرکت را وارد کنید.", "field": "name" },
  "traceId": "00-4bf92f35..."
}
  • error.code را در برنامه‌ی خود بررسی کنید (ثابت است)؛ message فارسی و برای نمایش به انسان است و ممکن است تغییر کند.
  • field فقط برای خطاهای اعتبارسنجی می‌آید و نام فیلدِ بدنه‌ی درخواست است.
  • هنگام گزارش مشکل به پشتیبانی، مقدار traceId را همراه بفرستید.

کدهای خطا

HTTPcodeمعنی
400invalid_requestبدنه‌ی درخواست یا قالب آن درست نیست (JSON خراب، Content-Type نادرست و…)
400validation_failedمقدار یک فیلد نامعتبر است؛ فیلد در field آمده
401invalid_credentialsموبایل، رمز یا کلید API اشتباه است (عمداً مشخص نمی‌کنیم کدام)
401unauthorizedتوکن ارسال نشده، نامعتبر یا منقضی است
403forbiddenدسترسی به این منبع مجاز نیست
404not_foundمسیر یا منبع پیدا نشد
409conflictتداخل با داده‌ی موجود (مثلاً شماره اقتصادی تکراری)
422rule_violationدرخواست از نظر قالب درست است اما قانون کسب‌وکار اجازه نمی‌دهد
402insufficient_creditاعتبار حساب برای ثبت صورتحساب کافی نیست
409amount_warningمبلغ صورتحساب غیرعادی است؛ در صورت درست‌بودن با ackAmountWarning: true دوباره بفرستید
409request_in_progressدرخواست قبلی با همین clientRef هنوز در حال پردازش است؛ هدر Retry-After را ببینید
409idempotency_conflictهمین clientRef قبلاً با محتوای دیگری استفاده شده
422invoice_invalidاعتبارسنجی صورتحساب ناموفق بود؛ فهرست کامل خطاها در error.details و صورتحسابی ثبت نشده است
429too_many_attemptsتلاش ناموفق ورود بیش از حد؛ هدر Retry-After را ببینید
429rate_limitedتعداد درخواست بیش از سقف مجاز
500server_errorخطای داخلی؛ با traceId به پشتیبانی اطلاع دهید
503service_unavailableسرویس موقتاً در دسترس نیست؛ کمی بعد دوباره تلاش کنید

محدودیت نرخ (Rate Limit)

محدودهسقف پیش‌فرض
دریافت توکن۲۰ درخواست در ۱۰ دقیقه برای هر IP
درخواست‌های خواندنی۱۲۰ درخواست در دقیقه برای هر توکن
ارسال صورتحساب (POST /v1/invoices)۶۰ درخواست در دقیقه برای هر توکن
ارسال گروهی (POST /v1/invoices/batch)۱۰ درخواست در دقیقه برای هر توکن
درخواست‌های نوشتنی (ثبت و ویرایش شماره اقتصادی)۳۰ درخواست در ۱۰ دقیقه برای هر توکن
کل درخواست‌ها۶۰۰ درخواست در دقیقه برای هر IP

با عبور از سقف، پاسخ 429 با کد rate_limited می‌گیرید. سقف‌ها ممکن است در آینده تغییر کنند؛ برنامه‌ی شما باید با 429 کمی صبر کند و دوباره تلاش کند.

توصیه: توکن را تا پایان اعتبارش نگه دارید و دوباره از آن استفاده کنید؛ برای هر درخواست توکن جدید نگیرید.

دریافت توکن

POST/v1/auth/token
بدون نیاز به توکنسقف نرخ: ۲۰ درخواست در ۱۰ دقیقه برای هر IP

بدنه حداکثر ۴ کیلوبایت.

فیلدنوعالزامیتوضیح
mobilestringبلهموبایل ثبت‌شده در پنل (مثل 09120000000)
passwordstringبلهرمز پنل
apiKeystringبلهکلید API ساخته‌شده در پنل (ei_...)

نمونه درخواست

POST /v1/auth/token HTTP/1.1
Host: api.tpinta.com
Content-Type: application/json

{
  "mobile": "09120000000",
  "password": "رمز-پنل",
  "apiKey": "ei_..."
}

نمونه پاسخ موفق — 200

{
  "success": true,
  "data": {
    "accessToken": "CfDJ8...",
    "tokenType": "Bearer",
    "expiresIn": 3600
  }
}

نمونه پاسخ‌های خطا

اطلاعات اشتباه:

HTTP/1.1 401
{
  "success": false,
  "error": { "code": "invalid_credentials", "message": "اطلاعات ورود یا کلید API نامعتبر است." },
  "traceId": "00-4bf92f35..."
}

قالب نادرست موبایل، رمز یا کلید:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "invalid_request", "message": "موبایل، رمز یا کلید API در قالب درست نیست." },
  "traceId": "00-4bf92f35..."
}

تلاش ناموفق زیاد (هدر Retry-After بر حسب ثانیه می‌آید):

HTTP/1.1 429
Retry-After: 600
{
  "success": false,
  "error": { "code": "too_many_attempts", "message": "تلاش ناموفق بیش از حد مجاز بوده است؛ بعداً دوباره تلاش کنید." },
  "traceId": "00-4bf92f35..."
}

اطلاعات حساب

GET/v1/me
نیاز به توکنسقف نرخ: ۱۲۰ درخواست در دقیقه برای هر توکن

برای آزمایش اتصال و اطمینان از سالم‌بودن توکن. بدنه ندارد.

نمونه درخواست

GET /v1/me HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN

نمونه پاسخ موفق — 200

{ "success": true, "data": { "displayName": "شرکت نمونه", "mobile": "09120000000" } }

نمونه پاسخ خطا — توکن نامعتبر یا منقضی

HTTP/1.1 401
{
  "success": false,
  "error": { "code": "unauthorized", "message": "توکن دسترسی نامعتبر یا منقضی است. دوباره از /v1/auth/token توکن بگیرید." },
  "traceId": "00-4bf92f35..."
}

فهرست شماره‌های اقتصادی

GET/v1/economic-ids
نیاز به توکنسقف نرخ: ۱۲۰ درخواست در دقیقه برای هر توکن

همه‌ی شماره‌های اقتصادی حساب شما را برمی‌گرداند. بدنه و پارامتر ندارد.

نمونه درخواست

GET /v1/economic-ids HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN

نمونه پاسخ موفق — 200

{
  "success": true,
  "data": {
    "items": [
      {
        "id": 12,
        "code": "10101234567",
        "type": 1,
        "name": "شرکت نمونه",
        "branch": null,
        "nationalId": "10101234567",
        "memoryId": "A1B2C3",
        "isTest": true,
        "signingMode": 1,
        "active": true,
        "createdAt": "2026-10-20T08:15:00Z",
        "hasPrivateKey": true,
        "hasCertificate": true,
        "hasInvoices": false
      }
    ]
  }
}

کلید خصوصی و گواهی هرگز برگردانده نمی‌شوند؛ فقط وجود آن‌ها با hasPrivateKey و hasCertificate مشخص است. hasInvoices نشان می‌دهد با این شماره صورتحسابی ثبت شده است (در این حالت تغییر کد و محیط ممکن نیست).

اگر هنوز شماره‌ای ثبت نکرده باشید: { "success": true, "data": { "items": [] } }

نمونه پاسخ خطا — توکن نامعتبر یا منقضی

HTTP/1.1 401
{
  "success": false,
  "error": { "code": "unauthorized", "message": "توکن دسترسی نامعتبر یا منقضی است. دوباره از /v1/auth/token توکن بگیرید." },
  "traceId": "00-4bf92f35..."
}

ثبت شماره اقتصادی

POST/v1/economic-ids
نیاز به توکنسقف نرخ: ۳۰ درخواست نوشتنی در ۱۰ دقیقه برای هر توکن

محدودیت حجم بدنه: حدود ۶۰ کیلوبایت.

فیلدنوعالزامیتوضیح
typenumberبلهنوع مؤدی: 1 حقوقی · 2 حقیقی · 3 مشارکت مدنی · 4 اتباع غیرایرانی
namestringبلهنام مؤدی / شرکت؛ ۲ تا ۲۰۰ نویسه؛ نویسه‌های < و > مجاز نیست
codestringبلهشماره اقتصادی؛ فقط رقم. طول: ۱۱ رقم برای حقوقی و مشارکت مدنی، ۱۴ رقم برای حقیقی و اتباع
nationalIdstringبلهفقط رقم. حقوقی: شناسه ملی ۱۱ رقم · حقیقی: کد ملی ۱۰ رقم · مشارکت مدنی: شناسه مشارکت ۱۱ رقم · اتباع: کد فراگیر ۱۲ رقم
memoryIdstringبلهشناسه یکتای حافظه مالیاتی؛ ۶ نویسه‌ی حروف بزرگ انگلیسی یا عدد
branchstringخیرنام شعبه؛ حداکثر ۱۰۰ نویسه
isTestbooleanخیرtrue آزمایشی (sandbox) · false عملیاتی. پیش‌فرض: true
signingModenumberخیر1 امضا با گواهی · 2 بدون گواهی (فقط کلید خصوصی). پیش‌فرض: 1
privateKeystringبله*کلید خصوصی RSA حداقل ۲۰۴۸ بیت، بدون رمز، قالب PEM یا Base64
certificatestringبله*گواهی امضا (PEM یا Base64) که با کلید خصوصی تطبیق داشته باشد؛ در حالت signingMode = 2 لازم نیست
activebooleanخیرپیش‌فرض: true

* کلید خصوصی و گواهی با هم بررسی می‌شوند: کلید باید با گواهی جفت باشد، گواهی در محیط عملیاتی نباید منقضی باشد و تاریخ شروع آن نباید در آینده باشد.

نمونه درخواست

POST /v1/economic-ids HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "type": 1,
  "name": "شرکت نمونه",
  "code": "10101234567",
  "nationalId": "10101234567",
  "memoryId": "A1B2C3",
  "isTest": true,
  "privateKey": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
  "certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
}

نمونه پاسخ موفق — 201

{ "success": true, "data": { "id": 12 } }

نمونه پاسخ‌های خطا

فیلد نامعتبر (اینجا طول شماره اقتصادی):

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "شماره اقتصادی شخص حقوقی باید دقیقاً ۱۱ رقم باشد.", "field": "code" },
  "traceId": "00-4bf92f35..."
}

شماره تکراری در همان محیط (آزمایشی/عملیاتی):

HTTP/1.1 409
{
  "success": false,
  "error": { "code": "conflict", "message": "این شماره اقتصادی در همین محیط قبلاً ثبت شده است." },
  "traceId": "00-4bf92f35..."
}

توکن نامعتبر:

HTTP/1.1 401
{
  "success": false,
  "error": { "code": "unauthorized", "message": "توکن دسترسی نامعتبر یا منقضی است. دوباره از /v1/auth/token توکن بگیرید." },
  "traceId": "00-4bf92f35..."
}

کد 422 rule_violation هم برای قوانینی که دیتابیس اعمال می‌کند ممکن است؛ متن دقیق آن در message می‌آید.

ویرایش شماره اقتصادی

PUT/v1/economic-ids/{id}
نیاز به توکنسقف نرخ: ۳۰ درخواست نوشتنی در ۱۰ دقیقه برای هر توکن

ویرایش جزئی است: فقط فیلدهایی را بفرستید که می‌خواهید تغییر کنند؛ فیلدهای ارسال‌نشده بدون تغییر می‌مانند. فیلدها همان فیلدهای ثبت‌اند.

  • برای پاک‌کردن نام شعبه "branch": "" بفرستید.
  • برای تغییر کلید یا گواهی، هر دو را با هم بفرستید (تا تطبیق آن‌ها بررسی شود).
  • اگر با این شماره صورتحساب ثبت شده باشد، تغییر code و محیط (isTest) رد می‌شود (422).
  • برای فعال/غیرفعال‌کردن از مسیر جداگانه‌ی زیر استفاده کنید. حذف شماره اقتصادی از طریق API ممکن نیست و فقط از پنل انجام می‌شود.

نمونه درخواست

PUT /v1/economic-ids/12 HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{ "name": "شرکت نمونه (نام جدید)", "branch": "شعبه مرکزی" }

نمونه پاسخ موفق — 200

{ "success": true, "data": { "id": 12 } }

نمونه پاسخ‌های خطا

شماره‌ای با این id در حساب شما نیست:

HTTP/1.1 404
{
  "success": false,
  "error": { "code": "not_found", "message": "شماره اقتصادی یافت نشد." },
  "traceId": "00-4bf92f35..."
}

فیلد نامعتبر:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "نام مؤدی حداکثر ۲۰۰ نویسه می‌تواند باشد.", "field": "name" },
  "traceId": "00-4bf92f35..."
}

توکن نامعتبر: همان پاسخ 401 unauthorized بخش قبل. تغییر code یا isTest وقتی صورتحساب ثبت شده باشد، 422 rule_violation می‌دهد و متن آن در message است.

فعال / غیرفعال‌کردن

PUT/v1/economic-ids/{id}/active
نیاز به توکنسقف نرخ: ۳۰ درخواست نوشتنی در ۱۰ دقیقه برای هر توکن

نمونه درخواست

PUT /v1/economic-ids/12/active HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{ "active": false }

نمونه پاسخ موفق — 200

{ "success": true, "data": { "id": 12, "active": false } }

نمونه پاسخ‌های خطا

فیلد active ارسال نشده:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "فیلد active (true یا false) الزامی است.", "field": "active" },
  "traceId": "00-4bf92f35..."
}

شماره متعلق به حساب شما نیست یا وجود ندارد:

HTTP/1.1 404
{
  "success": false,
  "error": { "code": "not_found", "message": "شماره اقتصادی یافت نشد." },
  "traceId": "00-4bf92f35..."
}

مانده اعتبار

GET/v1/credit/balance
نیاز به توکنسقف نرخ: ۱۲۰ درخواست در دقیقه برای هر توکن

فقط‌خواندنی؛ شارژ حساب از طریق پنل انجام می‌شود. بدنه ندارد.

نمونه درخواست

GET /v1/credit/balance HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN

نمونه پاسخ موفق — 200

{
  "success": true,
  "data": {
    "balance": 1500000,
    "invoiceFee": 3000,
    "remainingInvoices": 500
  }
}
فیلدتوضیح
balanceمانده‌ی اعتبار، با همان واحدی که در پنل نمایش داده می‌شود
invoiceFeeهزینه‌ی هر صورتحساب
remainingInvoicesتعداد صورتحساب قابل ارسال با مانده‌ی فعلی؛ در صورت نبود هزینه‌ی تعریف‌شده null است

اعداد بالا فقط نمونه‌اند.

نمونه پاسخ خطا — توکن نامعتبر یا منقضی

HTTP/1.1 401
{
  "success": false,
  "error": { "code": "unauthorized", "message": "توکن دسترسی نامعتبر یا منقضی است. دوباره از /v1/auth/token توکن بگیرید." },
  "traceId": "00-4bf92f35..."
}

در صورت عبور از سقف نرخ:

HTTP/1.1 429
{
  "success": false,
  "error": { "code": "rate_limited", "message": "تعداد درخواست‌ها بیش از حد مجاز است؛ کمی بعد دوباره تلاش کنید." },
  "traceId": "00-4bf92f35..."
}

ارسال صورتحساب: مفاهیم

مسیر یک صورتحساب

  1. شما صورتحساب را با POST /v1/invoices می‌فرستید.
  2. سرور آن را کامل اعتبارسنجی می‌کند (همان قواعد پنل). اگر مشکل داشته باشد هیچ چیز ثبت نمی‌شود و اعتباری کم نمی‌شود؛ پاسخ 422 invoice_invalid با فهرست همه‌ی خطاها می‌آید.
  3. اگر درست باشد، شماره مالیاتی ساخته می‌شود، هزینه‌ی صورتحساب از اعتبار کم می‌شود و صورتحساب با وضعیت queued ثبت می‌شود.
  4. ارسال به سامانه‌ی مؤدیان بعداً و به‌صورت خودکار انجام می‌شود. وضعیت نهایی (success یا failed) را با استعلام بگیرید.

توجه: پاسخ موفق 201 یعنی صورتحساب «ثبت و در صف قرار گرفت»، نه اینکه سامانه‌ی مؤدیان آن را تأیید کرده باشد.

وضعیت‌ها

statusمعنی
queuedثبت شده و در صف ارسال است
processingدر حال ارسال یا پیگیری در سامانه‌ی مؤدیان
successسامانه‌ی مؤدیان صورتحساب را تأیید کرده؛ referenceNumber شماره‌ی پیگیری آن است
failedرد شده یا ارسال ناموفق بوده؛ علت در message است

جلوگیری از ارسال تکراری با clientRef

اگر درخواست ارسال را بفرستید و به‌خاطر قطعی شبکه یا timeout پاسخ را نگیرید، نمی‌دانید صورتحساب ثبت شده یا نه. دوباره‌فرستادن بدون احتیاط می‌تواند دو صورتحساب بسازد و دو بار اعتبار کم کند. برای همین هر درخواست ارسال باید یک clientRef یکتا داشته باشد (مثلاً شماره‌ی فاکتور داخلی خودتان یا یک UUID). قواعد:

حالتنتیجه
اولین ارسال201، صورتحساب ثبت می‌شود
تکرار با همان clientRef و همان محتوا (بعد از ثبت موفق)200 با duplicate: true و هدر Idempotent-Replayed: true؛ صورتحساب تازه‌ای ساخته نمی‌شود و همان taxId و وضعیت فعلی برمی‌گردد
همان clientRef با محتوای متفاوت409 idempotency_conflict
درخواست قبلی هنوز در جریان است409 request_in_progress با Retry-After؛ کمی بعد دوباره بفرستید
ارسال قبلی ناموفق بود (مثلاً 422)چیزی ثبت نشده، پس همان clientRef را می‌توانید با محتوای اصلاح‌شده دوباره استفاده کنید
روش درست: هنگام timeout یا خطای شبکه، همان درخواست را با همان clientRef و همان بدنه دوباره بفرستید، یا با GET /v1/invoices/by-ref/{clientRef} وضعیت را بپرسید. هیچ‌وقت با clientRef جدید دوباره نفرستید مگر مطمئن باشید صورتحساب قبلی ثبت نشده است.

clientRef: ۸ تا ۶۴ نویسه؛ فقط حروف انگلیسی، عدد و . _ : -. در هر حساب یکتاست و برای همیشه نگه‌داری می‌شود.

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

POST/v1/invoices
نیاز به توکنسقف نرخ: ۶۰ درخواست در دقیقه برای هر توکن

حداکثر حجم بدنه: ۱ مگابایت؛ حداکثر ۵۰۰ ردیف. نام فیلدهای اقلام، سربرگ اضافه و پرداخت همان نام‌های سند سامانه‌ی مؤدیان است (sstid، am، fee و…).

فیلدهای اصلی

فیلدنوعالزامیتوضیح
clientRefstringبلهشناسه‌ی یکتای درخواست (بخش بالا)
economicIdnumberبلهشناسه‌ی شماره اقتصادی صادرکننده (فیلد id در GET /v1/economic-ids؛ نه خود کد اقتصادی)
subjectnumberبلهموضوع صورتحساب: 1 اصلی · 2 اصلاحی · 3 ابطالی · 4 برگشت از فروش
patternnumberبله*الگوی صورتحساب (مثلاً 1 فروش، 2 فروش ارز، 3 طلا و جواهر، 4 قرارداد پیمانکاری، 5 قبوض خدماتی، 6 بلیط هواپیما، 7 صادرات، 8 بارنامه، 9 فرآورده‌های نفتی، 11 بورس کالا، 13 بیمه، 14 فروش زنجیره‌ای)
typenumberبله*نوع صورتحساب: 1 نوع اول (خریدار شناسایی‌شده) · 2 نوع دوم · 3 نوع سوم
buyerTypenumberبله*نوع شخص خریدار: 1 حقیقی · 2 حقوقی · 3 مشارکت مدنی · 4 اتباع غیرایرانی
referenceTaxIdstringشرطیشماره مالیاتی صورتحساب مرجع؛ برای اصلاحی، ابطالی و برگشت از فروش لازم است
issuedAtstringخیرزمان صدور به‌صورت ISO 8601 (مثل 2026-10-27T09:30:00+03:30). خالی = همین الان. زمان آینده پذیرفته نمی‌شود
buyerobjectشرطیtinb شماره اقتصادی خریدار · bid شناسه/کد ملی · bpc کد پستی. اطلاعات لازم به الگو و نوع خریدار بستگی دارد (پیام خطا دقیق می‌گوید)
headerExtraobjectشرطیفیلدهای سربرگ مخصوص الگو؛ مثلاً setm روش تسویه (1 نقدی · 2 نسیه · 3 نقدی/نسیه) که در نوع اول لازم است
itemsarrayبله*اقلام صورتحساب (توضیح پایین)
paymentobjectخیراطلاعات پرداخت با نام‌های سند: pmt، pv، trn، iinn، acn، trmn، pcn، pid، pdt
transportedGoodsarrayشرطیفقط الگوی بارنامه: آرایه‌ای از { "sgid": "...", "sgt": "..." }
article9booleanخیرارسال خارج از مهلت طبق ماده ۹ قانون پایانه‌های فروشگاهی
ackAmountWarningbooleanخیرتأیید هشدار «مبلغ غیرعادی» (پایین‌تر)

* برای صورتحساب ابطالی (subject: 3) لازم نیست: الگو، نوع، خریدار و اقلام از صورتحساب مرجع گرفته می‌شود و فقط referenceTaxId لازم است.

اقلام (items) و محاسبه‌ی خودکار مبالغ

هر ردیف یک شیء است. فیلدهای پایه‌ی معمول:

فیلدتوضیح
sstidشناسه‌ی کالا/خدمت؛ دقیقاً ۱۳ رقم و موجود در فهرست رسمی شناسه‌های کالا و خدمات
ssttشرح کالا/خدمت
amتعداد/مقدار
muکد واحد اندازه‌گیری (اختیاری در بیشتر الگوها)
feeمبلغ واحد (ریال)
disتخفیف ردیف (ریال)؛ پیش‌فرض ۰
vraنرخ مالیات بر ارزش افزوده (درصد؛ برای معاف ۰)

مبالغ محاسباتی ردیف را لازم نیست خودتان حساب کنید: اگر prdis (مبلغ قبل از تخفیف)، adis (مبلغ بعد از تخفیف)، vam (مالیات)، tsstam (مبلغ کل ردیف) و در الگوهای مربوط odam، olam، tcpbs را نفرستید، سرور آن‌ها را با همان فرمول پنل حساب می‌کند. اگر خودتان بفرستید همان مقدار شما استفاده و راستی‌آزمایی می‌شود و در صورت اشتباه خطای دقیق می‌گیرید؛ چیزی بی‌صدا تغییر نمی‌کند. جمع‌های سربرگ (tbill، tvam و…) همیشه از روی اقلام ساخته می‌شود و لازم نیست بفرستید. فیلدهای دیگر سند (مثل nw، cfee، exr، odr، olr، bsrn) هم با همان نام قابل ارسال‌اند. نام‌های ناشناخته نادیده گرفته می‌شوند.

نمونه درخواست

POST /v1/invoices HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "clientRef": "INV-2026-000123",
  "economicId": 12,
  "subject": 1,
  "pattern": 1,
  "type": 1,
  "buyerType": 2,
  "issuedAt": "2026-10-27T09:30:00+03:30",
  "buyer": { "tinb": "10101234567" },
  "headerExtra": { "setm": 1 },
  "items": [
    {
      "sstid": "1234567890123",
      "sstt": "خدمات نمونه",
      "am": 2,
      "fee": 1000000,
      "vra": 10
    }
  ]
}
curl -X POST https://api.tpinta.com/v1/invoices \
  -H "Authorization: Bearer ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"clientRef":"INV-2026-000123","economicId":12,"subject":1,"pattern":1,"type":1,"buyerType":2,
       "buyer":{"tinb":"10101234567"},"headerExtra":{"setm":1},
       "items":[{"sstid":"1234567890123","sstt":"خدمات نمونه","am":2,"fee":1000000,"vra":10}]}'

در این نمونه سرور مبالغ ردیف را حساب می‌کند: prdis = ۲٬۰۰۰٬۰۰۰ · vam = ۲۰۰٬۰۰۰ · tsstam = ۲٬۲۰۰٬۰۰۰. مقدار sstid نمونه است؛ شناسه‌ی واقعی کالا/خدمت خودتان را بگذارید.

نمونه پاسخ موفق — 201

{
  "success": true,
  "data": {
    "taxId": "A12B34C0000000123456XY",
    "clientRef": "INV-2026-000123",
    "status": "queued",
    "duplicate": false
  }
}

taxId شماره مالیاتی ۲۲ نویسه‌ای صورتحساب است؛ برای استعلام و گزارش‌ها نگه‌داریدش.

نمونه پاسخ تکراری (همان clientRef) — 200

HTTP/1.1 200
Idempotent-Replayed: true
{
  "success": true,
  "data": {
    "taxId": "A12B34C0000000123456XY",
    "clientRef": "INV-2026-000123",
    "status": "processing",
    "message": null,
    "referenceNumber": null,
    "duplicate": true
  }
}

نمونه پاسخ‌های خطا

اعتبارسنجی ناموفق؛ صورتحسابی ثبت نشده و اعتباری کم نشده است. همه‌ی خطاها یک‌جا در details می‌آید:

HTTP/1.1 422
{
  "success": false,
  "error": {
    "code": "invoice_invalid",
    "message": "اعتبارسنجی صورتحساب ناموفق بود (2 خطا). صورتحسابی ثبت نشد.",
    "details": [
      "ردیف 1: شناسه کالا/خدمت «1234567890123» در فهرست شناسه‌های کالا و خدمات یافت نشد.",
      "..."
    ]
  },
  "traceId": "00-4bf92f35..."
}

فیلد ناقص یا نامعتبر در خودِ بدنه:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "pattern (الگوی صورتحساب) الزامی است.", "field": "pattern" },
  "traceId": "00-4bf92f35..."
}

اعتبار کافی نیست:

HTTP/1.1 402
{
  "success": false,
  "error": { "code": "insufficient_credit", "message": "اعتبار حساب برای ثبت این صورتحساب کافی نیست." },
  "traceId": "00-4bf92f35..."
}

مبلغ غیرعادی (نسبت به سابقه‌ی همین شماره اقتصادی یا سقف تعیین‌شده در پنل). اگر مبلغ درست است، همان درخواست را با "ackAmountWarning": true دوباره بفرستید:

HTTP/1.1 409
{
  "success": false,
  "error": { "code": "amount_warning", "message": "مبلغ صورتحساب غیرعادی است. ... اگر مبلغ درست است، همان درخواست را با ackAmountWarning=true دوباره بفرستید." },
  "traceId": "00-4bf92f35..."
}

همان clientRef با محتوای دیگر:

HTTP/1.1 409
{
  "success": false,
  "error": { "code": "idempotency_conflict", "message": "این clientRef قبلاً با محتوای دیگری استفاده شده است. برای صورتحساب جدید clientRef تازه بفرستید.", "field": "clientRef" },
  "traceId": "00-4bf92f35..."
}

شماره اقتصادی پیدا نشد یا متعلق به حساب شما نیست: 404 not_found با field: "economicId".

استعلام وضعیت با شماره مالیاتی

GET/v1/invoices/{taxId}
نیاز به توکنسقف نرخ: ۱۲۰ درخواست در دقیقه برای هر توکن

وضعیت فعلی صورتحساب را از دیتابیس می‌خواند (نه مستقیم از سامانه‌ی مؤدیان). به‌روزرسانی وضعیت را ارسال خودکار انجام می‌دهد؛ پس بعد از ثبت، چند ثانیه تا چند دقیقه طول می‌کشد تا از queued به success یا failed برسد. توصیه: هر ۱۰ تا ۳۰ ثانیه یک بار استعلام کنید، نه پشت‌سرهم. فقط صورتحساب‌های خود حساب قابل استعلام است.

نمونه درخواست

GET /v1/invoices/A12B34C0000000123456XY HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN

نمونه پاسخ موفق — 200

{
  "success": true,
  "data": {
    "taxId": "A12B34C0000000123456XY",
    "status": "success",
    "message": null,
    "referenceNumber": "1234567890123456"
  }
}

برای failed، علت در message می‌آید. برای جزئیات کامل‌تر (اقلام، خطاها، صورتحساب‌های مرتبط) از گزارش ارسالی‌ها استفاده کنید.

نمونه پاسخ‌های خطا

شماره‌ی مالیاتی با قالب درست (۲۲ نویسه) ولی ناموجود، یا متعلق به حساب دیگر:

HTTP/1.1 404
{
  "success": false,
  "error": { "code": "not_found", "message": "صورتحساب یافت نشد." },
  "traceId": "00-4bf92f35..."
}

قالب نادرست:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "شماره مالیاتی باید ۲۲ نویسه‌ی حرف و عدد انگلیسی باشد.", "field": "taxId" },
  "traceId": "00-4bf92f35..."
}

توکن نامعتبر یا منقضی: 401 unauthorized مثل بخش‌های قبل.

استعلام وضعیت با clientRef

GET/v1/invoices/by-ref/{clientRef}
نیاز به توکنسقف نرخ: ۱۲۰ درخواست در دقیقه برای هر توکن

برای وقتی که پاسخ ارسال به دست شما نرسیده (قطعی شبکه یا timeout) و taxId را ندارید.

نمونه درخواست

GET /v1/invoices/by-ref/INV-2026-000123 HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN

نمونه پاسخ موفق — 200

{
  "success": true,
  "data": {
    "clientRef": "INV-2026-000123",
    "taxId": "A12B34C0000000123456XY",
    "status": "queued",
    "message": null,
    "referenceNumber": null
  }
}
statusمعنی
pendingاین clientRef رزرو شده ولی صورتحساب هنوز ثبت نشده است (درخواست در جریان است یا نیمه‌کاره مانده). taxId ممکن است null باشد. بعد از حدود یک دقیقه، همان درخواست را با همان clientRef و همان بدنه دوباره بفرستید.
queued · processing · success · failedمثل استعلام با شماره مالیاتی

نمونه پاسخ خطا

چنین clientRefی برای حساب شما ثبت نشده (مثلاً ارسال شما هرگز به سرور نرسیده، یا قبلاً با خطای اعتبارسنجی رد شده):

HTTP/1.1 404
{
  "success": false,
  "error": { "code": "not_found", "message": "درخواستی با این clientRef پیدا نشد." },
  "traceId": "00-4bf92f35..."
}

ارسال گروهی صورتحساب

POST/v1/invoices/batch
نیاز به توکنسقف نرخ: ۱۰ درخواست در دقیقه برای هر توکنحداکثر ۵۰ صورتحساب در هر درخواست

چند صورتحساب را در یک درخواست می‌فرستید. هر مورد دقیقاً مثل ارسال تکی پردازش می‌شود: همان قواعد اعتبارسنجی، همان clientRef و همان محاسبه‌ی خودکار مبالغ. موارد پشت سر هم پردازش می‌شوند و شکست یک مورد بقیه را متوقف نمی‌کند.

  • بدنه فقط یک فیلد دارد: invoices (آرایه). هر عنصر همان بدنه‌ی ارسال صورتحساب است و clientRef مستقل دارد. clientRef تکراری در همین درخواست، برای مورد دوم به بعد خطا می‌دهد.
  • حداکثر حجم بدنه ۵ مگابایت و حداکثر تعداد ۵۰ صورتحساب است. فهرست خالی یا بیش از ۵۰ مورد، کل درخواست را با 400 validation_failed رد می‌کند و چیزی ثبت نمی‌شود.
  • پردازش پشت سر هم است، پس درخواست‌های بزرگ چند ثانیه طول می‌کشند. زمان‌سنج (timeout) سمت خودتان را حداقل ۶۰ ثانیه بگذارید و برای شروع، دسته‌های ۱۰ تا ۲۰ تایی را امتحان کنید.

نمونه درخواست

POST /v1/invoices/batch HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{
  "invoices": [
    {
      "clientRef": "INV-2026-000201",
      "economicId": 12, "subject": 1, "pattern": 1, "type": 1, "buyerType": 2,
      "buyer": { "tinb": "10101234567" }, "headerExtra": { "setm": 1 },
      "items": [ { "sstid": "1234567890123", "sstt": "خدمات نمونه", "am": 2, "fee": 1000000, "vra": 10 } ]
    },
    {
      "clientRef": "INV-2026-000202",
      "economicId": 12, "subject": 1, "pattern": 1, "type": 1, "buyerType": 2,
      "buyer": { "tinb": "10101234567" }, "headerExtra": { "setm": 1 },
      "items": [ { "sstid": "1234567890123", "sstt": "خدمات نمونه", "am": 1, "fee": 500000, "vra": 10 } ]
    }
  ]
}

نمونه پاسخ — 200

{
  "success": true,
  "data": {
    "summary": { "total": 4, "accepted": 1, "replayed": 1, "failed": 2 },
    "results": [
      { "index": 0, "clientRef": "INV-2026-000201", "ok": true,
        "taxId": "A12B34C0000000123456XY", "status": "queued", "duplicate": false },
      { "index": 1, "clientRef": "INV-2026-000202", "ok": true,
        "taxId": "A12B34C0000000123457XZ", "status": "success", "duplicate": true },
      { "index": 2, "clientRef": "INV-2026-000203", "ok": false,
        "error": {
          "code": "invoice_invalid",
          "message": "اعتبارسنجی صورتحساب ناموفق بود (1 خطا). صورتحسابی ثبت نشد.",
          "details": [ "ردیف 1: شناسه کالا/خدمت «1234567890123» در فهرست شناسه‌های کالا و خدمات یافت نشد." ]
        } },
      { "index": 3, "clientRef": "INV-2026-000201", "ok": false,
        "error": {
          "code": "validation_failed",
          "message": "این clientRef در همین درخواست تکراری است؛ برای هر صورتحساب clientRef جداگانه بفرستید.",
          "field": "invoices[3].clientRef"
        } }
    ]
  }
}

چطور پاسخ را بخوانیم

  • کد ۲۰۰ یعنی «درخواست پردازش شد»، نه «همه‌ی صورتحساب‌ها ثبت شدند». موفقیت هر مورد را در results[i].ok بررسی کنید. خلاصه در summary است.
  • ترتیب results با ترتیب invoices یکی است و index جایگاه مورد (از صفر) را می‌گوید.
  • خطای هر مورد همان کدهای جدول کدهای خطا را دارد (invoice_invalid، insufficient_credit، amount_warning، request_in_progress، idempotency_conflict، validation_failed، not_found). در error.field مسیر کامل فیلد می‌آید، مثل invoices[3].clientRef.
  • مورد با duplicate: true قبلاً با همان clientRef ثبت شده بود؛ صورتحساب تازه‌ای ساخته نشد و status وضعیت فعلی آن است.
  • ok: true با status: queued فقط یعنی ثبت و در صف ارسال قرار گرفت؛ وضعیت نهایی را با استعلام گروهی بگیرید.
خطای داخلی (server_error) در یک مورد: یعنی نتیجه‌ی آن مورد مشخص نیست یا امتحان نشده است (اگر چند مورد پشت سر هم با خطای داخلی شکست بخورند، بقیه‌ی موارد امتحان نمی‌شوند). همان مورد را با همان clientRef دوباره بفرستید؛ اگر قبلاً ثبت شده باشد، تکراری ساخته نمی‌شود و نتیجه‌ی قبلی برمی‌گردد. اگر پاسخ کل درخواست به دست شما نرسید (timeout)، همه‌ی clientRefها را با استعلام گروهی بررسی کنید.
چون هر صورتحساب جدا ثبت و جدا اعتبار می‌خورد، اگر اعتبار حساب وسط دسته تمام شود، موارد اول ثبت و موارد بعدی با 402 insufficient_credit رد می‌شوند. قبل از دسته‌های بزرگ، مانده اعتبار را بررسی کنید.

استعلام گروهی وضعیت

POST/v1/invoices/status
نیاز به توکنسقف نرخ: ۱۲۰ درخواست در دقیقه برای هر توکنحداکثر ۱۰۰ مورد در هر درخواست

وضعیت چند صورتحساب را یک‌جا می‌گیرید، با فهرستی از شماره‌های مالیاتی (taxIds) یا فهرستی از clientRefها (clientRefs). هر درخواست دقیقاً یکی از این دو را دارد. متد POST است فقط چون فهرست در بدنه می‌آید؛ چیزی تغییر نمی‌کند.

نمونه درخواست

POST /v1/invoices/status HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json

{ "clientRefs": [ "INV-2026-000201", "INV-2026-000202", "INV-2026-000999", "x" ] }

نمونه پاسخ — 200

{
  "success": true,
  "data": {
    "total": 4,
    "results": [
      { "index": 0, "clientRef": "INV-2026-000201", "taxId": "A12B34C0000000123456XY", "found": true,
        "status": "success", "message": null, "referenceNumber": "1234567890" },
      { "index": 1, "clientRef": "INV-2026-000202", "taxId": "A12B34C0000000123457XZ", "found": true,
        "status": "queued", "message": null, "referenceNumber": null },
      { "index": 2, "clientRef": "INV-2026-000999", "taxId": null, "found": false },
      { "index": 3, "clientRef": "x", "taxId": null, "found": false,
        "error": { "code": "validation_failed", "message": "clientRef باید ۸ تا ۶۴ نویسه و فقط شامل حروف انگلیسی، عدد و نویسه‌های . _ : - باشد." } }
    ]
  }
}
  • با taxIds به‌جای clientRef فیلد taxId همان مقدار ورودی است.
  • found: false بدون error یعنی چنین صورتحساب یا clientRefی برای حساب شما ثبت نشده؛ خطا نیست. با error یعنی قالب آن مورد نادرست بوده است.
  • معنی status مثل استعلام تکی است؛ برای clientRef مقدار pending هم ممکن است.
  • خطای کل درخواست (هر دو فهرست پر یا هر دو خالی، یا بیش از ۱۰۰ مورد): 400 validation_failed با field برابر taxIds یا clientRefs.

گزارش‌ها: قواعد مشترک

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

بازه‌ی تاریخ

  • بازه بر اساس تاریخ صدور صورتحساب (issuedAt) است، نه زمان ارسال به سامانه.
  • تاریخ‌ها میلادی و UTC هستند. قالب‌های مجاز: 2026-10-01 (نیمه‌شب UTC) یا 2026-10-01T08:30:00Z (با Z یا offset مثل +03:30).
  • from شامل خودش و to بدون خودش است. برای کل مهرماه میلادی: from=2026-10-01&to=2026-11-01.
  • اگر هیچ‌کدام را نفرستید، ۳۰ روز اخیر برگردانده می‌شود. اگر فقط from بفرستید، to برابر from + ۹۲ روز (حداکثر تا فردا) و اگر فقط to بفرستید، from برابر ۳۰ روز قبل از آن است.
  • طول بازه حداکثر ۹۲ روز است. برای بازه‌ی بلندتر، چند درخواست پشت‌سرهم بفرستید.

صفحه‌بندی

پارامترتوضیح
pageشماره‌ی صفحه، از ۱ (پیش‌فرض ۱)
sizeتعداد در صفحه، ۱ تا ۱۰۰ (پیش‌فرض ۱۰)

پاسخ شامل total (تعداد کل نتایج)، page، size و items است. تعداد صفحه‌ها = ceil(total / size). اگر page از آخرین صفحه بیشتر باشد، items خالی و total برابر ۰ است؛ پس تعداد کل را از صفحه‌ی اول بخوانید.

پارامتر نامعتبر هیچ‌وقت بی‌صدا نادیده گرفته نمی‌شود؛ 400 validation_failed با نام پارامتر در field می‌گیرید.

گزارش صورتحساب‌های ارسالی

GET/v1/reports/invoices
نیاز به توکنسقف نرخ: ۱۲۰ درخواست در دقیقه برای هر توکن

فهرست صورتحساب‌های ثبت‌شده با هر کانالی (ویزارد، اکسل یا API) در بازه‌ی انتخابی.

پارامترهای query (همه اختیاری)

پارامترتوضیح
from · toبازه‌ی تاریخ صدور؛ قواعد در بخش «قواعد مشترک»
statusqueued در صف · processing در حال پردازش یا استعلام · success موفق · failed ناموفق
economicIdشناسه‌ی شماره اقتصادی (همان id در فهرست شماره‌های اقتصادی، نه خود کد)
subjectموضوع صورتحساب: 1 اصلی · 2 اصلاحی · 3 ابطالی · 4 برگشت از فروش
patternالگوی صورتحساب، عدد ۱ تا ۳۰ طبق جدول الگوهای سامانه‌ی مودیان
channelکانال ثبت: 1 ویزارد · 2 اکسل · 3 API
qجست‌وجو: ابتدای شماره‌ی یکتا، شماره‌ی صورتحساب یا شناسه‌ی خریدار (حداکثر ۵۰ نویسه)
sortdate (پیش‌فرض) · status · taxid · eco · ins · inp · buyer · amount
dirdesc (پیش‌فرض) یا asc
page · sizeصفحه‌بندی

نمونه درخواست

GET /v1/reports/invoices?from=2026-10-01&to=2026-11-01&status=failed&size=25&page=1 HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN

نمونه پاسخ موفق — 200

{
  "success": true,
  "data": {
    "total": 1,
    "page": 1,
    "size": 25,
    "items": [
      {
        "taxId": "A1B2C3...",
        "issuedAt": "2026-10-12T09:30:00Z",
        "subject": 1,
        "pattern": 1,
        "type": 1,
        "amount": 2850000,
        "parentTaxId": null,
        "economicId": 12,
        "economicCode": "10101234567",
        "companyName": "شرکت نمونه",
        "buyerId": "10380123456",
        "buyerType": 2,
        "status": "failed",
        "error": "متن خطا از سامانه‌ی مودیان",
        "relatedCount": 0,
        "hasActiveChild": false,
        "channel": 3
      }
    ]
  }
}
فیلدتوضیح
taxIdشماره‌ی یکتای مالیاتی (۲۲ نویسه)
issuedAtتاریخ و زمان صدور (UTC)
subject · patternموضوع و الگوی صورتحساب (کدها مثل پارامترهای بالا)
typeنوع صورتحساب: 1 نوع اول · 2 نوع دوم · 3 نوع سوم
amountمبلغ کل صورتحساب
parentTaxIdشماره‌ی یکتای صورتحساب مرجع (برای اصلاحی، ابطالی و برگشتی)؛ در غیر این صورت null
economicId · economicCode · companyNameشماره اقتصادی صادرکننده
buyerId · buyerTypeشناسه‌ی خریدار و نوع او: 1 حقیقی · 2 حقوقی · 3 مشارکت مدنی · 4 اتباع غیرایرانی
statusوضعیت: queued · processing · success · failed
errorخلاصه‌ی علت خطا (حداکثر ۳۰۰ نویسه) و فقط وقتی status = failed؛ در غیر این صورت null
relatedCountتعداد صورتحساب‌هایی که این صورتحساب را مرجع قرار داده‌اند
hasActiveChildtrue یعنی برای این صورتحساب یک اصلاحی/ابطالی/برگشتی فعال ثبت شده و دیگر نمی‌تواند مرجع شود؛ سند جدید ملاک است
channelکانال ثبت

نمونه پاسخ‌های خطا

مقدار نامعتبر:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "مقدار status معتبر نیست (success | processing | queued | failed).", "field": "status" },
  "traceId": "00-4bf92f35..."
}

بازه‌ی بیش از ۹۲ روز:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "طول بازه‌ی تاریخ حداکثر ۹۲ روز است.", "field": "to" },
  "traceId": "00-4bf92f35..."
}

توکن نامعتبر:

HTTP/1.1 401
{
  "success": false,
  "error": { "code": "unauthorized", "message": "توکن دسترسی نامعتبر یا منقضی است. دوباره از /v1/auth/token توکن بگیرید." },
  "traceId": "00-4bf92f35..."
}

گزارش خطاها

GET/v1/reports/errors
نیاز به توکنسقف نرخ: ۱۲۰ درخواست در دقیقه برای هر توکن

صورتحساب‌هایی که در یکی از مراحل رد شده‌اند، به‌همراه علت. هر صورتحساب یک ردیف دارد و در message مهم‌ترین علت آمده است.

پارامترهای query (همه اختیاری)

پارامترتوضیح
from · toبازه‌ی تاریخ صدور؛ قواعد در بخش «قواعد مشترک»
sourceمرحله‌ی خطا: validation رد در کنترل‌های سامانه پیش از ارسال · submit رد هنگام ارسال به سامانه‌ی مودیان · inquiry رد در استعلام نهایی
economicIdشناسه‌ی شماره اقتصادی
qابتدای شماره‌ی یکتا، شماره‌ی صورتحساب، کد خطا یا بخشی از متن خطا (برای جست‌وجو در متن حداقل ۳ نویسه)
page · sizeصفحه‌بندی

نتایج از جدیدترین صورتحساب به قدیمی‌ترین مرتب می‌شوند.

نمونه درخواست

GET /v1/reports/errors?from=2026-10-01&to=2026-11-01&source=submit HTTP/1.1
Host: api.tpinta.com
Authorization: Bearer ACCESS_TOKEN

نمونه پاسخ موفق — 200

{
  "success": true,
  "data": {
    "total": 1,
    "page": 1,
    "size": 10,
    "items": [
      {
        "taxId": "A1B2C3...",
        "issuedAt": "2026-10-12T09:30:00Z",
        "subject": 1,
        "pattern": 1,
        "amount": 2850000,
        "economicId": 12,
        "economicCode": "10101234567",
        "companyName": "شرکت نمونه",
        "buyerId": "10380123456",
        "buyerType": 2,
        "source": "submit",
        "code": "400",
        "message": "متن خطا از سامانه‌ی مودیان",
        "errorCount": 1
      }
    ]
  }
}
فیلدتوضیح
sourceمرحله‌ی خطا (همان مقدارهای پارامتر source)
codeکد خطا؛ برای validation همیشه null است
messageمتن علت خطا (حداکثر ۱۰۰۰ نویسه). برای validation ممکن است چند خط باشد
errorCountتعداد خطاهای ثبت‌شده برای این صورتحساب
بقیه‌ی فیلدهاهمان معنی گزارش ارسالی‌ها

نمونه پاسخ‌های خطا

مقدار نامعتبر:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "مقدار source معتبر نیست (validation | submit | inquiry).", "field": "source" },
  "traceId": "00-4bf92f35..."
}

تاریخ با قالب نادرست:

HTTP/1.1 400
{
  "success": false,
  "error": { "code": "validation_failed", "message": "مقدار from باید تاریخ میلادی مثل 2026-10-01 یا 2026-10-01T08:30:00Z باشد.", "field": "from" },
  "traceId": "00-4bf92f35..."
}

توکن نامعتبر: همان پاسخ 401 unauthorized گزارش قبلی.