مستندات 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درخواست از نظر قالب درست است اما قانون کسب‌وکار اجازه نمی‌دهد
429too_many_attemptsتلاش ناموفق ورود بیش از حد؛ هدر Retry-After را ببینید
429rate_limitedتعداد درخواست بیش از سقف مجاز
500server_errorخطای داخلی؛ با traceId به پشتیبانی اطلاع دهید
503service_unavailableسرویس موقتاً در دسترس نیست؛ کمی بعد دوباره تلاش کنید

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

محدودهسقف پیش‌فرض
دریافت توکن۲۰ درخواست در ۱۰ دقیقه برای هر IP
درخواست‌های خواندنی۱۲۰ درخواست در دقیقه برای هر توکن
درخواست‌های نوشتنی (ثبت و ویرایش)۳۰ درخواست در ۱۰ دقیقه برای هر توکن
کل درخواست‌ها۶۰۰ درخواست در دقیقه برای هر 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..."
}

فازهای بعدی به‌زودی

  • گزارش صورتحساب‌های ارسالی و گزارش خطاها
  • ارسال صورتحساب (تکی)، همراه با شناسه‌ی یکتای درخواست برای جلوگیری از ارسال تکراری
  • استعلام وضعیت صورتحساب (تکی)
  • ارسال و استعلام گروهی

هر قابلیت پس از آماده‌شدن به همین صفحه اضافه می‌شود.