API حسابداری برای برنامهنویسان: تمام دفاتر از طریق REST
API حسابداری حسابدار من هر کاری را که در داشبورد برای یک کسبوکار انجام میدهید در اختیار کد شما میگذارد: حسابها، اسناد، سالهای مالی، طرفحسابها، نرخ ارز، گزارشهای مالی، انبار و حسابداری صنعتی، بودجه و حسابداری مدیریت، وبهوکها و ردپای حسابرسی. ورودی و خروجی JSON است و مستندات OpenAPI را میتوانید همانجا در مرورگر امتحان کنید.

- JSON روی HTTPS با مستندات OpenAPI
- REST
- کلید API زیر نظر مالک
- Bearer
- سقف پیشفرض درخواست برای هر کلید
- ۱۲۰ در دقیقه
- نوع رویداد وبهوک
- ۱۶
آدرس پایه
https://api.hesabdar.my/api/v1هر کسبوکار کلیدهای خودش را دارد؛ کلید تعیین میکند با دفاتر کدام کسبوکار کار میکنید.
از صفر تا ثبت اولین سند قطعی در سه قدم
- ۱
ساخت کلید
بهعنوان مالک کسبوکار، در تنظیمات کسبوکار یک کلید API بسازید و دسترسی آن را انتخاب کنید: فقط خواندن یا خواندن و نوشتن. کلید را همان لحظه کپی کنید؛ متن کامل آن فقط یک بار نمایش داده میشود.
- ۲
یک درخواست خواندنی
درخواست
GET /accountsرا با هدرAuthorization: Bearer lgr_live_…بفرستید. پاسخ، کدینگ حسابهای آن کسبوکار است و هدرها سقف باقیمانده درخواست و موجودی اعتبار را نشان میدهند. - ۳
ثبت سند
درخواست
POST /journal-entriesرا با ردیفهای تراز و هدرIdempotency-Keyبفرستید. از کد یا شناسه حساب استفاده کنید؛ با"status": "posted"سند همان لحظه قطعی میشود و بدون آن بهصورت موقت برای بازبینی میماند.
ثبت سند حسابداری با curl، جاوااسکریپت یا پایتون
یک درخواست به سه زبان: سند فروش قطعی با مشتری روی ردیف دریافتنی. اگر درخواست را با همان کلید یکتاسازی تکرار کنید، بهجای سند دوم، همان سند قبلی برگردانده میشود.
خواندن حسابها و گزارشها
# Trial balance for the current fiscal year
curl https://api.hesabdar.my/api/v1/reports/trial-balance \
-H "Authorization: Bearer $ACCOUNTING_API_KEY" \
-H "Accept: application/json" \
-H "Accept-Language: fa" # Persian error messages and labelsconst res = await fetch("https://api.hesabdar.my/api/v1/accounts?postable=1", {
headers: {
Authorization: `Bearer ${process.env.ACCOUNTING_API_KEY}`,
Accept: "application/json",
},
});
const { data: accounts } = await res.json();
console.log(res.headers.get("X-RateLimit-Remaining"), accounts.length);import os
import requests
resp = requests.get(
"https://api.hesabdar.my/api/v1/reports/balance-sheet",
params={"compare": 1}, # add the prior year column
headers={
"Authorization": f"Bearer {os.environ['ACCOUNTING_API_KEY']}",
"Accept": "application/json",
},
timeout=30,
)
report = resp.json()curl -X POST https://api.hesabdar.my/api/v1/journal-entries \
-H "Authorization: Bearer $ACCOUNTING_API_KEY" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-10482" \
-d '{
"entry_date": "2026-09-25",
"voucher_type": "SAL",
"reference": "INV-10482",
"description": "Online order 10482",
"status": "posted",
"lines": [
{ "account_code": "1111", "debit": 1250.00, "party_code": "C001" },
{ "account_code": "4101", "credit": 1250.00 }
]
}'const res = await fetch("https://api.hesabdar.my/api/v1/journal-entries", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ACCOUNTING_API_KEY}`,
Accept: "application/json",
"Content-Type": "application/json",
"Idempotency-Key": "order-10482", // same key on retry = same entry
},
body: JSON.stringify({
entry_date: "2026-09-25",
voucher_type: "SAL",
reference: "INV-10482",
description: "Online order 10482",
status: "posted",
lines: [
{ account_code: "1111", debit: 1250.0, party_code: "C001" },
{ account_code: "4101", credit: 1250.0 },
],
}),
});
if (!res.ok) {
const err = await res.json(); // { code, message, errors }
throw new Error(`${res.status} ${err.code}: ${err.message}`);
}
const { data: entry } = await res.json();
console.log(entry.number, res.headers.get("X-Credits-Balance"));import os
import requests
resp = requests.post(
"https://api.hesabdar.my/api/v1/journal-entries",
headers={
"Authorization": f"Bearer {os.environ['ACCOUNTING_API_KEY']}",
"Accept": "application/json",
"Idempotency-Key": "order-10482",
},
json={
"entry_date": "2026-09-25",
"voucher_type": "SAL",
"reference": "INV-10482",
"description": "Online order 10482",
"status": "posted",
"lines": [
{"account_code": "1111", "debit": 1250.00, "party_code": "C001"},
{"account_code": "4101", "credit": 1250.00},
],
},
timeout=30,
)
if resp.status_code >= 400:
err = resp.json()
raise RuntimeError(f"{resp.status_code} {err['code']}: {err['message']}")
entry = resp.json()["data"]
print(entry["number"], resp.headers.get("X-Credits-Balance"))کلید API که فقط مالک میسازد، عوض میکند و باطل میکند
کلید را بهصورت توکن Bearer بفرستید: Authorization: Bearer lgr_live_…. هدر X-API-Key هم پذیرفته میشود. هر کلید متعلق به یک کسبوکار است؛ اتصال سه شرکت یعنی سه کلید، و لو رفتن یک کلید دفاتر شرکتهای دیگر را در معرض خطر قرار نمیدهد.
کلیدی با دسترسی خواندن فقط میتواند مسیرهای خواندنی را فراخوانی کند و هر تغییری در داده به دسترسی نوشتن نیاز دارد؛ در غیر این صورت پاسخ 403 است. کلید میتواند تاریخ انقضا داشته باشد، چرخانده شود (کلید قبلی از کار میافتد و کلید تازه با همان تنظیمات صادر میشود) یا هر زمان باطل شود. هر درخواست با کلیدی که آن را فرستاده ثبت میشود.
Authorization: Bearer lgr_live_xxxxxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Accept: application/json
Accept-Language: en # or fa
Idempotency-Key: order-10482 # on createreadwriterotaterevokeexpires_atAPI چه چیزهایی را پوشش میدهد
همه مسیرها نسبت به آدرس پایهاند. ردیفهای سند هم شناسه (account_id، party_id، cost_center_id، project_id) و هم کد (account_code، party_code و مانند آن) را میپذیرند.
| منبع | مسیرها | توضیح |
|---|---|---|
| سالهای مالی | GET POST /fiscal-years، GET PUT DELETE /fiscal-years/{id}، POST /{id}/close، POST /{id}/reopen | بستن سال، سند اختتامیه و افتتاحیه را صادر میکند |
| حسابها | /accounts (CRUD)، GET /accounts/{id}/balance، PUT /accounts/cost-behavior | کدینگ حسابهای سال مالی جاری؛ تعیین گروهی رفتار هزینه (ثابت، متغیر، نیمهمتغیر) |
| طرفحسابها | /parties (CRUD) | مشتریان و تأمینکنندگان |
| مراکز هزینه | /cost-centers (CRUD) | واحدها و شعب |
| پروژهها | /projects (CRUD) | پروژهها و قراردادها |
| انواع سند | /voucher-types (CRUD) | کدهایی مثل SAL، PUR، PAY |
| اسناد حسابداری | /journal-entries (CRUD)، POST /bulk-post، POST /{id}/post، POST /{id}/reverse، POST /{id}/duplicate، /{id}/attachments | سند موقت ویرایش میشود؛ سند قطعی با برگشت اصلاح میشود |
| نرخ ارز | GET POST /exchange-rates، DELETE /exchange-rates/{id} | وقتی سند نرخ مخصوص خودش را ندارد استفاده میشود |
| گزارشها | /reports/trial-balance، balance-sheet، income-statement، cash-flow، equity-changes، general-ledger، journal، party-balances، dashboard | همان اعداد داشبورد |
| راهاندازی انبار | GET POST DELETE /inventory/setup | فعال یا غیرفعال کردن ماژول انبار و حسابداری صنعتی و نگاشت حسابهای آن |
| اطلاعات پایه انبار | /units، /warehouses، /item-categories، /items (CRUD) | روش ارزیابی هر کالا: FIFO، میانگین موزون، استاندارد یا شناسایی ویژه |
| سری ساخت و سریال | /lots (CRUD)، /inventory-reports/lot-balances، expiring-lots، lot-trace، serial-history | تخصیص FEFO، ردیابی رو به عقب و رو به جلو |
| اسناد انبار | /stock-documents (CRUD)، POST /{id}/post، POST /{id}/cancel | رسید، برگشت، حواله، تحویل، انتقال، تعدیل، هزینه تکمیلی خرید، کاهش ارزش |
| انبارگردانی | /stock-counts، POST /{id}/complete، POST /{id}/cancel | تکمیل شمارش، سند تعدیل را قطعی میکند |
| گزارشهای انبار | /inventory-reports/on-hand، kardex، movement-summary، reconciliation، ageing، reorder | تطبیق دفتر انبار با دفتر کل |
| تولید | /boms (CRUD)، POST /boms/{id}/roll-up، /cost-center-rates، /production-orders با release، issue، receive، close، reopen، GET /{id}/cost-sheet | هزینهیابی سفارش کار و محاسبه بهای استاندارد |
| دستمزد و سربار | /labor-entries، /overhead-applications، /overhead-allocations، /overhead-closings (با preview) | تسهیم مستقیم، یکطرفه و دوطرفه |
| هزینهیابی مرحلهای | /process-runs (CRUD)، POST /{id}/post، POST /{id}/cancel | واحدهای معادل، میانگین موزون یا FIFO |
| گزارشهای بهای تمامشده | /costing-reports/cogm، overhead، profitability، wip، variances | بهای تمامشده کالای ساختهشده و فروشرفته، انحرافات |
| ضایعات و هزینههای مستقیم | POST /production-orders/{id}/scrap، GET /production-scraps، POST /production-scraps/{id}/cancel، GET POST /direct-costs، POST /direct-costs/{id}/cancel | ضایعات عادی و غیرعادی، پیمانکاری فرعی و سایر هزینههای مستقیم |
| برنامهریزی | GET POST /mrp، GET POST /capacity-load | باز کردن فهرست مواد چندسطحی، پیشنهاد سفارش، مقایسه ساعت لازم با ظرفیت عادی |
| بودجهها | /budgets (CRUD)، PUT /{id}/lines، POST /{id}/lines/from-actuals، POST /{id}/lines/from-budget، POST /budgets/spread، POST /{id}/duplicate، approve، unapprove، archive، default، GET /budget-periods | ردیفهای ماهانه به تفکیک حساب، مرکز هزینه و پروژه |
| گزارشهای بودجه | GET /budgets/{id}/vs-actual، GET /budgets/{id}/flexible | انحرافات به تفکیک بخش، حساب، مرکز هزینه، پروژه یا ماه |
| برنامه بودجه جامع | /budget-plans (CRUD)، POST /{id}/compute، POST /{id}/generate-budget | بودجه عملیاتی و نقدی، صورت سود و زیان بودجهای |
| تحلیلهای مدیریتی | /management/cvp، variable-costing، segments، ratios | نقطه سربهسر، تطبیق هزینهیابی جذبی، ROI و سود باقیمانده، ۱۹ نسبت مالی |
| تصمیمگیری و ABC | POST /management/decisions/{type}، /abc-models (CRUD)، POST /abc-models/{id}/compute | ساخت یا خرید، سفارش خاص، حذف یا ادامه، فروش یا پردازش بیشتر، عامل محدودکننده |
| وبهوکها | /webhooks (CRUD)، GET /{id}/deliveries، POST /{id}/test، POST /{id}/deliveries/{delivery}/redeliver | امضاشده با HMAC SHA-256 |
| ردپای حسابرسی | GET /audit-logs | چه کسی، چه کاری، چه زمانی و از کجا |
کلید یکتاسازی، خطاها، سقف درخواست و اعتبار
کلید یکتاسازی (Idempotency)
هنگام ثبت سند هدرIdempotency-Key(یا فیلدidempotency_key) را بفرستید. تکرار درخواست با همان کلید، سند موجود را با کد وضعیت 200 بهجای 201 برمیگرداند؛ قطع شدن شبکه هرگز یک فروش را دو بار ثبت نمیکند.ساختار واحد خطا
هر خطا یکcodeماشینی، یکmessageفارسی یا انگلیسی (باAccept-Language: fa) و در خطای اعتبارسنجی،errorsبه تفکیک فیلد مثلlines.0.debitدارد.سقف درخواست
هر کلید بهطور پیشفرض ۱۲۰ درخواست در دقیقه مجاز است. هدرهایX-RateLimit-LimitوX-RateLimit-Remainingرا دنبال کنید؛ پاسخ429مقدارretry_afterرا به ثانیه دارد.اعتبار در هدرها
هر درخواست هزینهapi.callرا دارد و عملیاتها هزینه خودشان را اضافه میکنند، مثلentry.create. هدرهایX-Credits-ChargedوX-Credits-Balanceهزینه و مانده را نشان میدهند؛ پاسخ402یعنی اعتبار تمام شده است.
نمونه خطا
HTTP/1.1 422 Unprocessable Entity
{
"message": "The entry is not balanced: debits 1,250.00 vs credits 1,200.00 (difference 50.00).",
"code": "validation_failed",
"errors": {
"lines": ["The entry is not balanced: debits 1,250.00 vs credits 1,200.00 (difference 50.00)."],
"lines.1.account_id": ["Account 9999 was not found in this fiscal year."]
}
}| کد وضعیت | معنا |
|---|---|
| 401 | کلید API ارسال نشده، نامعتبر، منقضی یا باطلشده است |
| 402 | اعتبار کافی نیست (insufficient_credits) |
| 403 | کلید دسترسی write یا مجوز لازم را ندارد |
| 404 | این منبع در این کسبوکار وجود ندارد |
| 409 | با وضعیت فعلی در تضاد است، مثل ویرایش سند قطعی یا ثبت در سال بستهشده |
| 422 | اعتبارسنجی ناموفق بود؛ errors را به تفکیک فیلد ببینید |
| 423 | کسبوکار یا حساب مالک تعلیق شده است |
| 429 | سقف درخواست پر شده؛ پس از retry_after ثانیه دوباره تلاش کنید |
وبهوک امضاشده برای اسناد، حسابها، طرفحسابها، سالهای مالی و انبار
یک آدرس را برای رویدادهای موردنیازتان ثبت کنید تا حسابدار من برای هر رویداد یک درخواست JSON از نوع POST بفرستد. هر ارسال هدرهای X-Webhook-Event، شناسه یکتای X-Webhook-Delivery، X-Webhook-Timestamp و X-Webhook-Signature را دارد.
امضا عبارت sha256= و پس از آن HMAC SHA-256 رشته timestamp + "." + raw_body با کلید مخفی وبهوک شماست. ارسالهای ناموفق تا ۵ بار با فاصله روبهافزایش (از ۳۰ ثانیه تا ۳۰ دقیقه) تکرار میشوند و میتوانید از طریق API آنها را ببینید، آزمایش کنید و دوباره بفرستید.
رویدادها
entry.createdentry.updatedentry.postedentry.reversedentry.deletedaccount.createdaccount.updatedaccount.deletedfiscal_year.createdfiscal_year.closedparty.createdparty.updatedstock_document.postedstock_document.cancelledproduction_order.closedcosting.run_posted
یک نمونه ارسال
POST /webhooks/accounting
X-Webhook-Event: entry.posted
X-Webhook-Delivery: 5f0c7b1e-2a41-4c1e-9d3a-8b7f7f1c2e90
X-Webhook-Timestamp: 1790000000
X-Webhook-Signature: sha256=9c1f...e04a
{
"id": "5f0c7b1e-2a41-4c1e-9d3a-8b7f7f1c2e90",
"event": "entry.posted",
"business_id": 12,
"created_at": "2026-09-25T10:42:07+00:00",
"data": { "entry": { "number": 318, "status": "posted", "lines": [ ... ] } }
}بررسی امضا
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.ACCOUNTING_WEBHOOK_SECRET;
// Keep the raw body: the signature covers the exact bytes we sent.
app.post("/webhooks/accounting", express.raw({ type: "application/json" }), (req, res) => {
const timestamp = req.get("X-Webhook-Timestamp") ?? "";
const signature = req.get("X-Webhook-Signature") ?? "";
const expected =
"sha256=" +
crypto.createHmac("sha256", SECRET).update(timestamp + "." + req.body.toString("utf8")).digest("hex");
const valid =
signature.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300; // 5 minutes
if (!valid || !fresh) return res.sendStatus(401);
const event = JSON.parse(req.body.toString("utf8"));
// event.event === "entry.posted", event.data holds the entry
res.sendStatus(200);
});<?php
$secret = getenv('ACCOUNTING_WEBHOOK_SECRET');
$body = file_get_contents('php://input'); // raw body
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);
if (! hash_equals($expected, $signature) || abs(time() - (int) $timestamp) > 300) {
http_response_code(401);
exit;
}
$event = json_decode($body, true);
// $event['event'] === 'entry.posted', $event['data'] holds the entry
http_response_code(200);پرسشهای رایج درباره API حسابداری
آیا میتوانم API حسابداری را رایگان امتحان کنم؟
بله. حسابهای جدید اعتبار رایگان میگیرند. یک کسبوکار بسازید، کلید تولید کنید و API را فراخوانی کنید؛ هر درخواست مقدار کمی اعتبار مصرف میکند که در هدر X-Credits-Charged میبینید.
آیا یک کلید API به چند کسبوکار دسترسی دارد؟
خیر. هر کلید دقیقاً به یک کسبوکار تعلق دارد. این کار اتصالها را از هم جدا نگه میدارد و باطل کردن یک کلید روی بقیه اثری ندارد.
سند قطعی را چطور با API اصلاح کنم؟
مسیر POST /journal-entries/{id}/reverse را فراخوانی کنید. حسابدار من سند برگشتی قطعی با جابهجایی بدهکار و بستانکار میسازد و سند اصلی را برگشتخورده علامت میزند. سپس سند درست را ثبت کنید.
آیا API از سند ارزی پشتیبانی میکند؟
بله. currency_code و exchange_rate را روی سند بفرستید، یا نرخ را نفرستید تا آخرین نرخ ذخیرهشده در /exchange-rates استفاده شود.
مستندات کامل مسیرها کجاست؟
مستندات مرجع OpenAPI با Scalar در api.hesabdar.my/docs/api است. برای آموزش گامبهگام با مثال، راهنمای API حسابداری را بخوانید.
اتصال خودتان را از امروز بسازید
ثبتنام کنید، کسبوکار بسازید و کلید تولید کنید. اعتبار رایگان برای آزمایشهای اول کافی است و هر پاسخ، هزینه درخواست و اعتبار باقیمانده را نشان میدهد.