---
title: REST API
description: Un ghid prietenos pentru dezvoltatori despre TSync REST API — pornește cu autentificarea prin token, apoi citește și scrie facturi, clienți, lead-uri, stoc, plăți și multe altele. Include endpoint-uri, forma cererilor/răspunsurilor și exemple de cod.
product: TSync Intelligence 11.3.6
language: ro
canonical: https://docs.tsync.pro/ro/modules/tsync-rest-api/
source: https://docs.tsync.pro/llms.txt
---

# REST API

TSync REST API permite codului tău să comunice cu TSync. Cu el poți extrage date
într-un alt sistem, construi un dashboard sau o aplicație mobilă personalizată,
menține două sisteme sincronizate sau conecta TSync la instrumente de automatizare
— totul prin HTTPS simplu, cu JSON.

Dacă ai mai folosit vreun API web modern, asta îți va părea familiar: obții un
token, îl trimiți la fiecare cerere și primești JSON curat înapoi. Această pagină te
trece prin proces, apoi listează fiecare endpoint cu exemple de cerere și răspuns.

**Base URL:** `https://your-domain.com/api/v1`

Fiecare cale de mai jos este relativă la acel base URL. Așadar `/invoices` înseamnă
de fapt `https://your-domain.com/api/v1/invoices`.

---

## Pornire în trei pași

1. **Creează un token** în panoul de administrare (vezi mai jos) și copiază-l undeva
   în siguranță.
2. **Trimite-l la o cerere.** Cel mai rapid test rapid — listează-ți facturile:

   ```bash
   curl -s -H "Authorization: Bearer YOUR_TOKEN" \
     "https://your-domain.com/api/v1/invoices?per_page=5"
   ```

3. **Citește JSON-ul.** Un răspuns reușit are `"status": true` și datele tale sub
   `data`. Asta este toată bucla — restul sunt doar mai multe endpoint-uri și
   parametri.

---

## Autentificare

Fiecare cerere trebuie să poarte un token Bearer în header-ul `Authorization`.

### Generarea unui token

1. Deschide **Setup → REST API tokens** (`/admin/tsync_api_tokens`). Poți și apăsa
   **Ctrl/⌘+K** și căuta „API”.
2. Introdu o **etichetă** (de ex. „Mobile App”, „Integrare Zapier”) ca să-l poți
   recunoaște mai târziu.
3. Alege **membrul de personal** în numele căruia acționează token-ul. **Token-ul
   moștenește permisiunile acelei persoane** — poate face exact ce poate face ea,
   nimic mai mult.
4. Apasă **Generează token**. Token-ul este afișat **o singură dată** — copiază-l și
   stochează-l în siguranță. Nu îl vei mai putea vedea (se păstrează doar un hash).

### Folosirea token-ului

Include-l în fiecare cerere:

```
Authorization: Bearer your-api-token-here
```

Pentru că un token moștenește permisiunile membrului său de personal, accesul se
aliniază cu interfața de administrare. Dacă acea persoană nu poate vedea facturile
în TSync, nici token-ul nu poate ajunge la `/invoices` — primește un `403`.

### Revocarea unui token

Mergi la **Setup → REST API tokens**, găsește token-ul în listă (etichetă, proprietar, ultima utilizare, expirare, status) și apasă **Revocă**. Încetează
să mai funcționeze imediat.

---

## Limitarea ratei (rate limiting)

- **100 de cereri pe minut** per token.
- Fiecare răspuns include header-e ca să te poți autoregla:

| Header | Semnificație |
|--------|--------------|
| `X-RateLimit-Limit` | Numărul maxim de cereri per fereastră (de ex. 100) |
| `X-RateLimit-Remaining` | Cererile rămase în fereastra curentă |
| `X-RateLimit-Reset` | Timestamp Unix când se resetează fereastra |

Depășește limita și primești `429 Too Many Requests`. Corpul îți spune cât să
aștepți:

```json
{
  "status": false,
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Retry after 23 seconds.",
  "retry_after": 23
}
```

Un client simplu și politicos urmărește `X-RateLimit-Remaining` și își reduce
ritmul, sau reîncearcă după `retry_after` secunde când vede un `429`.

---

## Formatul răspunsului

Fiecare răspuns folosește aceeași formă JSON, astfel încât să le poți trata pe toate
la fel.

**Un singur element** vine înapoi sub `data`:

```json
{
  "status": true,
  "data": {
    "id": 123,
    "number": "INV-000123",
    "total": 5000.00
  }
}
```

**O listă** vine înapoi ca un array sub `data`, cu un bloc `meta` pentru paginare:

```json
{
  "status": true,
  "data": [
    { "id": 1, "...": "..." },
    { "id": 2, "...": "..." }
  ],
  "meta": {
    "page": 1,
    "per_page": 25,
    "total": 142,
    "total_pages": 6
  }
}
```

**O eroare** are întotdeauna `"status": false`, un cod scurt `error` pe care poți
ramifica logica și un `message` lizibil de oameni:

```json
{
  "status": false,
  "error": "not_found",
  "message": "Invoice #999 not found."
}
```

Sfat: verifică `status` mai întâi. Dacă este `true`, citește `data`; dacă este
`false`, citește `error` și `message`.

---

## Paginare

Fiecare endpoint de tip listă este paginat:

| Parametru | Implicit | Semnificație |
|-----------|----------|--------------|
| `page` | 1 | Numărul paginii (începe de la 1) |
| `per_page` | 25 | Elemente pe pagină (maxim 100) |

Folosește valoarea `total_pages` din `meta` ca să știi când să te oprești.

Exemplu: `GET /api/v1/invoices?page=2&per_page=50`

---

## Filtrare și sortare

Endpoint-urile de tip listă acceptă parametri de query pentru a restrânge și ordona
rezultatele:

| Parametru | Se aplică la | Semnificație |
|-----------|--------------|--------------|
| `search` | Toate | Căutare text în câmpurile cheie |
| `status` | Invoices, Leads | Filtrare după status (de ex. `paid`, `unpaid`, `overdue`) |
| `date_from` | Orice are dată | Data de început (`YYYY-MM-DD`) |
| `date_to` | Orice are dată | Data de sfârșit (`YYYY-MM-DD`) |
| `client_id` | Invoices, Payments | Filtrare după client |
| `assigned` | Leads | Filtrare după ID-ul membrului de personal asignat |
| `sort` | Toate | Câmpul după care se sortează (de ex. `date`, `total`, `name`) |
| `order` | Toate | `asc` sau `desc` |

Exemplu: `GET /api/v1/invoices?status=unpaid&date_from=2026-01-01&sort=total&order=desc`

---

## Endpoint-uri

API-ul acoperă evidențele tale de afaceri de bază. Iată-le pe fiecare cu parametrii
și un răspuns exemplu.

### Invoices

#### List invoices

```
GET /api/v1/invoices
```

Parametri de query: `status`, `client_id`, `date_from`, `date_to`, `search`,
`page`, `per_page`

**Răspuns:**

```json
{
  "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 a single invoice

```
GET /api/v1/invoices/:id
```

Returnează factura completă, inclusiv liniile ei și orice plăți înregistrate.

```json
{
  "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

#### List clients

```
GET /api/v1/clients
```

Parametri de query: `search`, `page`, `per_page`

**Răspuns:**

```json
{
  "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 a single client

```
GET /api/v1/clients/:id
```

Returnează detaliile complete ale clientului, inclusiv contacte, note și statistici
de sumar.

---

### Leads

#### List leads

```
GET /api/v1/leads
```

Parametri de query: `status`, `source`, `assigned`, `search`, `date_from`,
`date_to`, `page`, `per_page`

**Răspuns:**

```json
{
  "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 }
}
```

#### Create a lead

```
POST /api/v1/leads
Content-Type: application/json
```

**Corpul cererii:**

```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"
}
```

**Răspuns (`201 Created`):**

```json
{
  "status": true,
  "data": {
    "id": 790,
    "name": "Jane Doe",
    "company": "NewCo SRL",
    "status": "new",
    "created_at": "2026-05-16T09:00:00+03:00"
  }
}
```

---

### Stock

#### List stock items

```
GET /api/v1/stock
```

Parametri de query: `search`, `warehouse_id`, `below_reorder` (boolean), `page`,
`per_page`

**Răspuns:**

```json
{
  "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 }
}
```

#### Stock movements

```
GET /api/v1/stock/movements
```

Parametri de query: `item_id`, `warehouse_id`, `type` (in/out/transfer),
`date_from`, `date_to`, `page`, `per_page`

**Răspuns:**

```json
{
  "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

#### List payments

```
GET /api/v1/payments
```

Parametri de query: `client_id`, `invoice_id`, `date_from`, `date_to`, `page`,
`per_page`

**Răspuns:**

```json
{
  "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

#### List expenses

```
GET /api/v1/expenses
```

Parametri de query: `category`, `date_from`, `date_to`, `billable` (boolean),
`search`, `page`, `per_page`

**Răspuns:**

```json
{
  "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

#### List staff

```
GET /api/v1/staff
```

Parametri de query: `search`, `role`, `active` (boolean), `page`, `per_page`

**Răspuns:**

```json
{
  "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 }
}
```

#### The token's own user

```
GET /api/v1/staff/me
```

Util pentru a confirma că un token funcționează și a vedea ce îi este permis să
facă. Returnează membrul de personal din spatele token-ului, permisiunile lui și
starea curentă a limitei de rată.

```json
{
  "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

#### List datasets

```
GET /api/v1/analytics/datasets
```

Listează seturile de date de analiză predefinite pe care le poți rula. Fiecare are un `id`
de tip text stabil, un `label` lizibil și o scurtă `description`.

**Răspuns:**

```json
{
  "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
```

Rulează unul dintre seturile de date de mai sus (`:dataset_id` este `id`-ul din listă) și
returnează rândurile calculate. Fiecare set verifică permisiunea corespunzătoare (de ex.
`revenue_monthly` necesită drept de vizualizare a facturilor).

```json
{
  "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

Câteva endpoint-uri de citire suplimentare completează API-ul. Respectă aceleași reguli de
envelope, token și paginare ca cele de mai sus.

| Endpoint | Verb | Returnează |
|----------|------|------------|
| `/api/v1/status` | `GET` | Starea serviciului și identitatea din spatele token-ului (și răspunsul pentru `GET /api/v1`). |
| `/api/v1/items` | `GET` | Articole din catalog (listă). `search`, `page`, `per_page`. |
| `/api/v1/items/:id` | `GET` | Un singur articol din catalog. |
| `/api/v1/treasury/places` | `GET` | Locuri de păstrare a banilor — doar citire, limitate la companiile token-ului. |
| `/api/v1/bank/accounts` | `GET` | Conturi bancare — doar citire, limitate la companiile token-ului. |

Unele resurse acceptă și scrieri când membrul de personal al token-ului are permisiunea
necesară: `POST /api/v1/invoices`, `POST /api/v1/clients`, plus `GET /api/v1/leads/:id` și
`PUT /api/v1/leads/:id` pe lângă endpoint-urile de leaduri prezentate mai sus.

---

## Coduri de eroare

Când `status` este `false`, statusul HTTP și codul `error` îți spun ce a mers prost:

| Status HTTP | Cod eroare | Semnificație |
|-------------|------------|--------------|
| 400 | `bad_request` | Cerere malformată sau parametri invalizi |
| 401 | `unauthorized` | Token lipsă sau invalid |
| 403 | `forbidden` | Token-ul este valid, dar nu are permisiune pentru această resursă |
| 404 | `not_found` | Resursa nu există |
| 422 | `validation_error` | Datele de intrare au eșuat validarea (detalii în obiectul `errors`) |
| 429 | `rate_limit_exceeded` | Prea multe cereri |
| 500 | `server_error` | Ceva a mers prost pe server |

O eroare de validare îți spune exact ce câmpuri să corectezi:

```json
{
  "status": false,
  "error": "validation_error",
  "message": "Validation failed.",
  "errors": {
    "email": ["The email field is required."],
    "name": ["The name must be at least 2 characters."]
  }
}
```

---

## Exemple de cod

Aceleași două sarcini — listarea facturilor neplătite și crearea unui lead — în trei
limbaje.

### cURL

```bash
# 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
<?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)

```javascript
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 (în curând)

Notificările push când se modifică înregistrările sunt planificate pentru o
versiune viitoare. Deocamdată, interoghează cu filtrul `date_from` ca să prinzi
înregistrările noi sau actualizate de la ultima ta verificare.

---

## Permisiuni

Accesul la API folosește același sistem de permisiuni ca interfața de administrare.
Cele relevante:

| Permisiune | Necesară pentru |
|------------|-----------------|
| Manage API tokens | Generarea și revocarea token-urilor |
| API access | Folosirea API-ului în general (baza) |
| Permisiuni per înregistrare | Accesarea fiecărui endpoint (de ex. vizualizarea facturilor, crearea lead-urilor) |

Pentru că token-urile moștenesc rolul membrului lor de personal, cea mai simplă cale
de a controla ce poate face un token este să-l îndrepți către un membru de personal
cu exact permisiunile potrivite.

---

## Vezi și

- [Automatizări](tsync-automations.md) — reacționează la modificările de date fără să
  scrii cod
- [Primii pași cu TSync](../index.md) — prezentarea generală a produsului

---

## Format răspuns (v5.9.17)

Fiecare răspuns folosește un singur format:

**Succes (un obiect):**
```json
{ "status": true, "data": { } }
```

**Succes (listă):**
```json
{ "status": true, "data": [ ], "meta": { "page": 1, "per_page": 25, "total": 100, "total_pages": 4 } }
```

**Eroare:**
```json
{ "status": false, "error": "not_found", "message": "…" }
```

(`ok` apare și el lângă `status` pentru clienții mai vechi.) Fiecare răspuns are headere de rate-limit — `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` — iar fiecare apel este logat (token, staff, companie, metodă, endpoint, status, durată, IP).

### Endpointuri

`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` (doar citire) · `GET /api/v1/bank/accounts` (doar citire) · plus facturi, plăți, cheltuieli, analytics.

Fiecare token aparține unui membru al echipei și respectă permisiunile acestuia; datele nu sunt returnate între companii la care token-ul nu are acces.
