مستندات API
نسخهی ۱
با این API میتوانید بدون ورود به پنل، شمارههای اقتصادی خود را مدیریت کنید، ماندهی اعتبار را بخوانید و گزارش صورتحسابهای ارسالی و خطاها را دریافت کنید. ارسال و استعلام وضعیت صورتحساب هم، هم بهصورت تکی و هم گروهی، ممکن است.
آدرس پایه
https://api.tpinta.com/v1
- همهی درخواستها فقط روی HTTPS پذیرفته میشوند.
- بدنهی درخواست و پاسخ
JSONبا کدگذاری UTF-8 است؛ در درخواستهای دارای بدنه، هدرContent-Type: application/jsonبفرستید. - نام فیلدها camelCase است. زمانها بهصورت UTC و در قالب ISO 8601 برگردانده میشوند.
شروع سریع
- وارد پنل شوید و از منوی «کلید API» یک کلید بسازید (برای ساخت، رمز پنل لازم است). کلید فقط یک بار نمایش داده میشود؛ آن را جای امن ذخیره کنید.
- با موبایل، رمز پنل و کلید API یک توکن بگیرید.
- توکن را در هدر
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 دوباره توکن بگیرید. |
| تغییر رمز پنل | همهی توکنهای قبلی را باطل میکند. |
429 too_many_attempts). این مسدودسازی ورود به پنل را تحت تأثیر قرار نمیدهد.قالب پاسخها
همهی پاسخها (موفق یا ناموفق) یک قالب ثابت دارند.
موفق
{ "success": true, "data": { ... } }
ناموفق
{
"success": false,
"error": { "code": "validation_failed", "message": "نام مؤدی / شرکت را وارد کنید.", "field": "name" },
"traceId": "00-4bf92f35..."
}
error.codeرا در برنامهی خود بررسی کنید (ثابت است)؛messageفارسی و برای نمایش به انسان است و ممکن است تغییر کند.fieldفقط برای خطاهای اعتبارسنجی میآید و نام فیلدِ بدنهی درخواست است.- هنگام گزارش مشکل به پشتیبانی، مقدار
traceIdرا همراه بفرستید.
کدهای خطا
| HTTP | code | معنی |
|---|---|---|
| 400 | invalid_request | بدنهی درخواست یا قالب آن درست نیست (JSON خراب، Content-Type نادرست و…) |
| 400 | validation_failed | مقدار یک فیلد نامعتبر است؛ فیلد در field آمده |
| 401 | invalid_credentials | موبایل، رمز یا کلید API اشتباه است (عمداً مشخص نمیکنیم کدام) |
| 401 | unauthorized | توکن ارسال نشده، نامعتبر یا منقضی است |
| 403 | forbidden | دسترسی به این منبع مجاز نیست |
| 404 | not_found | مسیر یا منبع پیدا نشد |
| 409 | conflict | تداخل با دادهی موجود (مثلاً شماره اقتصادی تکراری) |
| 422 | rule_violation | درخواست از نظر قالب درست است اما قانون کسبوکار اجازه نمیدهد |
| 402 | insufficient_credit | اعتبار حساب برای ثبت صورتحساب کافی نیست |
| 409 | amount_warning | مبلغ صورتحساب غیرعادی است؛ در صورت درستبودن با ackAmountWarning: true دوباره بفرستید |
| 409 | request_in_progress | درخواست قبلی با همین clientRef هنوز در حال پردازش است؛ هدر Retry-After را ببینید |
| 409 | idempotency_conflict | همین clientRef قبلاً با محتوای دیگری استفاده شده |
| 422 | invoice_invalid | اعتبارسنجی صورتحساب ناموفق بود؛ فهرست کامل خطاها در error.details و صورتحسابی ثبت نشده است |
| 429 | too_many_attempts | تلاش ناموفق ورود بیش از حد؛ هدر Retry-After را ببینید |
| 429 | rate_limited | تعداد درخواست بیش از سقف مجاز |
| 500 | server_error | خطای داخلی؛ با traceId به پشتیبانی اطلاع دهید |
| 503 | service_unavailable | سرویس موقتاً در دسترس نیست؛ کمی بعد دوباره تلاش کنید |
محدودیت نرخ (Rate Limit)
| محدوده | سقف پیشفرض |
|---|---|
| دریافت توکن | ۲۰ درخواست در ۱۰ دقیقه برای هر IP |
| درخواستهای خواندنی | ۱۲۰ درخواست در دقیقه برای هر توکن |
ارسال صورتحساب (POST /v1/invoices) | ۶۰ درخواست در دقیقه برای هر توکن |
ارسال گروهی (POST /v1/invoices/batch) | ۱۰ درخواست در دقیقه برای هر توکن |
| درخواستهای نوشتنی (ثبت و ویرایش شماره اقتصادی) | ۳۰ درخواست در ۱۰ دقیقه برای هر توکن |
| کل درخواستها | ۶۰۰ درخواست در دقیقه برای هر IP |
با عبور از سقف، پاسخ 429 با کد rate_limited میگیرید. سقفها ممکن است در آینده تغییر کنند؛ برنامهی شما باید با 429 کمی صبر کند و دوباره تلاش کند.
دریافت توکن
بدنه حداکثر ۴ کیلوبایت.
| فیلد | نوع | الزامی | توضیح |
|---|---|---|---|
mobile | string | بله | موبایل ثبتشده در پنل (مثل 09120000000) |
password | string | بله | رمز پنل |
apiKey | string | بله | کلید 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 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 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..."
}
ثبت شماره اقتصادی
محدودیت حجم بدنه: حدود ۶۰ کیلوبایت.
| فیلد | نوع | الزامی | توضیح |
|---|---|---|---|
type | number | بله | نوع مؤدی: 1 حقوقی · 2 حقیقی · 3 مشارکت مدنی · 4 اتباع غیرایرانی |
name | string | بله | نام مؤدی / شرکت؛ ۲ تا ۲۰۰ نویسه؛ نویسههای < و > مجاز نیست |
code | string | بله | شماره اقتصادی؛ فقط رقم. طول: ۱۱ رقم برای حقوقی و مشارکت مدنی، ۱۴ رقم برای حقیقی و اتباع |
nationalId | string | بله | فقط رقم. حقوقی: شناسه ملی ۱۱ رقم · حقیقی: کد ملی ۱۰ رقم · مشارکت مدنی: شناسه مشارکت ۱۱ رقم · اتباع: کد فراگیر ۱۲ رقم |
memoryId | string | بله | شناسه یکتای حافظه مالیاتی؛ ۶ نویسهی حروف بزرگ انگلیسی یا عدد |
branch | string | خیر | نام شعبه؛ حداکثر ۱۰۰ نویسه |
isTest | boolean | خیر | true آزمایشی (sandbox) · false عملیاتی. پیشفرض: true |
signingMode | number | خیر | 1 امضا با گواهی · 2 بدون گواهی (فقط کلید خصوصی). پیشفرض: 1 |
privateKey | string | بله* | کلید خصوصی RSA حداقل ۲۰۴۸ بیت، بدون رمز، قالب PEM یا Base64 |
certificate | string | بله* | گواهی امضا (PEM یا Base64) که با کلید خصوصی تطبیق داشته باشد؛ در حالت signingMode = 2 لازم نیست |
active | boolean | خیر | پیشفرض: 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 میآید.
ویرایش شماره اقتصادی
ویرایش جزئی است: فقط فیلدهایی را بفرستید که میخواهید تغییر کنند؛ فیلدهای ارسالنشده بدون تغییر میمانند. فیلدها همان فیلدهای ثبتاند.
- برای پاککردن نام شعبه
"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/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 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..."
}
ارسال صورتحساب: مفاهیم
مسیر یک صورتحساب
- شما صورتحساب را با
POST /v1/invoicesمیفرستید. - سرور آن را کامل اعتبارسنجی میکند (همان قواعد پنل). اگر مشکل داشته باشد هیچ چیز ثبت نمیشود و اعتباری کم نمیشود؛ پاسخ
422 invoice_invalidبا فهرست همهی خطاها میآید. - اگر درست باشد، شماره مالیاتی ساخته میشود، هزینهی صورتحساب از اعتبار کم میشود و صورتحساب با وضعیت
queuedثبت میشود. - ارسال به سامانهی مؤدیان بعداً و بهصورت خودکار انجام میشود. وضعیت نهایی (
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 را میتوانید با محتوای اصلاحشده دوباره استفاده کنید |
GET /v1/invoices/by-ref/{clientRef} وضعیت را بپرسید. هیچوقت با clientRef جدید دوباره نفرستید مگر مطمئن باشید صورتحساب قبلی ثبت نشده است.clientRef: ۸ تا ۶۴ نویسه؛ فقط حروف انگلیسی، عدد و . _ : -. در هر حساب یکتاست و برای همیشه نگهداری میشود.
ارسال صورتحساب
حداکثر حجم بدنه: ۱ مگابایت؛ حداکثر ۵۰۰ ردیف. نام فیلدهای اقلام، سربرگ اضافه و پرداخت همان نامهای سند سامانهی مؤدیان است (sstid، am، fee و…).
فیلدهای اصلی
| فیلد | نوع | الزامی | توضیح |
|---|---|---|---|
clientRef | string | بله | شناسهی یکتای درخواست (بخش بالا) |
economicId | number | بله | شناسهی شماره اقتصادی صادرکننده (فیلد id در GET /v1/economic-ids؛ نه خود کد اقتصادی) |
subject | number | بله | موضوع صورتحساب: 1 اصلی · 2 اصلاحی · 3 ابطالی · 4 برگشت از فروش |
pattern | number | بله* | الگوی صورتحساب (مثلاً 1 فروش، 2 فروش ارز، 3 طلا و جواهر، 4 قرارداد پیمانکاری، 5 قبوض خدماتی، 6 بلیط هواپیما، 7 صادرات، 8 بارنامه، 9 فرآوردههای نفتی، 11 بورس کالا، 13 بیمه، 14 فروش زنجیرهای) |
type | number | بله* | نوع صورتحساب: 1 نوع اول (خریدار شناساییشده) · 2 نوع دوم · 3 نوع سوم |
buyerType | number | بله* | نوع شخص خریدار: 1 حقیقی · 2 حقوقی · 3 مشارکت مدنی · 4 اتباع غیرایرانی |
referenceTaxId | string | شرطی | شماره مالیاتی صورتحساب مرجع؛ برای اصلاحی، ابطالی و برگشت از فروش لازم است |
issuedAt | string | خیر | زمان صدور بهصورت ISO 8601 (مثل 2026-10-27T09:30:00+03:30). خالی = همین الان. زمان آینده پذیرفته نمیشود |
buyer | object | شرطی | tinb شماره اقتصادی خریدار · bid شناسه/کد ملی · bpc کد پستی. اطلاعات لازم به الگو و نوع خریدار بستگی دارد (پیام خطا دقیق میگوید) |
headerExtra | object | شرطی | فیلدهای سربرگ مخصوص الگو؛ مثلاً setm روش تسویه (1 نقدی · 2 نسیه · 3 نقدی/نسیه) که در نوع اول لازم است |
items | array | بله* | اقلام صورتحساب (توضیح پایین) |
payment | object | خیر | اطلاعات پرداخت با نامهای سند: pmt، pv، trn، iinn، acn، trmn، pcn، pid، pdt |
transportedGoods | array | شرطی | فقط الگوی بارنامه: آرایهای از { "sgid": "...", "sgt": "..." } |
article9 | boolean | خیر | ارسال خارج از مهلت طبق ماده ۹ قانون پایانههای فروشگاهی |
ackAmountWarning | boolean | خیر | تأیید هشدار «مبلغ غیرعادی» (پایینتر) |
* برای صورتحساب ابطالی (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".
استعلام وضعیت با شماره مالیاتی
وضعیت فعلی صورتحساب را از دیتابیس میخواند (نه مستقیم از سامانهی مؤدیان). بهروزرسانی وضعیت را ارسال خودکار انجام میدهد؛ پس بعد از ثبت، چند ثانیه تا چند دقیقه طول میکشد تا از 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
برای وقتی که پاسخ ارسال به دست شما نرسیده (قطعی شبکه یا 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..."
}
ارسال گروهی صورتحساب
چند صورتحساب را در یک درخواست میفرستید. هر مورد دقیقاً مثل ارسال تکی پردازش میشود: همان قواعد اعتبارسنجی، همان 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 رد میشوند. قبل از دستههای بزرگ، مانده اعتبار را بررسی کنید.استعلام گروهی وضعیت
وضعیت چند صورتحساب را یکجا میگیرید، با فهرستی از شمارههای مالیاتی (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 میگیرید.گزارش صورتحسابهای ارسالی
فهرست صورتحسابهای ثبتشده با هر کانالی (ویزارد، اکسل یا API) در بازهی انتخابی.
پارامترهای query (همه اختیاری)
| پارامتر | توضیح |
|---|---|
from · to | بازهی تاریخ صدور؛ قواعد در بخش «قواعد مشترک» |
status | queued در صف · processing در حال پردازش یا استعلام · success موفق · failed ناموفق |
economicId | شناسهی شماره اقتصادی (همان id در فهرست شمارههای اقتصادی، نه خود کد) |
subject | موضوع صورتحساب: 1 اصلی · 2 اصلاحی · 3 ابطالی · 4 برگشت از فروش |
pattern | الگوی صورتحساب، عدد ۱ تا ۳۰ طبق جدول الگوهای سامانهی مودیان |
channel | کانال ثبت: 1 ویزارد · 2 اکسل · 3 API |
q | جستوجو: ابتدای شمارهی یکتا، شمارهی صورتحساب یا شناسهی خریدار (حداکثر ۵۰ نویسه) |
sort | date (پیشفرض) · status · taxid · eco · ins · inp · buyer · amount |
dir | desc (پیشفرض) یا 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 | تعداد صورتحسابهایی که این صورتحساب را مرجع قرار دادهاند |
hasActiveChild | true یعنی برای این صورتحساب یک اصلاحی/ابطالی/برگشتی فعال ثبت شده و دیگر نمیتواند مرجع شود؛ سند جدید ملاک است |
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..."
}
گزارش خطاها
صورتحسابهایی که در یکی از مراحل رد شدهاند، بههمراه علت. هر صورتحساب یک ردیف دارد و در 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 گزارش قبلی.