REST API
TSync REST API позволяет вашему собственному коду взаимодействовать с TSync. С его помощью вы можете загружать данные в другую систему, создавать собственную панель или мобильное приложение, синхронизировать две системы или подключать TSync к инструментам автоматизации — всё это по обычному HTTPS с JSON.
Если вы уже работали с любым современным веб-API, это покажется знакомым: вы получаете токен, отправляете его с каждым запросом и получаете чистый JSON в ответ. Эта страница проведёт вас по основам, а затем перечислит каждый эндпоинт с примерами запросов и ответов.
Базовый URL: https://your-domain.com/api/v1
Каждый путь ниже указан относительно этого базового. Так что /invoices на самом деле
означает https://your-domain.com/api/v1/invoices.
Начало работы за три шага
Создайте токен в админ-панели (см. ниже) и скопируйте его в надёжное место.
Отправьте его в запросе. Самая быстрая проверка — список ваших счетов:
curl -s -H "Authorization: Bearer YOUR_TOKEN" \ "https://your-domain.com/api/v1/invoices?per_page=5"Прочитайте JSON. Успешный ответ содержит
"status": trueи ваши данные в полеdata. Вот и весь цикл — всё остальное это просто другие эндпоинты и параметры.
Аутентификация
Каждый запрос должен нести Bearer-токен в заголовке Authorization.
Генерация токена
- Откройте Setup → REST API tokens (
/admin/tsync_api_tokens). Можно также нажать Ctrl/⌘+K и найти «API». - Введите метку (например, «Mobile App», «Интеграция Zapier»), чтобы потом узнать его.
- Выберите сотрудника, от имени которого действует токен. Токен наследует права этого человека — он может делать ровно то, что может он, не больше.
- Нажмите Создать токен. Токен показывается один раз — скопируйте и сохраните его надёжно. Снова увидеть его не получится (хранится только хеш).
Использование токена
Включайте его в каждый запрос:
Authorization: Bearer your-api-token-here
Поскольку токен наследует права своего сотрудника, доступ совпадает с админ-интерфейсом.
Если этот человек не может просматривать счета в TSync, то и токен не может обратиться к
/invoices — он получит 403.
Отзыв токена
Перейдите в Setup → REST API tokens, найдите токен в списке (метка, владелец, последнее использование, срок, статус) и нажмите Отозвать. Он перестаёт работать немедленно.
Ограничение частоты запросов (rate limiting)
- 100 запросов в минуту на токен.
- Каждый ответ включает заголовки, чтобы вы могли регулировать темп:
| Заголовок | Значение |
|---|---|
X-RateLimit-Limit |
Максимум запросов за окно (например, 100) |
X-RateLimit-Remaining |
Сколько запросов осталось в текущем окне |
X-RateLimit-Reset |
Unix-метка времени сброса окна |
Превысите лимит — и получите 429 Too Many Requests. Тело ответа сообщает, сколько
ждать:
{
"status": false,
"error": "rate_limit_exceeded",
"message": "Too many requests. Retry after 23 seconds.",
"retry_after": 23
}
Простой и вежливый клиент следит за X-RateLimit-Remaining и сбавляет темп либо
повторяет попытку через retry_after секунд, когда видит 429.
Формат ответа
Каждый ответ использует одну и ту же структуру JSON, так что обрабатывать их все можно одинаково.
Отдельный объект возвращается в поле data:
{
"status": true,
"data": {
"id": 123,
"number": "INV-000123",
"total": 5000.00
}
}
Список возвращается как массив в поле data, с блоком meta для постраничной
навигации:
{
"status": true,
"data": [
{ "id": 1, "...": "..." },
{ "id": 2, "...": "..." }
],
"meta": {
"page": 1,
"per_page": 25,
"total": 142,
"total_pages": 6
}
}
Ошибка всегда содержит "status": false, короткий код error, по которому можно
ветвить логику, и понятное человеку сообщение message:
{
"status": false,
"error": "not_found",
"message": "Invoice #999 not found."
}
Совет: сначала проверяйте status. Если он true, читайте data; если false —
читайте error и message.
Постраничная навигация (pagination)
Каждый эндпоинт-список поддерживает постраничную навигацию:
| Параметр | По умолчанию | Значение |
|---|---|---|
page |
1 | Номер страницы (с 1) |
per_page |
25 | Элементов на странице (макс. 100) |
Используйте значение total_pages в meta, чтобы понять, когда остановиться.
Пример: GET /api/v1/invoices?page=2&per_page=50
Фильтрация и сортировка
Эндпоинты-списки принимают параметры запроса для сужения и упорядочивания результатов:
| Параметр | Применяется к | Значение |
|---|---|---|
search |
Ко всем | Текстовый поиск по ключевым полям |
status |
Счета, Лиды | Фильтр по статусу (например, paid, unpaid, overdue) |
date_from |
Ко всему с датами | Начальная дата (YYYY-MM-DD) |
date_to |
Ко всему с датами | Конечная дата (YYYY-MM-DD) |
client_id |
Счета, Платежи | Фильтр по клиенту |
assigned |
Лиды | Фильтр по ID назначенного сотрудника |
sort |
Ко всем | Поле для сортировки (например, date, total, name) |
order |
Ко всем | asc или desc |
Пример: GET /api/v1/invoices?status=unpaid&date_from=2026-01-01&sort=total&order=desc
Эндпоинты
API охватывает ваши основные бизнес-записи. Ниже каждый из них с параметрами и примером ответа.
Счета (Invoices)
Список счетов
GET /api/v1/invoices
Параметры запроса: status, client_id, date_from, date_to, search,
page, per_page
Ответ:
{
"status": true,
"data": [
{
"id": 123,
"number": "INV-000123",
"client_id": 45,
"client_name": "Acme SRL",
"date": "2026-05-01",
"duedate": "2026-05-31",
"subtotal": 4201.68,
"total_tax": 798.32,
"total": 5000.00,
"currency": "RON",
"status": "unpaid",
"status_label": "Unpaid"
}
],
"meta": { "page": 1, "per_page": 25, "total": 142, "total_pages": 6 }
}
Получить один счёт
GET /api/v1/invoices/:id
Возвращает счёт целиком, включая строки и любые зафиксированные платежи.
{
"status": true,
"data": {
"id": 123,
"number": "INV-000123",
"client_id": 45,
"client_name": "Acme SRL",
"date": "2026-05-01",
"duedate": "2026-05-31",
"subtotal": 4201.68,
"total_tax": 798.32,
"total": 5000.00,
"currency": "RON",
"status": "unpaid",
"items": [
{
"description": "Consulting services — May 2026",
"qty": 40,
"rate": 100.00,
"tax_name": "TVA 19%",
"tax_rate": 19.00,
"amount": 4000.00
}
],
"payments": [],
"created_at": "2026-05-01T10:30:00+03:00"
}
}
Клиенты (Clients)
Список клиентов
GET /api/v1/clients
Параметры запроса: search, page, per_page
Ответ:
{
"status": true,
"data": [
{
"id": 45,
"company": "Acme SRL",
"vat": "RO12345678",
"phonenumber": "+40721000000",
"city": "Bucharest",
"country": "Romania",
"active": true,
"total_invoiced": 125000.00,
"health_score": 82
}
],
"meta": { "page": 1, "per_page": 25, "total": 310, "total_pages": 13 }
}
Получить одного клиента
GET /api/v1/clients/:id
Возвращает полные данные клиента, включая контакты, заметки и сводную статистику.
Лиды (Leads)
Список лидов
GET /api/v1/leads
Параметры запроса: status, source, assigned, search, date_from,
date_to, page, per_page
Ответ:
{
"status": true,
"data": [
{
"id": 789,
"name": "John Smith",
"company": "Widget Corp",
"email": "john@widgetcorp.com",
"phonenumber": "+40722000000",
"value": 15000.00,
"status": "new",
"source": "Website",
"assigned": 3,
"assigned_name": "Maria Popescu",
"created_at": "2026-05-15T14:20:00+03:00"
}
],
"meta": { "page": 1, "per_page": 25, "total": 58, "total_pages": 3 }
}
Создать лид
POST /api/v1/leads
Content-Type: application/json
Тело запроса:
{
"name": "Jane Doe",
"company": "NewCo SRL",
"email": "jane@newco.ro",
"phonenumber": "+40723000000",
"value": 8000.00,
"source": "API",
"assigned": 3,
"description": "Interested in warehouse module"
}
Ответ (201 Created):
{
"status": true,
"data": {
"id": 790,
"name": "Jane Doe",
"company": "NewCo SRL",
"status": "new",
"created_at": "2026-05-16T09:00:00+03:00"
}
}
Остатки (Stock)
Список товаров на складе
GET /api/v1/stock
Параметры запроса: search, warehouse_id, below_reorder (boolean), page,
per_page
Ответ:
{
"status": true,
"data": [
{
"id": 201,
"code": "MAT-001",
"name": "Steel Rod 10mm",
"warehouse_id": 1,
"warehouse_name": "Main Warehouse",
"qty_on_hand": 450,
"qty_reserved": 30,
"qty_available": 420,
"reorder_level": 100,
"unit": "kg",
"avg_cost": 12.50,
"total_value": 5625.00
}
],
"meta": { "page": 1, "per_page": 25, "total": 1200, "total_pages": 48 }
}
Движения товаров
GET /api/v1/stock/movements
Параметры запроса: item_id, warehouse_id, type (in/out/transfer),
date_from, date_to, page, per_page
Ответ:
{
"status": true,
"data": [
{
"id": 5001,
"item_id": 201,
"item_name": "Steel Rod 10mm",
"type": "in",
"qty": 100,
"reference_type": "grn",
"reference_id": 88,
"warehouse_id": 1,
"date": "2026-05-14T08:00:00+03:00",
"staff_id": 2,
"staff_name": "Ion Popescu"
}
],
"meta": { "page": 1, "per_page": 25, "total": 8400, "total_pages": 336 }
}
Платежи (Payments)
Список платежей
GET /api/v1/payments
Параметры запроса: client_id, invoice_id, date_from, date_to, page,
per_page
Ответ:
{
"status": true,
"data": [
{
"id": 567,
"invoice_id": 123,
"invoice_number": "INV-000123",
"client_id": 45,
"amount": 5000.00,
"payment_mode": "Bank Transfer",
"date": "2026-05-10",
"note": "Wire transfer ref: TRF-2026-0510"
}
],
"meta": { "page": 1, "per_page": 25, "total": 890, "total_pages": 36 }
}
Расходы (Expenses)
Список расходов
GET /api/v1/expenses
Параметры запроса: category, date_from, date_to, billable (boolean),
search, page, per_page
Ответ:
{
"status": true,
"data": [
{
"id": 340,
"category": "Office Supplies",
"amount": 250.00,
"currency": "RON",
"tax": 47.50,
"date": "2026-05-12",
"client_id": null,
"billable": false,
"reference_no": "RCP-2026-0512",
"note": "Printer cartridges"
}
],
"meta": { "page": 1, "per_page": 25, "total": 234, "total_pages": 10 }
}
Сотрудники (Staff)
Список сотрудников
GET /api/v1/staff
Параметры запроса: search, role, active (boolean), page, per_page
Ответ:
{
"status": true,
"data": [
{
"id": 3,
"firstname": "Maria",
"lastname": "Popescu",
"email": "maria@company.ro",
"role": "Senior Sales",
"active": true,
"last_login": "2026-05-16T08:45:00+03:00"
}
],
"meta": { "page": 1, "per_page": 25, "total": 18, "total_pages": 1 }
}
Собственный пользователь токена
GET /api/v1/staff/me
Удобно для проверки того, что токен работает, и для просмотра того, что ему разрешено. Возвращает сотрудника, стоящего за токеном, его права и текущий статус ограничения частоты запросов.
{
"status": true,
"data": {
"id": 3,
"firstname": "Maria",
"lastname": "Popescu",
"email": "maria@company.ro",
"role": "Senior Sales",
"permissions": ["invoices.view", "clients.view", "leads.manage", "stock.view"],
"token_description": "Mobile App",
"rate_limit": 100,
"rate_limit_remaining": 87
}
}
Наборы данных аналитики (Analytics datasets)
Список наборов данных
GET /api/v1/analytics/datasets
Перечисляет встроенные наборы данных аналитики, которые можно запустить. У каждого есть
стабильный строковый id, читаемый label и краткое description.
Ответ:
{
"status": true,
"data": [
{ "id": "revenue_monthly", "label": "Monthly Revenue", "description": "Total invoiced revenue grouped by month." },
{ "id": "leads_by_status", "label": "Leads by Status", "description": "Count of leads grouped by their current status." },
{ "id": "expenses_by_category", "label": "Expenses by Category", "description": "Total expenses grouped by category." },
{ "id": "invoices_aging", "label": "Invoices Aging", "description": "Unpaid invoices grouped by aging buckets." },
{ "id": "stock_valuation", "label": "Stock Valuation", "description": "Current stock quantities and values by warehouse." }
]
}
Run a dataset
GET /api/v1/analytics/run/:dataset_id
Запускает один из наборов данных выше (:dataset_id — это id из списка) и возвращает
вычисленные строки. Каждый набор проверяет соответствующее право (например,
revenue_monthly требует право на просмотр счетов).
{
"status": true,
"data": {
"dataset": "revenue_monthly",
"results": [
{ "month": "2026-05", "revenue": 184200.00, "invoice_count": 37 }
],
"generated_at": "2026-05-16 02:00:00"
}
}
More endpoints
Ещё несколько эндпоинтов на чтение дополняют API. Они подчиняются тем же правилам envelope, токена и постраничной навигации, что и описанные выше.
| Эндпоинт | Метод | Возвращает |
|---|---|---|
/api/v1/status |
GET |
Состояние сервиса и личность, стоящая за токеном (также ответ для GET /api/v1). |
/api/v1/items |
GET |
Позиции каталога (список). search, page, per_page. |
/api/v1/items/:id |
GET |
Одна позиция каталога. |
/api/v1/treasury/places |
GET |
Места хранения денег — только чтение, в пределах компаний токена. |
/api/v1/bank/accounts |
GET |
Банковские счета — только чтение, в пределах компаний токена. |
Некоторые ресурсы также принимают запись, когда у сотрудника токена есть нужное право:
POST /api/v1/invoices, POST /api/v1/clients, а также GET /api/v1/leads/:id и
PUT /api/v1/leads/:id в дополнение к эндпоинтам лидов, показанным выше.
Коды ошибок
Когда status равен false, HTTP-статус и код error сообщают, что пошло не так:
| HTTP-статус | Код ошибки | Значение |
|---|---|---|
| 400 | bad_request |
Некорректный запрос или неверные параметры |
| 401 | unauthorized |
Отсутствует или недействителен токен |
| 403 | forbidden |
Токен действителен, но не имеет прав на этот ресурс |
| 404 | not_found |
Ресурс не существует |
| 422 | validation_error |
Входные данные не прошли валидацию (подробности в объекте errors) |
| 429 | rate_limit_exceeded |
Слишком много запросов |
| 500 | server_error |
На сервере произошла ошибка |
Ошибка валидации точно указывает, какие поля нужно исправить:
{
"status": false,
"error": "validation_error",
"message": "Validation failed.",
"errors": {
"email": ["The email field is required."],
"name": ["The name must be at least 2 characters."]
}
}
Примеры кода
Одни и те же две задачи — получить список неоплаченных счетов и создать лид — на трёх языках.
cURL
# List unpaid invoices
curl -s -H "Authorization: Bearer YOUR_TOKEN" \
"https://erp.example.com/api/v1/invoices?status=unpaid&per_page=10"
# Get a single client
curl -s -H "Authorization: Bearer YOUR_TOKEN" \
"https://erp.example.com/api/v1/clients/45"
# Create a lead
curl -s -X POST \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"Jane Doe","email":"jane@example.com","value":5000,"source":"API"}' \
"https://erp.example.com/api/v1/leads"
PHP
<?php
$token = 'YOUR_TOKEN';
$base = 'https://erp.example.com/api/v1';
// List invoices
$ch = curl_init("{$base}/invoices?status=unpaid&per_page=50");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer {$token}"],
]);
$response = json_decode(curl_exec($ch), true);
curl_close($ch);
foreach ($response['data'] as $invoice) {
echo "#{$invoice['number']} — {$invoice['total']} {$invoice['currency']}\n";
}
// Create a lead
$ch = curl_init("{$base}/leads");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer {$token}",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
'name' => 'Jane Doe',
'email' => 'jane@example.com',
'value' => 5000,
'source' => 'API',
]),
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
echo "Created lead #{$result['data']['id']}\n";
JavaScript (fetch)
const TOKEN = 'YOUR_TOKEN';
const BASE = 'https://erp.example.com/api/v1';
// List invoices
const invoices = await fetch(`${BASE}/invoices?status=unpaid`, {
headers: { 'Authorization': `Bearer ${TOKEN}` }
}).then(r => r.json());
console.log(`Found ${invoices.meta.total} unpaid invoices`);
invoices.data.forEach(inv => {
console.log(`#${inv.number} — ${inv.total} ${inv.currency}`);
});
// Create a lead
const newLead = await fetch(`${BASE}/leads`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'Jane Doe',
email: 'jane@example.com',
value: 5000,
source: 'API'
})
}).then(r => r.json());
console.log(`Created lead #${newLead.data.id}`);
Webhooks (скоро)
Push-уведомления при изменении записей запланированы на будущий релиз. Пока же
опрашивайте API с фильтром date_from, чтобы подхватывать новые или обновлённые
записи с момента последней проверки.
Права доступа (Permissions)
Доступ к API использует ту же систему прав, что и админ-интерфейс. Соответствующие права:
| Право | Нужно, чтобы |
|---|---|
| Manage API tokens | Генерировать и отзывать токены |
| API access | Вообще пользоваться API (базовое право) |
| Per-record permissions | Достучаться до каждого эндпоинта (например, просмотр счетов, создание лидов) |
Поскольку токены наследуют роль своего сотрудника, проще всего управлять тем, что может делать токен, назначив его сотруднику с ровно нужным набором прав.
Смотрите также
- Автоматизации — реагируйте на изменения данных без написания кода
- Начало работы с TSync — обзор продукта
Формат ответа (v5.9.17)
Каждый ответ использует единый формат:
Успех (один объект):
{ "status": true, "data": { } }
Успех (список):
{ "status": true, "data": [ ], "meta": { "page": 1, "per_page": 25, "total": 100, "total_pages": 4 } }
Ошибка:
{ "status": false, "error": "not_found", "message": "…" }
(ok также присутствует рядом со status для старых клиентов.) Каждый ответ содержит заголовки лимита — X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset — и каждый вызов логируется (токен, сотрудник, компания, метод, endpoint, статус, длительность, IP).
Эндпоинты
GET /api/v1/status · GET /api/v1/staff/me · GET|POST /api/v1/clients · GET|POST /api/v1/leads, PUT /api/v1/leads/{id} · GET /api/v1/items · GET /api/v1/stock · GET /api/v1/treasury/places (только чтение) · GET /api/v1/bank/accounts (только чтение) · плюс счета, платежи, расходы, аналитика.
Каждый токен принадлежит сотруднику и соблюдает его права; данные не возвращаются между компаниями, к которым у токена нет доступа.