Mergi la conținut

API Harmoniq

Conectați sistemele proprii la Harmoniq pentru a consulta și actualiza date despre angajați, unități, concedii, performanță, instruiri și alte activități. API-ul folosește JSON prin HTTPS, cu chei separate pentru fiecare sistem și drepturi de acces pe resurse.

API-ul face parte din planul Enterprise.

Primii pași

  1. Ca proprietar sau administrator al companiei, deschideți Acces → Chei API și alegeți Cheie nouă.
  2. Denumiți cheia după sistemul care o va folosi. Acordați doar drepturile de citire sau scriere necesare și, dacă este posibil, limitați accesul la adresele IP ale sistemului.
  3. Copiați cheia: este afișată o singură dată. Harmoniq păstrează doar o amprentă a ei.
  4. Apelați adresa companiei cu cheia în antetul Authorization.

Trimiteți cererile la adresa companiei:

https://compania-mea.harmoniq.ro/api/v1
curl https://compania-mea.harmoniq.ro/api/v1/employees?per_page=10 \
  -H "Authorization: Bearer hq_12_••••••••"

Autentificare

Trimiteți cheia ca token Bearer în antetul Authorization. Cheia este valabilă doar la adresa companiei pentru care a fost creată. Puteți stabili o dată de expirare, limita accesul la adrese sau intervale IP și suspenda, reactiva ori revoca cheia. Modificările sunt înregistrate în numele persoanei care a creat-o. Dacă aceasta pierde dreptul de a administra chei API, cheia permite în continuare citirea, dar nu și scrierea.

Authorization: Bearer hq_12_••••••••

Drepturi

Pentru fiecare resursă, cheia poate primi drepturi de citire ({resource}:read) și de scriere ({resource}:write). Acestea se aplică datelor din întreaga companie. Există și două drepturi speciale: sensitive, pentru citirea și scrierea câmpurilor personalizate marcate ca sensibile, și metrics:write, pentru trimiterea valorilor KPI folosind referințe de business.

Cereri și răspunsuri

  • Cererile și răspunsurile folosesc JSON cu codare UTF-8. Pentru cererile cu corp, trimiteți antetul Content-Type: application/json.
  • Folosiți formatul AAAA-LL-ZZ pentru date și ISO 8601 pentru dată și oră. Răspunsurile folosesc UTC, de exemplu 2026-05-01T08:00:00Z.
  • O singură înregistrare este returnată ca {"data": {…}}; o listă ca {"data": […], "meta": {page, per_page, total, last_page}, "links": {next, prev}}.
  • Liste: page (de la 1), per_page (25 implicit, cel mult 100), sort (id, created_at, updated_at; cu minus pentru descrescător), updated_since (înregistrările modificate după un anumit moment, pentru sincronizare), plus filtrele fiecărei resurse.
  • Creați cu POST; modificați cu PATCH, trimițând doar câmpurile de schimbat; DELETE răspunde 204. Cererile care includ câmpuri fără drept de scriere sunt respinse.
  • Operațiile de scriere sunt atomice: toate modificările se salvează împreună sau nu se salvează niciuna.
GET https://compania-mea.harmoniq.ro/api/v1/employees?status=active&updated_since=2026-05-01T00:00:00Z&page=2

Erori

Erorile sunt returnate în formatul {"error": "<cod>", "message": "<text>"}. Pentru date invalide, API-ul returnează codul 422 și detalii în „errors”, pentru fiecare câmp afectat.

StareCodCe înseamnă
401invalid_tokenCheia lipsește, este necunoscută sau aparține altei companii.
403token_inactiveCheia este suspendată sau expirată.
403insufficient_scopeCheia nu are dreptul necesar pentru această operație.
403ip_not_allowedCheia nu acceptă apeluri de la această adresă.
403token_owner_inactivePersoana care a creat cheia nu mai poate administra chei: cheia citește, dar nu scrie.
404—Resursa sau înregistrarea nu există în compania dumneavoastră (sau nu este în plan).
405—Resursa nu oferă această operație.
409in_useÎnregistrarea este folosită în altă parte și nu poate fi ștearsă.
422—Date invalide. Nu s-a salvat nimic.
429—Prea multe cereri; încercați din nou după Retry-After secunde.

Limite

Limita este de 120 de cereri pe minut pentru fiecare cheie și 300 pentru fiecare adresă IP. La depășire, API-ul returnează codul 429. Antetul Retry-After indică timpul de așteptare până la următoarea încercare.

Versiuni

Versiunea curentă este 1 (/api/v1). Resursele, câmpurile și filtrele noi se adaugă în această versiune. Modificările incompatibile cu integrările existente vor fi introduse într-o versiune nouă, anunțată din timp.

Date personale

  • CNP-ul nu poate fi citit sau scris prin API.
  • Accesul la câmpurile personalizate sensibile necesită dreptul sensitive.
  • Rezultatele chestionarelor anonime sunt disponibile doar ca totaluri. Nu sunt accesibile cât timp răspunsurile sunt sigilate sau numărul lor este prea mic pentru a proteja anonimatul participanților.
  • Jurnalul API păstrează timp de 30 de zile cheia folosită, adresa apelată, codul răspunsului și durata, fără conținutul cererii sau al răspunsului. Ultimele apeluri pot fi consultate în Acces → Chei API.

Trimiterea valorilor KPI

Pentru a trimite valori KPI, puteți folosi referințe de business în loc de ID-uri interne. Trimiteți POST /api/v1/metrics/{key}/values cu perioada și valorile pentru angajați (identificați prin marcă), unități sau departamente (identificate prin cod). Operația necesită dreptul metrics:write. GET /api/v1/metrics listează indicatorii care acceptă aceste valori.

POST https://compania-mea.harmoniq.ro/api/v1/metrics/sales.actual/values

{
    "period": "2026-09",
    "values": [
        {
            "subject": "CJ01",
            "value": 1234.5
        },
        {
            "subject": "FV0012",
            "value": 980
        }
    ]
}

Organizație

Zone geografice /geo-areas

Arborele de țări, regiuni și zone din care fac parte unitățile; de el depinde și aria managerilor de zonă. Numele sunt unice între zonele cu același părinte. Ștergerea e refuzată cât timp unități sau subzone o folosesc.

Drepturi: geo_areas:read, geo_areas:write

Adrese

  • GET /api/v1/geo-areas Listă
  • GET /api/v1/geo-areas/{id} O înregistrare
  • POST /api/v1/geo-areas Creare
  • PATCH /api/v1/geo-areas/{id} Modificare
  • DELETE /api/v1/geo-areas/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Nume, unic între zonele cu același părinte.
level_labelstring | null Cum se numește nivelul (țară, regiune, zonă).
parent_idinteger | null Zona din care face parte; null pentru o zonă de nivel superior. Niciodată ea însăși sau una dintre subzonele ei.
sortinteger | null Ordinea între zonele surori.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

parent_idintegerDoar zonele aflate direct sub aceasta.
rootsbooleantrue: doar zonele de nivel superior.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/geo-areas

{
    "name": "Nord-Vest",
    "level_label": "regiune",
    "parent_id": 1,
    "sort": 0
}

Exemplu de răspuns

{
    "data": {
        "id": 3,
        "name": "Nord-Vest",
        "level_label": "regiune",
        "parent_id": 1,
        "sort": 0,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Unități /work-units

Unitățile companiei: magazine, farmacii, birouri, hoteluri. Ștergerea e refuzată cât timp oameni, documente sau rezultate se mai referă la ea.

Drepturi: work_units:read, work_units:write

Adrese

  • GET /api/v1/work-units Listă
  • GET /api/v1/work-units/{id} O înregistrare
  • POST /api/v1/work-units Creare
  • PATCH /api/v1/work-units/{id} Modificare
  • DELETE /api/v1/work-units/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Nume, unic în companie.
codestring | null Codul dumneavoastră, unic în companie (folosit la potrivirea valorilor KPI).
geo_area_idinteger | null Zona geografică (regiune, țară) din care face parte.
addressstring | null Adresa.
citystring | nulldoar citire Localitatea (din lista oficială, pentru unitățile din România).
countystring | nulldoar citire Județul sau regiunea.
phonestring | null Telefon.
emailstring | null E-mail.
opened_ondate | null Data deschiderii.
closed_ondate | null Data închiderii.
is_activeboolean Dacă este în folosință.
custom_fieldsobject Câmpurile proprii ale companiei, după id-ul câmpului (vedeți /custom-fields).
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

codestringCodul exact (fără diferență între litere mari și mici).
geo_area_idintegerDoar din această zonă.
is_activebooleantrue sau false.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/work-units

{
    "name": "Farmacia Verde Centru",
    "code": "CJ01",
    "geo_area_id": 3,
    "address": "Str. Memorandumului 10",
    "opened_on": "2016-03-01",
    "is_active": true,
    "custom_fields": {
        "12": "XL"
    }
}

Exemplu de răspuns

{
    "data": {
        "id": 12,
        "name": "Farmacia Verde Centru",
        "code": "CJ01",
        "geo_area_id": 3,
        "address": "Str. Memorandumului 10",
        "city": "Cluj-Napoca",
        "county": "Cluj",
        "phone": null,
        "email": null,
        "opened_on": "2016-03-01",
        "closed_on": "2026-05-01",
        "is_active": true,
        "custom_fields": {
            "12": "XL"
        },
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Departamente /departments

Funcții la nivelul companiei (Vânzări, Logistică…), care pot fi imbricate. Ștergerea e refuzată cât timp încadrări sau subdepartamente îl folosesc.

Drepturi: departments:read, departments:write

Adrese

  • GET /api/v1/departments Listă
  • GET /api/v1/departments/{id} O înregistrare
  • POST /api/v1/departments Creare
  • PATCH /api/v1/departments/{id} Modificare
  • DELETE /api/v1/departments/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Nume, unic în companie.
codestring | null Codul dumneavoastră, unic în companie (folosit la potrivirea valorilor KPI).
parent_idinteger | null Departamentul din care face parte; niciodată el însuși sau unul dintre subdepartamentele lui.
is_activeboolean Dacă este în folosință.
custom_fieldsobject Câmpurile proprii ale companiei, după id-ul câmpului (vedeți /custom-fields).
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

codestringCodul exact (fără diferență între litere mari și mici).
parent_idintegerDoar departamentele aflate direct sub acesta.
is_activebooleantrue sau false.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/departments

{
    "name": "Farmacie",
    "code": "FARM",
    "is_active": true,
    "custom_fields": {
        "12": "XL"
    }
}

Exemplu de răspuns

{
    "data": {
        "id": 4,
        "name": "Farmacie",
        "code": "FARM",
        "parent_id": 1,
        "is_active": true,
        "custom_fields": {
            "12": "XL"
        },
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Funcții /positions

Funcțiile din companie și nivelul lor (un număr mai mare înseamnă o funcție mai înaltă). Ștergerea e refuzată cât timp cineva o ocupă.

Drepturi: positions:read, positions:write

Adrese

  • GET /api/v1/positions Listă
  • GET /api/v1/positions/{id} O înregistrare
  • POST /api/v1/positions Creare
  • PATCH /api/v1/positions/{id} Modificare
  • DELETE /api/v1/positions/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Nume, unic în companie.
codestring | null Codul dumneavoastră, unic în companie.
levelintegerobligatoriu Nivelul, de la 0 la 100.
descriptiontext | null Descriere.
is_activeboolean Dacă este în folosință.
custom_fieldsobject Câmpurile proprii ale companiei, după id-ul câmpului (vedeți /custom-fields).
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

codestringCodul exact (fără diferență între litere mari și mici).
is_activebooleantrue sau false.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/positions

{
    "name": "Farmacist",
    "code": "FA",
    "level": 2,
    "is_active": true,
    "custom_fields": {
        "12": "XL"
    }
}

Exemplu de răspuns

{
    "data": {
        "id": 7,
        "name": "Farmacist",
        "code": "FA",
        "level": 2,
        "description": null,
        "is_active": true,
        "custom_fields": {
            "12": "XL"
        },
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Echipe /teams

Grupuri de oameni din unități diferite (un proiect, un grup de lucru). Membrii se adaugă și se scot unul câte unul, cu acțiunile de mai jos.

Drepturi: teams:read, teams:write

Adrese

  • GET /api/v1/teams Listă
  • GET /api/v1/teams/{id} O înregistrare
  • POST /api/v1/teams Creare
  • PATCH /api/v1/teams/{id} Modificare
  • DELETE /api/v1/teams/{id} Ștergere
  • POST /api/v1/teams/{id}/add-member Adaugă un angajat în echipă (nu se schimbă nimic dacă face deja parte din ea). Corp: {"employee_id": 345}.
  • POST /api/v1/teams/{id}/remove-member Scoate un angajat din echipă. Corp: {"employee_id": 345}.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Nume, unic în companie.
descriptiontext | null Descriere.
is_activeboolean Dacă este în folosință.
member_idsarraydoar citire Angajații din echipă (doar citire; se schimbă cu add-member / remove-member).
custom_fieldsobject Câmpurile proprii ale companiei, după id-ul câmpului (vedeți /custom-fields).
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

is_activebooleantrue sau false.
employee_idintegerDoar echipele din care face parte acest angajat.

/api/v1/teams/{id}/add-member: employee_id (integer) — Angajatul de adăugat (un id din /employees).

/api/v1/teams/{id}/remove-member: employee_id (integer) — Angajatul de scos (un id din /employees).

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/teams

{
    "name": "Proiect inventar",
    "is_active": true,
    "custom_fields": {
        "12": "XL"
    }
}

Exemplu de răspuns

{
    "data": {
        "id": 2,
        "name": "Proiect inventar",
        "description": null,
        "is_active": true,
        "member_ids": [
            345,
            346
        ],
        "custom_fields": {
            "12": "XL"
        },
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Câmpuri proprii /custom-fields

Câmpurile adăugate de companie propriilor înregistrări, doar citire: ce înseamnă fiecare id din custom_fields al unei înregistrări, tipul și variantele lui. Câmpurile sensibile ale angajaților apar doar pentru o cheie cu dreptul sensitive. Câmpurile se definesc în aplicație.

Drepturi: custom_fields:read

Adrese

  • GET /api/v1/custom-fields Listă
  • GET /api/v1/custom-fields/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator; cheia din custom_fields al unei înregistrări.
entityemployee | work_unit | department | position | team | companydoar citire Tipul de înregistrare căruia îi aparține.
labelstringdoar citire Numele, în limba cererii (Accept-Language).
typetext | textarea | number | date | boolean | select | multiselect | urldoar citire Ce conține: text, textarea, number, date (Y-m-d), boolean, select, multiselect sau url.
optionsarray | nulldoar citire Variantele unui select sau multiselect: id și etichetă; valoarea păstrată este id-ul.
is_requiredbooleandoar citire Dacă valoarea este obligatorie.
visibilityreach | sensitivedoar citire reach (toți cei care văd angajatul) sau sensitive.
is_activebooleandoar citire Dacă este în folosință.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

entityemployee | work_unit | department | position | team | companyDoar câmpurile acestui tip de înregistrare.
is_activebooleantrue sau false.

Exemplu de răspuns

{
    "data": {
        "id": 12,
        "entity": "employee",
        "label": "Mărime uniformă",
        "type": "select",
        "options": [
            {
                "id": "m",
                "label": "M"
            }
        ],
        "is_required": false,
        "visibility": "reach",
        "is_active": true,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Oameni și timp

Angajați /employees

Oamenii companiei. Crearea unui angajat creează și prima încadrare; mutările ulterioare se fac prin /placements. CNP-ul nu se citește și nu se scrie niciodată prin API. Conturile de acces se creează în aplicație.

Drepturi: employees:read, employees:write

Adrese

  • GET /api/v1/employees Listă
  • GET /api/v1/employees/{id} O înregistrare
  • POST /api/v1/employees Creare
  • PATCH /api/v1/employees/{id} Modificare
  • DELETE /api/v1/employees/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
employee_numberstring | null Marca, unică în companie (folosită la potrivirea valorilor KPI).
first_namestringobligatoriu Prenume.
last_namestringobligatoriu Nume.
emailstring | null E-mail de serviciu.
phonestring | null Telefon.
birth_datedate | null Data nașterii.
hire_datedate | null Data angajării (de la ea începe prima încadrare).
termination_datedate | null Data plecării.
statusactive | inactive | terminated active, inactive sau terminated.
work_unit_idintegerobligatoriu Unitatea încadrării principale de acum; obligatorie la creare, doar citire după.
department_idinteger | null Departamentul încadrării principale (doar la creare).
position_idinteger | null Funcția încadrării principale (doar la creare).
has_loginbooleandoar citire Dacă persoana se poate autentifica.
custom_fieldsobject Câmpurile proprii ale companiei, după id; cele sensibile doar cu dreptul sensitive.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

statusactive | inactive | terminatedDoar cu această stare.
work_unit_idintegerÎncadrați acum în această unitate.
employee_numberstringMarca exactă.
emailstringE-mailul exact.
qstringO parte din nume.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/employees

{
    "employee_number": "FV0012",
    "first_name": "Ana",
    "last_name": "Popescu",
    "email": "ana.popescu@example.com",
    "hire_date": "2024-02-01",
    "status": "active",
    "work_unit_id": 12,
    "custom_fields": {
        "12": "XL"
    }
}

Exemplu de răspuns

{
    "data": {
        "id": 345,
        "employee_number": "FV0012",
        "first_name": "Ana",
        "last_name": "Popescu",
        "email": "ana.popescu@example.com",
        "phone": null,
        "birth_date": "2026-05-01",
        "hire_date": "2024-02-01",
        "termination_date": "2026-05-01",
        "status": "active",
        "work_unit_id": 12,
        "department_id": 1,
        "position_id": 1,
        "has_login": true,
        "custom_fields": {
            "12": "XL"
        },
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Încadrări /placements

Unde lucrează fiecare persoană: unitate, departament și funcție, de când până când. O încadrare principală nouă o preia pe cea dinainte, care rămâne încadrare secundară curentă până când este încheiată.

Drepturi: placements:read, placements:write

Adrese

  • GET /api/v1/placements Listă
  • GET /api/v1/placements/{id} O înregistrare
  • POST /api/v1/placements Creare
  • DELETE /api/v1/placements/{id} Ștergere
  • POST /api/v1/placements/{id}/end Încheie încadrarea la valid_to (nu înainte de începutul ei).
  • POST /api/v1/placements/{id}/make-primary O face încadrarea principală; cea principală dinainte devine secundară.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
employee_idintegerobligatoriu Persoana.
work_unit_idintegerobligatoriu Unitatea.
department_idinteger | null Departamentul.
position_idinteger | null Funcția.
is_primaryboolean Dacă este încadrarea principală a persoanei.
valid_fromdateobligatoriu Prima zi.
valid_todate | null Ultima zi (gol: încă în vigoare).
created_atdatetimedoar citire Creată.
updated_atdatetimedoar citire Ultima modificare.

Filtre

employee_idintegerDoar ale acestei persoane.
work_unit_idintegerDoar în această unitate.
currentbooleantrue: doar încadrările în vigoare azi.

/api/v1/placements/{id}/end: valid_to (date) — Ultima zi a încadrării (Y-m-d).

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/placements

{
    "employee_id": 345,
    "work_unit_id": 12,
    "is_primary": true,
    "valid_from": "2026-03-01"
}

Exemplu de răspuns

{
    "data": {
        "id": 901,
        "employee_id": 345,
        "work_unit_id": 12,
        "department_id": 1,
        "position_id": 1,
        "is_primary": true,
        "valid_from": "2026-03-01",
        "valid_to": "2026-05-01",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Tipuri de concediu /leave-types

Tipurile de concediu folosite de companie, așa cum sunt configurate în aplicație. Doar citire.

Drepturi: leave_types:read

Adrese

  • GET /api/v1/leave-types Listă
  • GET /api/v1/leave-types/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
codestring | nulldoar citire Cod scurt.
namestringdoar citire Numele, în limba cererii (Accept-Language), altfel în limba companiei.
uses_balancebooleandoar citire Dacă zilele se scad dintr-un sold anual.
default_entitlementnumber | nulldoar citire Zile pe an pentru un an întreg lucrat.
is_paidbooleandoar citire Concediu plătit.
requires_attachmentbooleandoar citire Cere un document atașat (asemenea cereri se depun în aplicație).
requires_referencebooleandoar citire Cere un număr de referință.
requires_replacementbooleandoar citire Cere un coleg care înlocuiește.
is_activebooleandoar citire Dacă poate fi cerut.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

is_activebooleantrue sau false.

Exemplu de răspuns

{
    "data": {
        "id": 1,
        "code": "CO",
        "name": "Concediu de odihnă",
        "uses_balance": true,
        "default_entitlement": 21,
        "is_paid": true,
        "requires_attachment": true,
        "requires_reference": true,
        "requires_replacement": true,
        "is_active": true,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Cereri de concediu /leave-requests

Cererile de concediu, după aceleași reguli ca în aplicație: se numără zilele lucrătoare, se verifică soldul și suprapunerile și pornește fluxul de aprobare al companiei. Aprobarea și respingerea urmează fluxul cererii: cel care a creat cheia trebuie să fie aprobator la pasul curent.

Drepturi: leave_requests:read, leave_requests:write

Adrese

  • GET /api/v1/leave-requests Listă
  • GET /api/v1/leave-requests/{id} O înregistrare
  • POST /api/v1/leave-requests Creare
  • POST /api/v1/leave-requests/{id}/approve Aprobă pasul curent (comentariu opțional).
  • POST /api/v1/leave-requests/{id}/reject Respinge cererea; comentariul (motivul) este obligatoriu.
  • POST /api/v1/leave-requests/{id}/cancel Anulează o cerere în așteptare sau aprobată.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
employee_idintegerobligatoriu Persoana în concediu.
leave_type_idintegerobligatoriu Tipul de concediu.
starts_ondateobligatoriu Prima zi.
ends_ondateobligatoriu Ultima zi.
daysnumberdoar citire Zilele numărate (lucrătoare, fără sărbători).
statuspending | approved | rejected | cancelleddoar citire pending, approved, rejected sau cancelled.
replacement_employee_idinteger | null Colegul care înlocuiește.
referencestring | null Număr de referință (de exemplu certificatul medical).
notetext | null Observații.
created_atdatetimedoar citire Depusă.
updated_atdatetimedoar citire Ultima modificare.

Filtre

employee_idintegerDoar ale acestei persoane.
statuspending | approved | rejected | cancelledDoar cu această stare.
fromdateCare ating această zi sau una ulterioară.
todateCare ating această zi sau una anterioară.

/api/v1/leave-requests/{id}/approve: comment (text) — Comentariu opțional pentru persoană.

/api/v1/leave-requests/{id}/reject: comment (text) — Motivul, arătat persoanei (obligatoriu).

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/leave-requests

{
    "employee_id": 345,
    "leave_type_id": 1,
    "starts_on": "2026-07-06",
    "ends_on": "2026-07-10"
}

Exemplu de răspuns

{
    "data": {
        "id": 77,
        "employee_id": 345,
        "leave_type_id": 1,
        "starts_on": "2026-07-06",
        "ends_on": "2026-07-10",
        "days": 5,
        "status": "pending",
        "replacement_employee_id": 1,
        "reference": null,
        "note": null,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Solduri de concediu /leave-balances

Soldul anual al fiecărei persoane, pentru fiecare tip de concediu care se scade dintr-un sold. Listarea unui an îl deschide pentru toți oamenii activi, pro rata și cu zilele reportate, ca în aplicație; zilele folosite, în așteptare și disponibile se calculează. Zilele anului, ajustarea și zilele reportate se pot modifica — niciodată pentru persoana care a creat cheia.

Drepturi: leave_balances:read, leave_balances:write

Adrese

  • GET /api/v1/leave-balances Listă
  • GET /api/v1/leave-balances/{id} O înregistrare
  • PATCH /api/v1/leave-balances/{id} Modificare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
employee_idintegerdoar citire Persoana.
leave_type_idintegerdoar citire Tipul de concediu.
yearintegerdoar citire Anul.
entitlementnumber Zilele anului (0–365).
adjustmentnumber Zile adăugate sau scăzute (−365–365).
carried_overnumber Zile reportate din anul trecut.
carried_over_expires_ondate | null Până când se pot folosi zilele reportate.
carried_usablenumberdoar citire Zile reportate încă folosibile azi.
earliernumberdoar citire Zile rămase din anii dinaintea celui precedent, încă folosibile azi.
earlier_expires_ondate | nulldoar citire Până când se pot lua cele mai vechi dintre aceste zile.
usednumberdoar citire Zile luate (aprobate).
pendingnumberdoar citire Zile cerute, în așteptarea aprobării.
availablenumberdoar citire Zile rămase.
notestring | null Observații.
created_atdatetimedoar citire Deschis.
updated_atdatetimedoar citire Ultima modificare.

Filtre

yearintegerAnul (implicit: anul curent).
employee_idintegerDoar această persoană.
leave_type_idintegerDoar acest tip de concediu.

Exemplu de răspuns

{
    "data": {
        "id": 55,
        "employee_id": 345,
        "leave_type_id": 1,
        "year": 2026,
        "entitlement": 21,
        "adjustment": 0,
        "carried_over": 3,
        "carried_over_expires_on": "2026-03-31",
        "carried_usable": 3,
        "earlier": 0,
        "earlier_expires_on": "2026-05-01",
        "used": 5,
        "pending": 2,
        "available": 17,
        "note": null,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Evenimente în calendar /calendar-events

Calendarul companiei. Participanții (sau unitatea) sunt anunțați despre un eveniment nou, o oră nouă sau un loc nou. Un eveniment nou se poate repeta: fiecare apariție devine un eveniment separat din aceeași serie și se modifică, se anulează sau se șterge separat.

Drepturi: calendar_events:read, calendar_events:write

Adrese

  • GET /api/v1/calendar-events Listă
  • GET /api/v1/calendar-events/{id} O înregistrare
  • POST /api/v1/calendar-events Creare
  • PATCH /api/v1/calendar-events/{id} Modificare
  • DELETE /api/v1/calendar-events/{id} Ștergere
  • POST /api/v1/calendar-events/{id}/cancel Anulează această apariție; participanții sunt anunțați.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
event_type_idinteger | null Tipul evenimentului.
titlestringobligatoriu Titlu.
descriptiontext | null Descriere (HTML; curățată ca orice text scris în aplicație).
locationstring | null Locul.
starts_atdatetimeobligatoriu Început (ISO 8601).
ends_atdatetimeobligatoriu Sfârșit (ISO 8601).
all_dayboolean Toată ziua.
visibilityeveryone | unit | participantsobligatoriu everyone, unit (oamenii unității) sau participants.
work_unit_idinteger | null Unitatea, pentru vizibilitatea unit.
participantsarray Id-urile angajaților invitați.
rsvpboolean Întreabă cine vine.
recurrenceweekly | biweekly | monthly | yearly | null Doar la creare: weekly, biweekly, monthly sau yearly.
recurrence_untildate | null Doar la creare: ultima zi a seriei (cel mult doi ani înainte).
series_idinteger | nulldoar citire Seria din care face parte.
cancelled_atdatetime | nulldoar citire Când a fost anulat.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

fromdateCare se termină în această zi sau după.
todateCare încep în această zi sau înainte.
work_unit_idintegerDoar ale acestei unități.
cancelledbooleantrue: doar cele anulate; false: doar celelalte.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/calendar-events

{
    "title": "Inventar trimestrial",
    "description": "<p>Toată echipa.</p>",
    "starts_at": "2026-07-06T15:00:00Z",
    "ends_at": "2026-07-06T17:00:00Z",
    "visibility": "everyone",
    "participants": [
        345,
        346
    ]
}

Exemplu de răspuns

{
    "data": {
        "id": 410,
        "event_type_id": 1,
        "title": "Inventar trimestrial",
        "description": "<p>Toată echipa.</p>",
        "location": null,
        "starts_at": "2026-07-06T15:00:00Z",
        "ends_at": "2026-07-06T17:00:00Z",
        "all_day": true,
        "visibility": "everyone",
        "work_unit_id": 1,
        "participants": [
            345,
            346
        ],
        "rsvp": true,
        "recurrence": "weekly",
        "recurrence_until": "2026-05-01",
        "series_id": 1,
        "cancelled_at": "2026-05-01T08:00:00Z",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Performanță

Indicatori KPI /kpi-metrics

Ce măsoară compania: cheia fiecărui indicator, unitatea de măsură, pentru cine se măsoară (nivelul) și cât de des (perioada). Doar citire; indicatorii se definesc în aplicație. Prin API se pot trimite valori doar pentru indicatorii cu sursa „api”.

Drepturi: kpi_metrics:read

Adrese

  • GET /api/v1/kpi-metrics Listă
  • GET /api/v1/kpi-metrics/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
keystringdoar citire Cheia indicatorului, folosită în formule și la trimiterea valorilor.
labelstringdoar citire Numele, în limba companiei.
descriptionstring | nulldoar citire Ce măsoară.
unitcurrency | percent | count | score | days | hours | ratiodoar citire Unitatea: currency, percent, count, score, days, hours sau ratio.
value_typedecimal | integer | percent | booleandoar citire Felul valorii: decimal, integer, percent sau boolean.
grainemployee | team | department | work_unit | geo_area | companydoar citire Pentru cine se măsoară: employee, team, department, work_unit, geo_area sau company.
periodday | week | month | quarter | yeardoar citire Cât de des: day, week, month, quarter sau year.
aggregationsum | avg | last | min | max | countdoar citire Cum se adună valorile pe o perioadă mai lungă.
source_typemanual | import | module | derived | api | objective | reviewdoar citire De unde vin valorile (manual, import, api, un modul…).
is_higher_betterbooleandoar citire Dacă o valoare mai mare e mai bună.
is_activebooleandoar citire Dacă este în folosință.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

keystringCheia exactă (fără diferență între litere mari și mici).
source_typemanual | import | module | derived | api | objective | reviewDoar indicatorii cu această sursă.
is_activebooleantrue sau false.

Exemplu de răspuns

{
    "data": {
        "id": 7,
        "key": "sales.actual",
        "label": "Sales",
        "description": null,
        "unit": "currency",
        "value_type": "decimal",
        "grain": "employee",
        "period": "month",
        "aggregation": "sum",
        "source_type": "api",
        "is_higher_better": true,
        "is_active": true,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Valori KPI /metric-values

Valoarea unui indicator pentru un subiect într-o perioadă. Crearea o scrie (sau înlocuiește valoarea existentă pentru acel subiect și acea perioadă); acceptă valori doar indicatorii cu sursa „api”. O valoare lipsă (null) înseamnă „fără date”, niciodată zero. Pentru multe valori după referințe de business (marcă, codul unității) folosiți POST /metrics/{key}/values.

Drepturi: metric_values:read, metric_values:write

Adrese

  • GET /api/v1/metric-values Listă
  • GET /api/v1/metric-values/{id} O înregistrare
  • POST /api/v1/metric-values Creare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
metricstringobligatoriu Cheia indicatorului.
subject_typeemployee | team | department | work_unit | geo_area | companydoar citire Felul subiectului (nivelul indicatorului).
subject_idintegerobligatoriu Id-ul subiectului (angajat, unitate, departament, zonă sau echipă; 0 pentru companie).
periodstringobligatoriu Cheia perioadei: 2026-09 (lună), 2026-W38 (săptămână), 2026-Q3, 2026, 2026-09-14 (zi).
period_startdatedoar citire Prima zi a perioadei.
period_enddatedoar citire Ultima zi a perioadei.
valuescalar | null Valoarea, ca număr sau text („1234.5”, „1.234,5”, „87%”, true/false); null pentru fără date. Se păstrează ca șir zecimal.
sourcemanual | import | module | derived | api | objective | reviewdoar citire De unde provine.
recorded_atdatetimedoar citire Când a fost scrisă.

Filtre

metricstringDoar valorile acestui indicator (cheia lui).
periodstringDoar această perioadă (împreună cu metric).
subject_idintegerDoar acest subiect.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/metric-values

{
    "metric": "sales.api",
    "subject_id": 345,
    "period": "2026-09",
    "value": "1234.5"
}

Exemplu de răspuns

{
    "data": {
        "id": 5120,
        "metric": "sales.api",
        "subject_type": "employee",
        "subject_id": 345,
        "period": "2026-09",
        "period_start": "2026-09-01",
        "period_end": "2026-09-30",
        "value": "1234.5",
        "source": "api",
        "recorded_at": "2026-05-01T08:00:00Z"
    }
}

Fișe de performanță /kpi-scorecards

Fișele de performanță cu toate versiunile lor (ciornă, publicată, arhivată): părțile din care e făcut scorul, ponderile lor și nivelurile în care cade un scor. Doar citire; fișele se construiesc în aplicație, iar o versiune publicată nu se mai schimbă.

Drepturi: kpi_scorecards:read

Adrese

  • GET /api/v1/kpi-scorecards Listă
  • GET /api/v1/kpi-scorecards/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificatorul acestei versiuni.
familystringdoar citire Fișa, de-a lungul versiunilor ei.
versionintegerdoar citire Numărul versiunii.
namestringdoar citire Nume.
descriptionstring | nulldoar citire Descriere.
grainemployee | team | department | work_unit | geo_area | companydoar citire Pe cine notează.
periodday | week | month | quarter | yeardoar citire Cât de des notează.
statusdraft | published | archiveddoar citire draft, published sau archived.
effective_fromdate | nulldoar citire În vigoare de la.
effective_todate | nulldoar citire În vigoare până la.
published_atdatetime | nulldoar citire Când a fost publicată această versiune.
componentsarraydoar citire Părțile: cheie, etichetă, pondere (0–1), țintă, format de afișare, dacă o vede angajatul.
levelsarraydoar citire Nivelurile: nume, cel mai mic scor care îl atinge, culoare.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

statusdraft | published | archivedDoar versiunile cu această stare.
familystringDoar versiunile acestei fișe.

Exemplu de răspuns

{
    "data": {
        "id": 4,
        "family": "9b2e0c1e-0f0a-4b47-9f3a-2c1d7e8a1b20",
        "version": 2,
        "name": "Pharmacist performance",
        "description": null,
        "grain": "employee",
        "period": "month",
        "status": "published",
        "effective_from": "2026-05-01",
        "effective_to": "2026-05-01",
        "published_at": "2026-05-01T08:00:00Z",
        "components": [
            {
                "key": "sales",
                "label": "Sales achievement",
                "weight": "0.55"
            }
        ],
        "levels": [
            {
                "name": "Good",
                "min_score": "85",
                "color": "#2B6CB0"
            }
        ],
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Rezultate KPI /kpi-results

Scorurile pe fișele de performanță: rezultatul curent al fiecărui subiect și al fiecărei perioade, nivelul atins și valoarea și punctele fiecărei părți. Un total sau o parte fără date este null, niciodată zero. Doar citire; rezultatele apar la închiderea unei perioade.

Drepturi: kpi_results:read

Adrese

  • GET /api/v1/kpi-results Listă
  • GET /api/v1/kpi-results/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
scorecard_idintegerdoar citire Versiunea fișei care l-a calculat.
scorecardstringdoar citire Numele ei.
subject_typeemployee | team | department | work_unit | geo_area | companydoar citire Felul subiectului.
subject_idintegerdoar citire Id-ul subiectului.
subjectstring | nulldoar citire Numele subiectului.
perioddatedoar citire Prima zi a perioadei.
totalstring | nulldoar citire Scorul, ca șir zecimal; null când nu sunt date.
levelstring | nulldoar citire Nivelul atins.
level_colorstring | nulldoar citire Culoarea nivelului.
bonusstring | nulldoar citire Bonusul, când fișa îl calculează.
partsarraydoar citire Fiecare parte: cheie, etichetă, valoare și punctele aduse (șiruri zecimale; null pentru fără date).
created_atdatetimedoar citire Când a fost calculat.

Filtre

scorecard_idintegerDoar această versiune a fișei.
perioddatePrima zi a perioadei (Y-m-d).
subject_typeemployee | team | department | work_unit | geo_area | companyDoar acest fel de subiect.
subject_idintegerDoar acest subiect.

Exemplu de răspuns

{
    "data": {
        "id": 9811,
        "scorecard_id": 4,
        "scorecard": "Pharmacist performance",
        "subject_type": "employee",
        "subject_id": 345,
        "subject": "Ana Popescu",
        "period": "2026-09-01",
        "total": "92.40",
        "level": "Good",
        "level_color": "#2B6CB0",
        "bonus": null,
        "parts": [
            {
                "key": "sales",
                "label": "Sales achievement",
                "value": "104.2",
                "points": "57.31"
            }
        ],
        "created_at": "2026-05-01T08:00:00Z"
    }
}

Obiective /objectives

Obiective după o regulă (de exemplu „produse focus”): perioada, parametrii și țintele pe unități. Regula și perioada nu se mai schimbă după creare. Acțiunea record păstrează ce au realizat oamenii sau unitățile; punctajul se calculează la închiderea perioadei. Un obiectiv deja punctat nu poate fi șters.

Drepturi: objectives:read, objectives:write

Adrese

  • GET /api/v1/objectives Listă
  • GET /api/v1/objectives/{id} O înregistrare
  • POST /api/v1/objectives Creare
  • PATCH /api/v1/objectives/{id} Modificare
  • DELETE /api/v1/objectives/{id} Ștergere
  • POST /api/v1/objectives/{id}/record Păstrează ce au realizat subiecții: măsurile lor înlocuiesc ce era înregistrat; măsurile goale șterg înregistrarea (din nou fără date).

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
rule_idintegerobligatoriu Regula care îl punctează (doar la creare).
rulestringdoar citire Numele regulii.
namestringobligatoriu Nume.
descriptiontext | null Descriere.
periodstringobligatoriu Cheia perioadei, în perioada regulii (doar la creare), de exemplu 2026-09.
period_startdatedoar citire Prima zi.
period_enddatedoar citire Ultima zi.
paramsobject Valorile parametrilor regulii, după nume (celelalte se ignoră); lipsă: valorile implicite ale regulii.
targetsarray Țintele pe unități: o listă de {work_unit_id, target}. Când are ținte, obiectivul este doar pentru acele unități.
external_refstring | null Referința dumneavoastră (doar la creare).
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

rule_idintegerDoar după această regulă.
period_startdatePrima zi a perioadei (Y-m-d).
external_refstringReferința exactă.

/api/v1/objectives/{id}/record: achievements (array) — O listă de {subject_id, measures: {numele măsurii: număr}}; subiecți la nivelul regulii, din unitățile cu ținte.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/objectives

{
    "rule_id": 2,
    "name": "Vitamin C 1000",
    "period": "2026-09",
    "params": {
        "bonus": "2"
    },
    "targets": [
        {
            "work_unit_id": 12,
            "target": "30"
        }
    ],
    "external_ref": "CAMP-2026-09"
}

Exemplu de răspuns

{
    "data": {
        "id": 31,
        "rule_id": 2,
        "rule": "Focus products",
        "name": "Vitamin C 1000",
        "description": null,
        "period": "2026-09",
        "period_start": "2026-09-01",
        "period_end": "2026-09-30",
        "params": {
            "bonus": "2"
        },
        "targets": [
            {
                "work_unit_id": 12,
                "target": "30"
            }
        ],
        "external_ref": "CAMP-2026-09",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Evaluări /reviews

Evaluările date pe grile: cui, de cine, pentru ce perioadă, punctele și rezultatul și răspunsul la fiecare criteriu. Doar citire; evaluările se dau în aplicație. Ciornele sunt lucrul evaluatorului și nu apar niciodată.

Drepturi: reviews:read

Adrese

  • GET /api/v1/reviews Listă
  • GET /api/v1/reviews/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
form_idintegerdoar citire Versiunea grilei.
formstringdoar citire Numele grilei.
employee_idintegerdoar citire Persoana evaluată.
evaluator_idinteger | nulldoar citire Contul celui care a evaluat.
period_startdatedoar citire Prima zi a perioadei.
period_enddatedoar citire Ultima zi.
statussubmitted | cancelleddoar citire submitted sau cancelled.
total_pointsstring | nulldoar citire Punctele obținute.
max_pointsstring | nulldoar citire Punctele posibile.
resultstring | nulldoar citire Rezultatul (puncte sau procent, când grila dă procent).
commenttext | nulldoar citire Comentariul evaluatorului, ca text simplu.
submitted_atdatetime | nulldoar citire Când a fost trimisă.
cancelled_atdatetime | nulldoar citire Când a fost anulată.
answersarraydoar citire Fiecare criteriu: cheie, variantele alese, o valoare, punctele și un comentariu.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

statussubmitted | cancelledsubmitted sau cancelled.
employee_idintegerDoar această persoană.
form_idintegerDoar această versiune a grilei.
period_startdatePrima zi a perioadei (Y-m-d).

Exemplu de răspuns

{
    "data": {
        "id": 812,
        "form_id": 3,
        "form": "Monthly evaluation",
        "employee_id": 345,
        "evaluator_id": 12,
        "period_start": "2026-09-01",
        "period_end": "2026-09-30",
        "status": "submitted",
        "total_points": "8.00",
        "max_points": "10.00",
        "result": "80",
        "comment": null,
        "submitted_at": "2026-05-01T08:00:00Z",
        "cancelled_at": "2026-05-01T08:00:00Z",
        "answers": [
            {
                "criterion_key": "attitude",
                "selected": [
                    "teamwork"
                ],
                "value": null,
                "points": "2.00",
                "comment": null
            }
        ],
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Instruire, audit și SSM

Cursuri /courses

Catalogul de cursuri. Titlul și descrierea se scriu în limba companiei (celelalte limbi se traduc în aplicație); capitolele și coperțile se scriu în aplicație. Un curs se poate șterge doar cât timp nu a fost alocat nimănui — altfel arhivați-l.

Drepturi: courses:read, courses:write

Adrese

  • GET /api/v1/courses Listă
  • GET /api/v1/courses/{id} O înregistrare
  • POST /api/v1/courses Creare
  • PATCH /api/v1/courses/{id} Modificare
  • DELETE /api/v1/courses/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
titlestringobligatoriu Titlu.
descriptiontext | null Descriere scurtă, text simplu.
category_idinteger | null Categoria.
categorystring | nulldoar citire Numele categoriei.
authorstring | null Autor.
statusdraft | published | archivedobligatoriu draft, published sau archived; doar cursurile publicate pot fi alocate.
estimated_minutesinteger | null Durata estimată, în minute.
validity_monthsinteger | null Câte luni rămâne valabil certificatul; gol: nu expiră.
issues_certificateboolean Dacă la final se emite un certificat.
recertifiesboolean Dacă oamenii sunt reînscriși înainte să expire certificatul.
pointsintegerobligatoriu Punctele primite la final.
chapters_countintegerdoar citire Numărul de capitole.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

statusdraft | published | archivedDoar cu această stare.
category_idintegerDoar din această categorie.
qstringO parte din titlu.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/courses

{
    "title": "Siguranța la incendiu",
    "status": "published",
    "estimated_minutes": 20,
    "validity_months": 12,
    "issues_certificate": true,
    "recertifies": false,
    "points": 10
}

Exemplu de răspuns

{
    "data": {
        "id": 7,
        "title": "Siguranța la incendiu",
        "description": null,
        "category_id": 1,
        "category": "Obligatorii",
        "author": null,
        "status": "published",
        "estimated_minutes": 20,
        "validity_months": 12,
        "issues_certificate": true,
        "recertifies": false,
        "points": 10,
        "chapters_count": 4,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Alocări de instruire /learning-assignments

Un curs publicat (sau un test de sine stătător) dat unor oameni: tuturor, unei unități, unei zone, unui departament, unei funcții sau unor angajați anume. Oamenii sunt înscriși imediat. Se șterge doar cât timp nimeni nu a început.

Drepturi: learning_assignments:read, learning_assignments:write

Adrese

  • GET /api/v1/learning-assignments Listă
  • GET /api/v1/learning-assignments/{id} O înregistrare
  • POST /api/v1/learning-assignments Creare
  • DELETE /api/v1/learning-assignments/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
course_idinteger | null Cursul (sau test_id).
test_idinteger | null Un test de sine stătător (sau course_id).
available_fromdateobligatoriu De când poate fi parcurs.
due_ondate | null Termen.
enrolls_newcomersboolean Dacă cei care corespund mai târziu sunt înscriși automat.
targetsarrayobligatoriu Cui: o listă de {type, id}; type este all, employee, position, work_unit, department sau geo_area (id gol pentru all).
enrollments_countintegerdoar citire Oameni înscriși.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

course_idintegerDoar pentru acest curs.
test_idintegerDoar pentru acest test.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/learning-assignments

{
    "course_id": 7,
    "available_from": "2026-05-01",
    "due_on": "2026-05-31",
    "enrolls_newcomers": true,
    "targets": [
        {
            "type": "work_unit",
            "id": 12
        }
    ]
}

Exemplu de răspuns

{
    "data": {
        "id": 31,
        "course_id": 7,
        "test_id": 1,
        "available_from": "2026-05-01",
        "due_on": "2026-05-31",
        "enrolls_newcomers": true,
        "targets": [
            {
                "type": "work_unit",
                "id": 12
            }
        ],
        "enrollments_count": 14,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Înscrieri /enrollments

Cine este înscris la ce curs sau test și cât a parcurs. Acțiuni: un termen mai târziu, încă o încercare, scutirea cuiva care nu a început.

Drepturi: enrollments:read, enrollments:write

Adrese

  • GET /api/v1/enrollments Listă
  • GET /api/v1/enrollments/{id} O înregistrare
  • POST /api/v1/enrollments/{id}/extend Stabilește un termen mai târziu.
  • POST /api/v1/enrollments/{id}/grant-attempt Permite încă o încercare la test (nu după promovare).
  • POST /api/v1/enrollments/{id}/excuse Scutește persoana (doar înainte să înceapă).

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
assignment_idinteger | nulldoar citire Alocarea din care provine.
employee_idintegerdoar citire Persoana.
course_idinteger | nulldoar citire Cursul.
test_idinteger | nulldoar citire Testul.
available_fromdate | nulldoar citire Disponibil de la.
due_ondate | nulldoar citire Termen.
statusassigned | in_progress | awaiting_grading | completed | failed | excuseddoar citire assigned, in_progress, awaiting_grading, completed, failed sau excused.
started_atdatetime | nulldoar citire Început.
completed_atdatetime | nulldoar citire Terminat.
scorenumber | nulldoar citire Scorul la test (%).
passedboolean | nulldoar citire Dacă testul a fost promovat.
extra_attemptsintegerdoar citire Încercări suplimentare acordate.
is_overduebooleandoar citire Trecut de termen și neterminat.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

employee_idintegerDoar această persoană.
course_idintegerDoar acest curs.
test_idintegerDoar acest test.
assignment_idintegerDoar această alocare.
statusassigned | in_progress | awaiting_grading | completed | failed | excusedDoar cu această stare.

/api/v1/enrollments/{id}/extend: due_on (date) — Noul termen, nu înainte de deschiderea înscrierii.

Exemplu de răspuns

{
    "data": {
        "id": 501,
        "assignment_id": 31,
        "employee_id": 345,
        "course_id": 7,
        "test_id": 1,
        "available_from": "2026-05-01",
        "due_on": "2026-05-31",
        "status": "completed",
        "started_at": "2026-05-01T08:00:00Z",
        "completed_at": "2026-05-01T08:00:00Z",
        "score": 90,
        "passed": true,
        "extra_attempts": 0,
        "is_overdue": false,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Certificate /certificates

Certificatele obținute la terminarea unui curs, cu codul pe care oricine îl poate verifica pe pagina certificatului.

Drepturi: certificates:read

Adrese

  • GET /api/v1/certificates Listă
  • GET /api/v1/certificates/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
enrollment_idintegerdoar citire Înscrierea care l-a adus.
employee_idintegerdoar citire Persoana.
course_idintegerdoar citire Cursul.
numberstringdoar citire Numărul certificatului.
verification_codestringdoar citire Codul public de verificare.
issued_ondatedoar citire Emis la.
expires_ondate | nulldoar citire Valabil până la; gol: nu expiră.
is_validbooleandoar citire Valabil azi.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

employee_idintegerDoar această persoană.
course_idintegerDoar acest curs.

Exemplu de răspuns

{
    "data": {
        "id": 88,
        "enrollment_id": 501,
        "employee_id": 345,
        "course_id": 7,
        "number": "FV-2026-0042",
        "verification_code": "K7Q2M9XA",
        "issued_on": "2026-05-12",
        "expires_on": "2027-05-12",
        "is_valid": true,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Audituri /audits

Auditurile unităților, cu constatările lor, punct cu punct. Doar citire: un audit se face în aplicație.

Drepturi: audits:read

Adrese

  • GET /api/v1/audits Listă
  • GET /api/v1/audits/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
work_unit_idintegerdoar citire Unitatea auditată.
template_namestringdoar citire Lista de verificare folosită.
auditor_idinteger | nulldoar citire Cine l-a făcut (utilizator).
statusdraft | completeddoar citire draft sau completed.
conducted_atdatetime | nulldoar citire Când a avut loc.
completed_atdatetime | nulldoar citire Când a fost finalizat.
scorenumber | nulldoar citire Scor (%).
pass_scorenumber | nulldoar citire Prag (%).
passedboolean | nulldoar citire Promovat (doar auditurile finalizate).
critical_findingsintegerdoar citire Puncte critice neîndeplinite.
is_self_checkbooleandoar citire Făcut de cineva care lucrează în unitate sau o conduce (nu intră în KPI-urile de audit).
notetext | nulldoar citire Observații.
findingsarraydoar citire Fiecare punct: {id, section, item, weight, critical, result (ok, not_ok, na), comment}.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

work_unit_idintegerDoar această unitate.
statusdraft | completedDoar cu această stare.
conducted_fromdateFăcut la această dată sau după.
conducted_todateFăcut la această dată sau înainte.

Exemplu de răspuns

{
    "data": {
        "id": 19,
        "work_unit_id": 12,
        "template_name": "Verificare lunară farmacie",
        "auditor_id": 1,
        "status": "completed",
        "conducted_at": "2026-05-01T08:00:00Z",
        "completed_at": "2026-05-01T08:00:00Z",
        "score": 88.89,
        "pass_score": 80,
        "passed": true,
        "critical_findings": 0,
        "is_self_check": true,
        "note": null,
        "findings": [
            {
                "section": "Frigider",
                "item": "Termometrul este calibrat",
                "weight": 2,
                "critical": true,
                "result": "not_ok",
                "comment": "Ultima calibrare în martie."
            }
        ],
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Acțiuni corective /audit-action-plans

Acțiunile corective stabilite după audituri. Avansează ca pe pagina auditului: marcate ca rezolvate cu o notă, verificate, redeschise cu un motiv sau anulate.

Drepturi: audit_action_plans:read, audit_action_plans:write

Adrese

  • GET /api/v1/audit-action-plans Listă
  • GET /api/v1/audit-action-plans/{id} O înregistrare
  • POST /api/v1/audit-action-plans/{id}/mark-done Marchează o acțiune deschisă ca rezolvată.
  • POST /api/v1/audit-action-plans/{id}/verify Acceptă o acțiune rezolvată.
  • POST /api/v1/audit-action-plans/{id}/reopen Trimite înapoi o acțiune rezolvată, cu motivul.
  • POST /api/v1/audit-action-plans/{id}/cancel Anulează o acțiune deschisă sau rezolvată.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
audit_idintegerdoar citire Auditul.
result_idinteger | nulldoar citire Constatarea la care răspunde.
descriptiontextdoar citire Ce trebuie făcut.
responsible_idinteger | nulldoar citire Cine trebuie să o facă (utilizator).
due_ondatedoar citire Termen.
statusopen | done | verified | cancelleddoar citire open, done, verified sau cancelled.
is_overduebooleandoar citire Deschisă și trecută de termen.
done_notetext | nulldoar citire Ce s-a făcut (și de ce a fost redeschisă).
done_atdatetime | nulldoar citire Marcată rezolvată.
verified_byinteger | nulldoar citire Cine a verificat-o (utilizator).
verified_atdatetime | nulldoar citire Verificată.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

audit_idintegerDoar pentru acest audit.
statusopen | done | verified | cancelledDoar cu această stare.
responsible_idintegerDoar pentru această persoană.

/api/v1/audit-action-plans/{id}/mark-done: note (text) — Ce s-a făcut.

/api/v1/audit-action-plans/{id}/reopen: reason (text) — De ce nu este acceptată.

Exemplu de răspuns

{
    "data": {
        "id": 4,
        "audit_id": 19,
        "result_id": 1,
        "description": "Calibrați termometrul frigiderului și păstrați certificatul.",
        "responsible_id": 1,
        "due_on": "2026-05-20",
        "status": "open",
        "is_overdue": true,
        "done_note": null,
        "done_at": "2026-05-01T08:00:00Z",
        "verified_by": 1,
        "verified_at": "2026-05-01T08:00:00Z",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Tipuri SSM /ssm-types

Tipurile de instruiri și controale de sănătate și securitate în muncă pe care compania le înregistrează, cu valabilitatea fiecăruia.

Drepturi: ssm_types:read

Adrese

  • GET /api/v1/ssm-types Listă
  • GET /api/v1/ssm-types/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringdoar citire Nume.
validity_monthsinteger | nulldoar citire Câte luni rămâne valabil; gol: nu expiră.
is_requiredbooleandoar citire Obligatoriu pentru toți.
is_activebooleandoar citire În folosință.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

is_activebooleantrue sau false.

Exemplu de răspuns

{
    "data": {
        "id": 2,
        "name": "Instruire periodică",
        "validity_months": 6,
        "is_required": true,
        "is_active": true,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Înregistrări SSM /ssm-records

Cine a avut ce instruire sau control SSM, când și până când este valabil (calculat din tip). O înregistrare pe apel.

Drepturi: ssm_records:read, ssm_records:write

Adrese

  • GET /api/v1/ssm-records Listă
  • GET /api/v1/ssm-records/{id} O înregistrare
  • POST /api/v1/ssm-records Creare
  • DELETE /api/v1/ssm-records/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
employee_idintegerobligatoriu Persoana.
type_idintegerobligatoriu Instruirea sau controlul.
done_ondateobligatoriu Când a fost efectuat (nu în viitor).
valid_untildate | nulldoar citire Valabil până la (din tip).
statevalid | expiring | expired | missing | nonedoar citire Azi: valid, expiring, expired.
trainerstring | null Instructor sau medic.
notestring | null Observații.
recorded_byinteger | nulldoar citire Cine l-a înregistrat (utilizator).
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

employee_idintegerDoar această persoană.
type_idintegerDoar acest tip.
valid_until_beforedateValabil până la această dată sau mai devreme.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/ssm-records

{
    "employee_id": 345,
    "type_id": 2,
    "done_on": "2026-04-15"
}

Exemplu de răspuns

{
    "data": {
        "id": 120,
        "employee_id": 345,
        "type_id": 2,
        "done_on": "2026-04-15",
        "valid_until": "2026-10-15",
        "state": "valid",
        "trainer": null,
        "note": null,
        "recorded_by": 1,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Documente, solicitări, chestionare și comunicare

Categorii de documente /document-categories

Categoriile în care se îndosariază documentele, pentru toată compania sau pentru unități.

Drepturi: document_categories:read

Adrese

  • GET /api/v1/document-categories Listă
  • GET /api/v1/document-categories/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringdoar citire Nume, în limba cerută.
scopecompany | unitdoar citire company (documente ale companiei) sau unit (documente ale unităților).
sortintegerdoar citire Poziția în liste.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

scopecompany | unitDoar categoriile companiei sau doar ale unităților.

Exemplu de răspuns

{
    "data": {
        "id": 4,
        "name": "Autorizații",
        "scope": "company",
        "sort": 1,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Documente /documents

Autorizații, contracte și regulamente, cu data expirării. API-ul citește datele documentului și numele, mărimea și tipul fișierului curent; fișierul se descarcă din aplicație. Un fișier se trimite ca {"name", "content_base64"} (aceleași tipuri ca în aplicație — PDF, Office, imagini, ZIP — cel mult 50 MB); un fișier trimis la un document existent adaugă o versiune nouă. Ștergerea mută documentul în coș, de unde se poate restaura din aplicație.

Drepturi: documents:read, documents:write

Adrese

  • GET /api/v1/documents Listă
  • GET /api/v1/documents/{id} O înregistrare
  • POST /api/v1/documents Creare
  • PATCH /api/v1/documents/{id} Modificare
  • DELETE /api/v1/documents/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
titlestringobligatoriu Titlu.
descriptiontext | null Descriere.
category_idinteger | null Categoria (vedeți /document-categories).
work_unit_idinteger | null Unitatea căreia îi aparține; gol pentru un document al companiei. Se alege doar la creare.
is_internalboolean Îl văd doar cei care administrează documentele.
expires_ondate | null Data expirării.
expiry_statevalid | expiring | expired | nulldoar citire valid, expiring sau expired (gol fără dată de expirare).
repeat_monthsinteger | null Se reînnoiește la acest număr de luni.
alert_daysarray | null Cu câte zile înainte de expirare pleacă mementourile (cel mult 6).
versionsintegerdoar citire Câte versiuni ale fișierului există.
file_namestring | nulldoar citire Numele fișierului curent.
file_sizeinteger | nulldoar citire Mărimea, în octeți.
file_mimestring | nulldoar citire Tipul.
filefileobligatoriu Fișierul: {"name": "…", "content_base64": "…"}. Obligatoriu la creare; la modificare adaugă o versiune.
version_notestring | null O notă pentru versiunea fișierului (se citește nota versiunii curente).
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

work_unit_idintegerDoar documentele acestei unități.
category_idintegerDoar această categorie.
companybooleantrue: doar documentele companiei; false: doar ale unităților.
expires_beforedateCare expiră până la această dată, inclusiv.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/documents

{
    "title": "Autorizație sanitară de funcționare",
    "category_id": 4,
    "work_unit_id": 12,
    "is_internal": false,
    "expires_on": "2026-12-31",
    "repeat_months": 12,
    "alert_days": [
        30,
        7
    ],
    "file": {
        "name": "document.pdf",
        "content_base64": "JVBERi0xLjQK…"
    }
}

Exemplu de răspuns

{
    "data": {
        "id": 31,
        "title": "Autorizație sanitară de funcționare",
        "description": null,
        "category_id": 4,
        "work_unit_id": 12,
        "is_internal": false,
        "expires_on": "2026-12-31",
        "expiry_state": "valid",
        "repeat_months": 12,
        "alert_days": [
            30,
            7
        ],
        "versions": 2,
        "file_name": "autorizatie.pdf",
        "file_size": 184220,
        "file_mime": "application/pdf",
        "version_note": null,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Categorii de solicitări /service-categories

Despre ce sunt solicitările de servicii (mentenanță, IT…) și dacă au nevoie întâi de aprobare.

Drepturi: service_categories:read

Adrese

  • GET /api/v1/service-categories Listă
  • GET /api/v1/service-categories/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringdoar citire Nume, în limba cerută.
is_activebooleandoar citire Dacă se pot face solicitări în ea.
needs_approvalbooleandoar citire Dacă o solicitare așteaptă aprobarea înainte să se deschidă.
sortintegerdoar citire Poziția în liste.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

is_activebooleantrue sau false.

Exemplu de răspuns

{
    "data": {
        "id": 2,
        "name": "Mentenanță și reparații",
        "is_active": true,
        "needs_approval": false,
        "sort": 1,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Solicitări /service-requests

Cereri de a repara sau de a asigura ceva într-o unitate, cu istoricul lor. Se depun pentru persoana din requested_by (care trebuie să poată face solicitări pentru acea unitate) sau pentru cel care a creat cheia; se aplică fluxul de aprobare al categoriei. Se mută cu acțiunea move, cum poate face pe ecran cel care a creat cheia.

Drepturi: service_requests:read, service_requests:write

Adrese

  • GET /api/v1/service-requests Listă
  • GET /api/v1/service-requests/{id} O înregistrare
  • POST /api/v1/service-requests Creare
  • POST /api/v1/service-requests/{id}/move Mută solicitarea în altă stare (in_progress, resolved, unresolved, open, cancelled), cum poate cel care a creat cheia. Nerezolvată și redeschiderea cer un comentariu.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
category_idintegerobligatoriu Categoria (vedeți /service-categories).
work_unit_idintegerobligatoriu Unitatea pentru care este.
titlestringobligatoriu Titlu scurt.
descriptiontextobligatoriu Ce nu merge sau ce trebuie.
requested_byinteger Utilizatorul pentru care se depune (o persoană din companie); cel care a creat cheia, dacă lipsește.
employee_idintegerdoar citire Fișa de angajat a celui care a depus-o.
statusawaiting_approval | open | in_progress | resolved | unresolved | rejected | cancelleddoar citire awaiting_approval, open, in_progress, resolved, unresolved, rejected sau cancelled.
assigned_tointeger | nulldoar citire Utilizatorul care a preluat-o.
closed_atdatetime | nulldoar citire Când a fost închisă.
historyarraydoar citire Fiecare mutare: din, în, comentariu, de cine, când.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

statusawaiting_approval | open | in_progress | resolved | unresolved | rejected | cancelledDoar cu această stare.
category_idintegerDoar această categorie.
work_unit_idintegerDoar această unitate.

/api/v1/service-requests/{id}/move: status (awaiting_approval | open | in_progress | resolved | unresolved | rejected | cancelled) — Starea nouă.; comment (text) — De ce (obligatoriu pentru nerezolvată și la redeschidere).

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/service-requests

{
    "category_id": 2,
    "work_unit_id": 12,
    "title": "Frigiderul de vaccinuri nu mai răcește",
    "description": "text",
    "requested_by": 17
}

Exemplu de răspuns

{
    "data": {
        "id": 88,
        "category_id": 2,
        "work_unit_id": 12,
        "title": "Frigiderul de vaccinuri nu mai răcește",
        "description": "text",
        "requested_by": 17,
        "employee_id": 345,
        "status": "open",
        "assigned_to": 1,
        "closed_at": "2026-05-01T08:00:00Z",
        "history": [
            {
                "status_from": "open",
                "status_to": "in_progress",
                "comment": "Vine tehnicianul mâine.",
                "user_id": 9,
                "at": "2026-05-04T08:00:00Z"
            }
        ],
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Materiale /materials

Ce pot cere unitățile, cu stocul de acum, acolo unde se urmărește.

Drepturi: materials:read

Adrese

  • GET /api/v1/materials Listă
  • GET /api/v1/materials/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringdoar citire Nume.
descriptiontext | nulldoar citire Descriere.
unitstringdoar citire Unitatea de măsură.
track_stockbooleandoar citire Dacă se urmărește stocul.
stocknumber | nulldoar citire Stocul de acum (gol dacă nu se urmărește).
is_activebooleandoar citire Dacă se poate cere.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

is_activebooleantrue sau false.

Exemplu de răspuns

{
    "data": {
        "id": 7,
        "name": "Mănuși nitril",
        "description": null,
        "unit": "cutie",
        "track_stock": true,
        "stock": 35,
        "is_active": true,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Cereri de materiale /material-requests

Cereri de materiale, cu pozițiile lor. Se depun pentru persoana din requested_by (sau pentru cel care a creat cheia), pentru materiale active și o unitate pentru care poate cere; apoi se preiau, se finalizează (stocul scade) sau se anulează, cum poate pe ecran cel care a creat cheia.

Drepturi: material_requests:read, material_requests:write

Adrese

  • GET /api/v1/material-requests Listă
  • GET /api/v1/material-requests/{id} O înregistrare
  • POST /api/v1/material-requests Creare
  • POST /api/v1/material-requests/{id}/take Preia o cerere nouă.
  • POST /api/v1/material-requests/{id}/complete O finalizează: stocul materialelor urmărite scade.
  • POST /api/v1/material-requests/{id}/cancel Anulează o cerere încă nefinalizată.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
work_unit_idintegerobligatoriu Unitatea pentru care este.
requested_byinteger Utilizatorul pentru care se depune; cel care a creat cheia, dacă lipsește.
statusnew | taken | completed | cancelleddoar citire new, taken, completed sau cancelled.
handled_byinteger | nulldoar citire Utilizatorul care o rezolvă.
notetext | null O notă.
itemsarrayobligatoriu Ce se cere: [{"material_id": 7, "quantity": 5}] (cel puțin o poziție).
completed_atdatetime | nulldoar citire Când a fost finalizată.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

statusnew | taken | completed | cancelledDoar cu această stare.
work_unit_idintegerDoar această unitate.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/material-requests

{
    "work_unit_id": 12,
    "requested_by": 17,
    "items": [
        {
            "material_id": 7,
            "quantity": 5
        }
    ]
}

Exemplu de răspuns

{
    "data": {
        "id": 51,
        "work_unit_id": 12,
        "requested_by": 17,
        "status": "new",
        "handled_by": 1,
        "note": null,
        "items": [
            {
                "material_id": 7,
                "quantity": 5
            }
        ],
        "completed_at": "2026-05-01T08:00:00Z",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Chestionare /surveys

Chestionarele publicate și închise, cu întrebările lor, și rezultatele doar ca totaluri: câți au ales fiecare răspuns, media unei scale și câți au răspuns la o întrebare liberă — niciodată ce au scris. Rezultatele unui chestionar anonim rămân ascunse cât timp răspunsurile sunt sigilate și cât are mai puțin de 5 răspunsuri.

Drepturi: surveys:read

Adrese

  • GET /api/v1/surveys Listă
  • GET /api/v1/surveys/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
titlestringdoar citire Titlu.
descriptiontext | nulldoar citire Descriere.
is_anonymousbooleandoar citire Dacă răspunsurile sunt anonime.
is_mandatorybooleandoar citire Dacă răspunsul este obligatoriu.
statuspublished | closeddoar citire published sau closed.
opens_atdatetime | nulldoar citire Când se deschide.
closes_atdatetime | nulldoar citire Când se închide.
published_atdatetime | nulldoar citire Când a fost publicat.
questionsarraydoar citire Întrebările: id, tip (single, multiple, scale, text), text, obligatorie, variante.
resultsobjectdoar citire Totaluri: hidden, sealed, responses, assigned, completed și, pe întrebare, câți au răspuns, numărul pe variantă sau pe valoare a scalei, media.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

statuspublished | closedpublished sau closed.
is_anonymousbooleantrue sau false.

Exemplu de răspuns

{
    "data": {
        "id": 5,
        "title": "Climatul de lucru",
        "description": null,
        "is_anonymous": true,
        "is_mandatory": false,
        "status": "closed",
        "opens_at": "2026-05-01T08:00:00Z",
        "closes_at": "2026-05-01T08:00:00Z",
        "published_at": "2026-05-01T08:00:00Z",
        "questions": [
            {
                "id": 11,
                "type": "single",
                "text": "Ați recomanda compania?",
                "is_required": true,
                "options": [
                    {
                        "id": 31,
                        "label": "Da"
                    }
                ]
            }
        ],
        "results": {
            "hidden": false,
            "responses": 14,
            "questions": [
                {
                    "question_id": 11,
                    "answered": 14,
                    "counts": {
                        "31": 11
                    },
                    "average": null
                }
            ]
        },
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Răspunsuri la chestionare /survey-responses

Răspunsurile la chestionarele nominale, câte un răspuns pe persoană cu ce a ales. Răspunsurile unui chestionar anonim nu se dau niciodată unul câte unul — doar totalurile, în /surveys.

Drepturi: survey_responses:read

Adrese

  • GET /api/v1/survey-responses Listă
  • GET /api/v1/survey-responses/{id} O înregistrare

Câmpuri

NumeTipDescriere
idstringdoar citire Identificator (un UUID).
survey_idintegerdoar citire Chestionarul.
employee_idintegerdoar citire Cine a răspuns.
submitted_atdatetime | nulldoar citire Când.
answersarraydoar citire Răspunsurile: întrebarea, varianta aleasă, valoarea (scală) sau textul.

Filtre

survey_idintegerDoar răspunsurile acestui chestionar.
employee_idintegerDoar răspunsurile acestei persoane.

Exemplu de răspuns

{
    "data": {
        "id": "9b2f4c1e-6f0a-4e7c-9a51-3c2d1e0f7a88",
        "survey_id": 5,
        "employee_id": 345,
        "submitted_at": "2026-05-01T08:00:00Z",
        "answers": [
            {
                "question_id": 11,
                "option_id": 31,
                "value": null,
                "text": null
            }
        ]
    }
}

Postări /posts

Postările Social pentru toată compania (nu dintr-un grup), publicate. Le creează cel care a creat cheia: o postare sau, dacă poate face anunțuri, o știre, un anunț, o promoție sau un concurs; textul este simplu, cu un rând liber între paragrafe.

Drepturi: posts:read, posts:write

Adrese

  • GET /api/v1/posts Listă
  • GET /api/v1/posts/{id} O înregistrare
  • POST /api/v1/posts Creare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
typepost | news | announcement | promotion | contestobligatoriu post, news, announcement, promotion sau contest.
titlestring | null Titlu (opțional).
bodytextobligatoriu Textul (simplu, la citire).
authorstring | nulldoar citire Cine a scris-o.
comments_enabledboolean Dacă se pot face comentarii.
comments_countintegerdoar citire Câte comentarii are.
published_atdatetime | null Când se publică; un moment viitor o programează.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

typepost | news | announcement | promotion | contestDoar acest tip.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/posts

{
    "type": "announcement",
    "title": "Program de sărbători",
    "body": "Între 24 și 26 decembrie programul este 9–14.",
    "comments_enabled": true
}

Exemplu de răspuns

{
    "data": {
        "id": 120,
        "type": "announcement",
        "title": "Program de sărbători",
        "body": "Între 24 și 26 decembrie programul este 9–14.",
        "author": "Maria Matei",
        "comments_enabled": true,
        "comments_count": 3,
        "published_at": "2026-05-01T08:00:00Z",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Articole din baza de cunoștințe /knowledge-articles

Articolele publicate din baza de cunoștințe (proceduri, instrucțiuni), cu textul simplu, în limba cerută (Accept-Language) sau în limba companiei.

Drepturi: knowledge_articles:read

Adrese

  • GET /api/v1/knowledge-articles Listă
  • GET /api/v1/knowledge-articles/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
category_idinteger | nulldoar citire Subiectul.
categorystring | nulldoar citire Numele subiectului.
titlestringdoar citire Titlu.
summarytext | nulldoar citire Rezumat.
bodytext | nulldoar citire Articolul, ca text simplu.
is_featuredbooleandoar citire Dacă este evidențiat.
published_atdatetime | nulldoar citire Prima publicare.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Ultima modificare.

Filtre

category_idintegerDoar acest subiect.
is_featuredbooleantrue sau false.

Exemplu de răspuns

{
    "data": {
        "id": 9,
        "category_id": 2,
        "category": "Operațiuni",
        "title": "Recepția mărfii",
        "summary": null,
        "body": null,
        "is_featured": true,
        "published_at": "2026-05-01T08:00:00Z",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Clienți (CRM)

Clienți /crm-contacts

Oamenii pe care compania îi deservește — clienți și potențiali clienți. O adresă de email este unică în companie (a doua este refuzată). Acordul de marketing nu se scrie odată cu înregistrarea: se schimbă doar prin acțiunea consent, care îi păstrează istoricul (dat sau retras, cum, când, de cine). Acțiunea erase șterge datele persoanei la cererea ei și nu poate fi anulată: numele, emailul, telefonul, notele și ce s-a scris despre ea dispar, cifrele (cumpărări, valori ale oportunităților, note) rămân, iar înregistrarea nu mai poate fi modificată.

Drepturi: crm_contacts:read, crm_contacts:write

Adrese

  • GET /api/v1/crm-contacts Listă
  • GET /api/v1/crm-contacts/{id} O înregistrare
  • POST /api/v1/crm-contacts Creare
  • PATCH /api/v1/crm-contacts/{id} Modificare
  • DELETE /api/v1/crm-contacts/{id} Ștergere
  • POST /api/v1/crm-contacts/{id}/consent Înregistrează că persoana și-a dat sau și-a retras acordul de marketing, și cum.
  • POST /api/v1/crm-contacts/{id}/erase Șterge datele persoanei la cererea ei (GDPR). Ireversibil.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
first_namestring | null Prenume.
last_namestring | null Nume.
emailstring | null Adresa de email (unică în companie, păstrată cu litere mici).
phonestring | null Telefon, așa cum a fost scris.
account_idinteger | null Organizația din care face parte (vezi /crm-accounts).
job_titlestring | null Rolul său acolo.
citystring | null Localitate.
countrystring | null Țara, cod ISO din două litere.
localestring | null Limba în care i se scrie (ro, en…).
statuslead | customer | inactive lead (potențial), customer (client) sau inactive. O cumpărare sau o oportunitate câștigată face dintr-un potențial client un client.
sourcewalk_in | website | phone | referral | campaign | event | partner | other | null De unde a venit: walk_in, website, phone, referral, campaign, event, partner sau other.
work_unit_idinteger | null Unitatea (magazin, hotel, birou) care îl deservește; gol pentru niciuna.
owner_idinteger | null Utilizatorul care se ocupă de el; cel care a creat cheia, dacă lipsește la creare.
tagsarray Etichete (litere mici, cel mult 20).
notestext | null Note.
marketing_consentbooleandoar citire Dacă acceptă acum comunicări de marketing (doar citire — se schimbă prin acțiunea consent).
consent_updated_atdatetime | nulldoar citire Când s-a schimbat ultima dată acordul.
last_activity_atdatetime | nulldoar citire Când s-a făcut ultima dată ceva cu el.
erased_atdatetime | nulldoar citire Când i-au fost șterse datele la cerere (înregistrarea e apoi doar de citit).
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Filtre

qstringNume, email sau telefon care conține textul.
emailstringExact acest email (literele mari nu contează).
phonestringAcest număr de telefon (se compară doar cifrele).
statuslead | customer | inactiveDoar cu această stare.
work_unit_idintegerDoar ai acestei unități.
owner_idintegerDoar ai acestui utilizator.
account_idintegerDoar ai acestei organizații.
tagstringDoar cu această etichetă.
consentbooleantrue: doar cei care acceptă marketing; false: doar cei care nu acceptă.

/api/v1/crm-contacts/{id}/consent: granted (boolean) — true: dat; false: retras.; channel (form | verbal | email | import | api | other) — Cum: form, verbal, email, import, api sau other (api, dacă lipsește).; note (string) — O notă (de exemplu unde se păstrează formularul).

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/crm-contacts

{
    "first_name": "Ioana",
    "last_name": "Pop",
    "email": "ioana.pop@example.com",
    "phone": "0722 111 222",
    "account_id": 31,
    "city": "Cluj-Napoca",
    "country": "RO",
    "locale": "ro",
    "status": "customer",
    "source": "walk_in",
    "work_unit_id": 12,
    "owner_id": 17,
    "tags": [
        "loyalty"
    ]
}

Exemplu de răspuns

{
    "data": {
        "id": 120,
        "first_name": "Ioana",
        "last_name": "Pop",
        "email": "ioana.pop@example.com",
        "phone": "0722 111 222",
        "account_id": 31,
        "job_title": null,
        "city": "Cluj-Napoca",
        "country": "RO",
        "locale": "ro",
        "status": "customer",
        "source": "walk_in",
        "work_unit_id": 12,
        "owner_id": 17,
        "tags": [
            "loyalty"
        ],
        "notes": null,
        "marketing_consent": true,
        "consent_updated_at": "2026-05-01T08:00:00Z",
        "last_activity_at": "2026-05-01T08:00:00Z",
        "erased_at": "2026-05-01T08:00:00Z",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Organizații client /crm-accounts

Companiile și instituțiile cărora le vinde firma. Numele este unic în companie. Ștergerea uneia îi păstrează contactele și oportunitățile, fără legătură.

Drepturi: crm_accounts:read, crm_accounts:write

Adrese

  • GET /api/v1/crm-accounts Listă
  • GET /api/v1/crm-accounts/{id} O înregistrare
  • POST /api/v1/crm-accounts Creare
  • PATCH /api/v1/crm-accounts/{id} Modificare
  • DELETE /api/v1/crm-accounts/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Denumire (unică în companie).
registration_numberstring | null Număr de înregistrare la Registrul Comerțului.
vat_numberstring | null Cod de TVA.
industrystring | null Domeniu de activitate.
emailstring | null Adresa de email.
phonestring | null Telefon.
websitestring | null Site.
addressstring | null Adresă.
citystring | null Localitate.
countrystring | null Țara, cod ISO din două litere.
work_unit_idinteger | null Unitatea (magazin, hotel, birou) care îl deservește; gol pentru niciuna.
owner_idinteger | null Utilizatorul care se ocupă de el; cel care a creat cheia, dacă lipsește la creare.
tagsarray Etichete (litere mici, cel mult 20).
notestext | null Note.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Filtre

qstringDenumire care conține textul.
work_unit_idintegerDoar ale acestei unități.
owner_idintegerDoar ale acestui utilizator.
tagstringDoar cu această etichetă.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/crm-accounts

{
    "name": "Hotel Sigma SRL",
    "registration_number": "J12/345/2019",
    "vat_number": "RO12345678",
    "industry": "Hospitality",
    "email": "office@sigma.example",
    "phone": "0264 000 111",
    "city": "Cluj-Napoca",
    "country": "RO",
    "work_unit_id": 12,
    "owner_id": 17,
    "tags": [
        "corporate",
        "events"
    ]
}

Exemplu de răspuns

{
    "data": {
        "id": 31,
        "name": "Hotel Sigma SRL",
        "registration_number": "J12/345/2019",
        "vat_number": "RO12345678",
        "industry": "Hospitality",
        "email": "office@sigma.example",
        "phone": "0264 000 111",
        "website": null,
        "address": null,
        "city": "Cluj-Napoca",
        "country": "RO",
        "work_unit_id": 12,
        "owner_id": 17,
        "tags": [
            "corporate",
            "events"
        ],
        "notes": null,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Fluxuri de vânzare /crm-pipelines

Fluxurile prin care trec oportunitățile, cu etapele lor (configurate în aplicație). Fiecare companie are unul implicit. O etapă este în lucru (cu șansa ca o oportunitate de acolo să fie câștigată) sau închide oportunitatea ca fiind câștigată ori pierdută.

Drepturi: crm_pipelines:read

Adrese

  • GET /api/v1/crm-pipelines Listă
  • GET /api/v1/crm-pipelines/{id} O înregistrare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringdoar citire Denumire.
is_defaultbooleandoar citire Dacă oportunitățile noi ajung aici când nu se indică un flux.
sortintegerdoar citire Poziția în liste.
stagesarraydoar citire Etapele, în ordine: id, name, kind (open, won sau lost), probability (0–100) și sort.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Exemplu de răspuns

{
    "data": {
        "id": 1,
        "name": "Sales",
        "is_default": true,
        "sort": 1,
        "stages": [
            {
                "id": 3,
                "name": "Proposal sent",
                "kind": "open",
                "probability": 60,
                "sort": 20
            },
            {
                "id": 5,
                "name": "Won",
                "kind": "won",
                "probability": 100,
                "sort": 40
            }
        ],
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Oportunități /crm-deals

Vânzări, rezervări sau contracte în lucru într-un flux de vânzare. Fluxul și etapa se aleg la creare (prima etapă în lucru a fluxului implicit, dacă lipsesc); apoi o oportunitate își schimbă etapa doar prin move, win, lose și reopen. Starea urmează mereu etapa, iar closed_at se completează când este câștigată sau pierdută. O oportunitate câștigată face din contactul ei un client.

Drepturi: crm_deals:read, crm_deals:write

Adrese

  • GET /api/v1/crm-deals Listă
  • GET /api/v1/crm-deals/{id} O înregistrare
  • POST /api/v1/crm-deals Creare
  • PATCH /api/v1/crm-deals/{id} Modificare
  • DELETE /api/v1/crm-deals/{id} Ștergere
  • POST /api/v1/crm-deals/{id}/move Mută oportunitatea în altă etapă (a fluxului ei sau a altuia — oportunitatea se mută odată cu ea).
  • POST /api/v1/crm-deals/{id}/win Marchează oportunitatea câștigată (etapa câștigată a fluxului).
  • POST /api/v1/crm-deals/{id}/lose Marchează oportunitatea pierdută (etapa pierdută a fluxului), cu motivul.
  • POST /api/v1/crm-deals/{id}/reopen Readuce o oportunitate încheiată în ultima etapă în lucru a fluxului.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
titlestringobligatoriu Ce se vinde.
pipeline_idinteger Fluxul (vezi /crm-pipelines). Doar la creare.
stage_idinteger Etapa. Doar la creare; apoi prin acțiuni.
statusopen | won | lostdoar citire open, won sau lost — tipul etapei.
contact_idinteger | null Clientul (vezi /crm-contacts).
account_idinteger | null Organizația (vezi /crm-accounts).
valuenumber | null Cât valorează.
currencystring Moneda valorii (cod ISO); moneda CRM a companiei, dacă lipsește.
expected_close_ondate | null Când se așteaptă să se încheie.
closed_atdatetime | nulldoar citire Când a fost câștigată sau pierdută.
lost_reasonstring | nulldoar citire De ce a fost pierdută.
sourcewalk_in | website | phone | referral | campaign | event | partner | other | null De unde a venit (ca la clienți).
work_unit_idinteger | null Unitatea (magazin, hotel, birou) care îl deservește; gol pentru niciuna.
owner_idinteger | null Utilizatorul care se ocupă de el; cel care a creat cheia, dacă lipsește la creare.
notestext | null Note.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Filtre

statusopen | won | lostDoar în lucru, câștigate sau pierdute.
pipeline_idintegerDoar din acest flux.
stage_idintegerDoar din această etapă.
work_unit_idintegerDoar ale acestei unități.
owner_idintegerDoar ale acestui utilizator.
contact_idintegerDoar ale acestui client.
account_idintegerDoar ale acestei organizații.
closed_sincedateÎncheiate la această dată sau după.
closed_untildateÎncheiate la această dată sau înainte.

/api/v1/crm-deals/{id}/move: stage_id (integer) — Etapa în care se mută.

/api/v1/crm-deals/{id}/lose: lost_reason (string) — De ce a fost pierdută.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/crm-deals

{
    "title": "Corporate rates 2027",
    "pipeline_id": 1,
    "stage_id": 3,
    "contact_id": 120,
    "account_id": 31,
    "value": 12500.5,
    "currency": "RON",
    "expected_close_on": "2026-12-15",
    "source": "referral",
    "work_unit_id": 12,
    "owner_id": 17
}

Exemplu de răspuns

{
    "data": {
        "id": 77,
        "title": "Corporate rates 2027",
        "pipeline_id": 1,
        "stage_id": 3,
        "status": "open",
        "contact_id": 120,
        "account_id": 31,
        "value": 12500.5,
        "currency": "RON",
        "expected_close_on": "2026-12-15",
        "closed_at": "2026-05-01T08:00:00Z",
        "lost_reason": null,
        "source": "referral",
        "work_unit_id": 12,
        "owner_id": 17,
        "notes": null,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Activități cu clienții /crm-activities

Ce s-a făcut sau urmează să se facă cu clienții: apel, întâlnire, vizită, email, notă, sarcină și cumpărare. O sarcină așteaptă până este finalizată; orice altceva este făcut când se înregistrează (la done_at, dacă se trimite). O cumpărare are nevoie de sumă și face din contactul ei un client. O activitate a unei oportunități preia clientul, organizația și unitatea oportunității, dacă nu sunt trimise.

Drepturi: crm_activities:read, crm_activities:write

Adrese

  • GET /api/v1/crm-activities Listă
  • GET /api/v1/crm-activities/{id} O înregistrare
  • POST /api/v1/crm-activities Creare
  • PATCH /api/v1/crm-activities/{id} Modificare
  • DELETE /api/v1/crm-activities/{id} Ștergere
  • POST /api/v1/crm-activities/{id}/complete Marchează o sarcină ca făcută (acum).
  • POST /api/v1/crm-activities/{id}/reopen O marchează din nou ca nefăcută (nu și pentru cumpărări).

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
typecall | meeting | visit | email | task | note | purchaseobligatoriu call, meeting, visit, email, task, note sau purchase.
subjectstringobligatoriu Descriere scurtă.
bodytext | null Detalii.
contact_idinteger | null Clientul.
account_idinteger | null Organizația.
deal_idinteger | null Oportunitatea de care ține.
amountnumber | null Suma unei cumpărări, în moneda CRM a companiei (goală pentru celelalte tipuri).
due_atdatetime | null Termenul unei sarcini.
done_atdatetime | null Când a fost făcută; gol pentru o sarcină încă de făcut.
work_unit_idinteger | null Unitatea (magazin, hotel, birou) care îl deservește; gol pentru niciuna.
owner_idinteger | null Utilizatorul care se ocupă de el; cel care a creat cheia, dacă lipsește la creare.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Filtre

typecall | meeting | visit | email | task | note | purchaseDoar de acest tip.
work_unit_idintegerDoar ale acestei unități.
owner_idintegerDoar ale acestui utilizator.
contact_idintegerDoar ale acestui client.
deal_idintegerDoar ale acestei oportunități.
donebooleantrue: doar cele făcute; false: doar cele de făcut.
due_beforedatetimeCu termen înainte de acest moment.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/crm-activities

{
    "type": "purchase",
    "subject": "Receipt 1243",
    "contact_id": 120,
    "amount": 240,
    "due_at": "2026-11-03T09:00:00Z",
    "done_at": "2026-11-02T15:20:00Z",
    "work_unit_id": 12,
    "owner_id": 17
}

Exemplu de răspuns

{
    "data": {
        "id": 530,
        "type": "purchase",
        "subject": "Receipt 1243",
        "body": null,
        "contact_id": 120,
        "account_id": 1,
        "deal_id": 1,
        "amount": 240,
        "due_at": "2026-11-03T09:00:00Z",
        "done_at": "2026-11-02T15:20:00Z",
        "work_unit_id": 12,
        "owner_id": 17,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Păreri ale clienților /crm-feedback

Ce au spus clienții: păreri (o notă de la 0 la 10 — cât de probabil ar recomanda firma — și/sau un comentariu) și reclamații. O părere are nevoie de o notă sau de un comentariu. O reclamație rămâne deschisă până este rezolvată, cu ce s-a făcut; poate fi redeschisă. Tipul se stabilește la creare.

Drepturi: crm_feedback:read, crm_feedback:write

Adrese

  • GET /api/v1/crm-feedback Listă
  • GET /api/v1/crm-feedback/{id} O înregistrare
  • POST /api/v1/crm-feedback Creare
  • PATCH /api/v1/crm-feedback/{id} Modificare
  • DELETE /api/v1/crm-feedback/{id} Ștergere
  • POST /api/v1/crm-feedback/{id}/resolve Rezolvă o reclamație, spunând ce s-a făcut.
  • POST /api/v1/crm-feedback/{id}/reopen Redeschide o reclamație rezolvată.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
kindfeedback | complaintobligatoriu feedback (părere) sau complaint (reclamație). Doar la creare.
contact_idinteger | null Clientul.
account_idinteger | null Organizația.
scoreinteger | null De la 0 la 10.
commenttext | null Ce a spus.
channelin_person | phone | email | website | review_site | survey | other | null Cum a venit: in_person, phone, email, website, review_site, survey sau other.
received_ondate Când a fost primită (azi, dacă lipsește).
statusopen | resolveddoar citire open (o reclamație încă nerezolvată) sau resolved.
resolved_atdatetime | nulldoar citire Când a fost rezolvată reclamația.
resolutiontext | nulldoar citire Ce s-a făcut.
work_unit_idinteger | null Unitatea (magazin, hotel, birou) care îl deservește; gol pentru niciuna.
owner_idinteger | null Utilizatorul care se ocupă de el; cel care a creat cheia, dacă lipsește la creare.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Filtre

kindfeedback | complaintDoar păreri sau doar reclamații.
statusopen | resolvedDoar deschise sau doar rezolvate.
work_unit_idintegerDoar ale acestei unități.
contact_idintegerDoar ale acestui client.
received_sincedatePrimite la această dată sau după.

/api/v1/crm-feedback/{id}/resolve: resolution (text) — Ce s-a făcut.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/crm-feedback

{
    "kind": "feedback",
    "contact_id": 120,
    "score": 9,
    "comment": "Quick and friendly service.",
    "channel": "in_person",
    "received_on": "2026-11-02",
    "work_unit_id": 12,
    "owner_id": 17
}

Exemplu de răspuns

{
    "data": {
        "id": 64,
        "kind": "feedback",
        "contact_id": 120,
        "account_id": 1,
        "score": 9,
        "comment": "Quick and friendly service.",
        "channel": "in_person",
        "received_on": "2026-11-02",
        "status": "resolved",
        "resolved_at": "2026-05-01T08:00:00Z",
        "resolution": null,
        "work_unit_id": 12,
        "owner_id": 17,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Spații și raft

Parteneri /merch-partners

Producătorii și brandurile ale căror campanii intră în spațiile de expunere și pe rafturile companiei: o singură listă pentru ambele module. Numele este unic în companie. Scrierea cere dreptul „Gestionează partenerii” pentru cel care a creat cheia.

Drepturi: merch_partners:read, merch_partners:write

Adrese

  • GET /api/v1/merch-partners Listă
  • GET /api/v1/merch-partners/{id} O înregistrare
  • POST /api/v1/merch-partners Creare
  • PATCH /api/v1/merch-partners/{id} Modificare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Numele partenerului (unic în companie).
codestring | null Cod intern.
contact_namestring | null Persoana de contact.
contact_emailstring | null Emailul persoanei de contact.
contact_phonestring | null Telefonul persoanei de contact.
notestext | null Note.
crm_account_idinteger | null Organizația client din CRM căreia îi corespunde (vezi /crm-accounts), dacă există.
is_activeboolean Dacă poate primi campanii noi.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Filtre

qstringNume care conține textul.
is_activebooleantrue: doar activii; false: doar inactivii.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/merch-partners

{
    "name": "Dermalab",
    "code": "DLB",
    "contact_name": "Ana Ionescu",
    "contact_email": "ana@dermalab.example",
    "contact_phone": "0722 000 111",
    "crm_account_id": 31,
    "is_active": true
}

Exemplu de răspuns

{
    "data": {
        "id": 3,
        "name": "Dermalab",
        "code": "DLB",
        "contact_name": "Ana Ionescu",
        "contact_email": "ana@dermalab.example",
        "contact_phone": "0722 000 111",
        "notes": null,
        "crm_account_id": 31,
        "is_active": true,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Tipuri de zone /space-zone-types

Spații și expunere: tipurile de zone pe care compania le are în mai multe locații (o ramă click, un suport pe counter, un totem), cu dimensiunile și capacitatea lor obișnuite. Prețul lunar îl scrie doar cine vede sumele.

Drepturi: space_zone_types:read, space_zone_types:write

Adrese

  • GET /api/v1/space-zone-types Listă
  • GET /api/v1/space-zone-types/{id} O înregistrare
  • POST /api/v1/space-zone-types Creare
  • PATCH /api/v1/space-zone-types/{id} Modificare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Denumire.
descriptiontext | null Descriere.
width_cmnumber | null Lățime, în centimetri.
height_cmnumber | null Înălțime, în centimetri.
depth_cmnumber | null Adâncime, în centimetri.
facesinteger Câte fețe are (1 sau 2: A, B).
capacityinteger Câte materiale încap pe o față.
capacity_labelstring | null Ce numără capacitatea (de exemplu „afișe A2”).
is_displayboolean Dacă este spațiu de expunere (poate găzdui campanii).
monthly_pricenumber | null Tariful pe lună pentru o unitate din capacitate (sugerează valoarea campaniilor).
is_activeboolean Dacă se mai folosește.
sortinteger Ordinea în liste.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Filtre

is_activebooleantrue: doar cele folosite; false: doar cele scoase din uz.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/space-zone-types

{
    "name": "Ramă click A2",
    "width_cm": 50,
    "height_cm": 70,
    "faces": 2,
    "capacity": 2,
    "capacity_label": "afișe A2",
    "is_display": true,
    "monthly_price": 150,
    "is_active": true,
    "sort": 10
}

Exemplu de răspuns

{
    "data": {
        "id": 2,
        "name": "Ramă click A2",
        "description": null,
        "width_cm": 50,
        "height_cm": 70,
        "depth_cm": 12.5,
        "faces": 2,
        "capacity": 2,
        "capacity_label": "afișe A2",
        "is_display": true,
        "monthly_price": 150,
        "is_active": true,
        "sort": 10,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Zone din locații /space-zones

Spații și expunere: zonele fiecărei locații (unde sunt, cât de mari, cât încape pe fiecare față), doar în locațiile pe care cel care a creat cheia le amenajează. O zonă rămâne în locația ei. O zonă nouă de un anumit tip preia dimensiunile tipului pentru ce lipsește. Mai puține fețe sau mai puțin loc decât au nevoie campaniile ei în desfășurare sunt refuzate; o zonă cu campanii nu se poate șterge.

Drepturi: space_zones:read, space_zones:write

Adrese

  • GET /api/v1/space-zones Listă
  • GET /api/v1/space-zones/{id} O înregistrare
  • POST /api/v1/space-zones Creare
  • PATCH /api/v1/space-zones/{id} Modificare
  • DELETE /api/v1/space-zones/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
work_unit_idintegerobligatoriu Locația (unitatea) — doar la creare.
zone_type_idinteger | null Tipul zonei (vezi /space-zone-types), dacă are.
namestringobligatoriu Denumire (de exemplu „Totem dreapta ușii”).
descriptiontext | null Descriere.
width_cmnumber | null Lățime, în centimetri.
height_cmnumber | null Înălțime, în centimetri.
depth_cmnumber | null Adâncime, în centimetri.
area_m2number | null Suprafață, în metri pătrați.
facesinteger Câte fețe are (1 sau 2).
capacityinteger Câte materiale încap pe o față.
capacity_labelstring | null Ce numără capacitatea.
is_displayboolean Dacă este spațiu de expunere.
monthly_pricenumber | null Tariful pe lună (doar cine vede sumele îl scrie).
statusactive | unavailable active sau unavailable (temporar indisponibilă).
pin_xnumber | nulldoar citire Poziția pe schița locației, în procente de la stânga (se așază din aplicație).
pin_ynumber | nulldoar citire Poziția pe schița locației, în procente de sus.
sortinteger Ordinea în locație.
created_atdatetimedoar citire Creată.
updated_atdatetimedoar citire Modificată ultima dată.

Filtre

work_unit_idintegerDoar ale acestei locații.
zone_type_idintegerDoar de acest tip.
statusactive | unavailableDoar cu această stare.
is_displaybooleantrue: doar spațiile de expunere.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/space-zones

{
    "work_unit_id": 12,
    "zone_type_id": 2,
    "name": "Ramă click intrare",
    "width_cm": 50,
    "height_cm": 70,
    "faces": 2,
    "capacity": 2,
    "capacity_label": "afișe A2",
    "is_display": true,
    "monthly_price": 150,
    "status": "active",
    "sort": 100
}

Exemplu de răspuns

{
    "data": {
        "id": 41,
        "work_unit_id": 12,
        "zone_type_id": 2,
        "name": "Ramă click intrare",
        "description": null,
        "width_cm": 50,
        "height_cm": 70,
        "depth_cm": 12.5,
        "area_m2": 12.5,
        "faces": 2,
        "capacity": 2,
        "capacity_label": "afișe A2",
        "is_display": true,
        "monthly_price": 150,
        "status": "active",
        "pin_x": 42.5,
        "pin_y": 88,
        "sort": 100,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Mobilier și tarife /shelf-fixture-types

Spațiu la raft: tipurile de mobilier (gondolă, capăt de raft, frigider) cu tariful — pe față de produs sau pe metru de raft, pe lună. Tarifele le scrie doar cine are dreptul la prețurile de la raft.

Drepturi: shelf_fixture_types:read, shelf_fixture_types:write

Adrese

  • GET /api/v1/shelf-fixture-types Listă
  • GET /api/v1/shelf-fixture-types/{id} O înregistrare
  • POST /api/v1/shelf-fixture-types Creare
  • PATCH /api/v1/shelf-fixture-types/{id} Modificare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Denumire.
face_pricenumber | null Tarif pe față de produs, pe lună.
meter_pricenumber | null Tarif pe metru de raft, pe lună.
is_activeboolean Dacă se mai folosește.
sortinteger Ordinea în liste.
created_atdatetimedoar citire Creat.
updated_atdatetimedoar citire Modificat ultima dată.

Filtre

is_activebooleantrue: doar cele folosite.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/shelf-fixture-types

{
    "name": "Gondolă",
    "face_price": 25,
    "is_active": true,
    "sort": 10
}

Exemplu de răspuns

{
    "data": {
        "id": 1,
        "name": "Gondolă",
        "face_price": 25,
        "meter_price": 12.5,
        "is_active": true,
        "sort": 10,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Planograme /shelf-planograms

Spațiu la raft: planogramele descrise o dată — mobilierul, dimensiunile, rafturile de sus în jos, cu ce încape pe fiecare (fețe sau centimetri) și coeficientul lui de preț. Trimiterea câmpului shelves înlocuiește lista de rafturi; un raft pe care sunt campanii nu poate fi scos. Numele este unic.

Drepturi: shelf_planograms:read, shelf_planograms:write

Adrese

  • GET /api/v1/shelf-planograms Listă
  • GET /api/v1/shelf-planograms/{id} O înregistrare
  • POST /api/v1/shelf-planograms Creare
  • PATCH /api/v1/shelf-planograms/{id} Modificare

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
namestringobligatoriu Denumire (unică).
codestring | null Cod intern.
fixture_type_idinteger | null Tipul de mobilier (vezi /shelf-fixture-types).
categorystring | null Categoria de produse.
width_cmnumber | null Lățime, în centimetri.
height_cmnumber | null Înălțime, în centimetri.
depth_cmnumber | null Adâncime, în centimetri.
capacity_unitfaces | cm faces: capacitatea rafturilor e în fețe de produs; cm: în centimetri.
instructionstext | null Instrucțiunile de aranjare (text formatat, curățat).
is_activeboolean Dacă se mai amplasează.
shelvesarrayobligatoriu Rafturile, de sus în jos: [{label, capacity, price_factor}] (position se dă în ordinea listei; price_factor îl scrie doar cine vede prețurile).
created_atdatetimedoar citire Creată.
updated_atdatetimedoar citire Modificată ultima dată.

Filtre

fixture_type_idintegerDoar cu acest mobilier.
is_activebooleantrue: doar cele active.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/shelf-planograms

{
    "name": "Capăt de raft vitamine",
    "code": "CR-VIT",
    "fixture_type_id": 2,
    "category": "Suplimente",
    "width_cm": 100,
    "height_cm": 180,
    "capacity_unit": "faces",
    "is_active": true,
    "shelves": [
        {
            "position": 1,
            "label": null,
            "capacity": 8,
            "price_factor": 1.2
        },
        {
            "position": 2,
            "label": "La nivelul ochilor",
            "capacity": 8,
            "price_factor": 1.5
        }
    ]
}

Exemplu de răspuns

{
    "data": {
        "id": 4,
        "name": "Capăt de raft vitamine",
        "code": "CR-VIT",
        "fixture_type_id": 2,
        "category": "Suplimente",
        "width_cm": 100,
        "height_cm": 180,
        "depth_cm": 12.5,
        "capacity_unit": "faces",
        "instructions": null,
        "is_active": true,
        "shelves": [
            {
                "position": 1,
                "label": null,
                "capacity": 8,
                "price_factor": 1.2
            },
            {
                "position": 2,
                "label": "La nivelul ochilor",
                "capacity": 8,
                "price_factor": 1.5
            }
        ],
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Planograme amplasate /shelf-placements

Spațiu la raft: o planogramă amplasată într-o locație, cu eticheta, nota și costurile ei, doar în locațiile pe care cel care a creat cheia le amenajează. Ștergerea o scoate din locație: rămâne pentru istoricul campaniilor ei sau dispare dacă nu a avut niciuna; niciodată cât timp rulează o campanie pe ea. Costurile le scrie doar cine vede prețurile.

Drepturi: shelf_placements:read, shelf_placements:write

Adrese

  • GET /api/v1/shelf-placements Listă
  • GET /api/v1/shelf-placements/{id} O înregistrare
  • POST /api/v1/shelf-placements Creare
  • PATCH /api/v1/shelf-placements/{id} Modificare
  • DELETE /api/v1/shelf-placements/{id} Ștergere

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
planogram_idintegerobligatoriu Planograma — doar la creare.
work_unit_idintegerobligatoriu Locația — doar la creare.
labelstring | null O etichetă care o deosebește de altă amplasare a aceleiași planograme în locație.
statusactive | removeddoar citire active sau removed (scoasă).
installed_ondate | null Data amplasării.
removed_ondate | nulldoar citire Data scoaterii.
local_notetext | null Ce diferă aici față de planograma obișnuită.
setup_costnumber | null Costul amenajării.
monthly_costnumber | null Costul lunar aici (întreținere, amortizare).
created_atdatetimedoar citire Creată.
updated_atdatetimedoar citire Modificată ultima dată.

Filtre

work_unit_idintegerDoar din această locație.
planogram_idintegerDoar această planogramă.
statusactive | removedDoar cu această stare.

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/shelf-placements

{
    "planogram_id": 4,
    "work_unit_id": 12,
    "label": "lângă casă",
    "installed_on": "2026-02-18",
    "monthly_cost": 25
}

Exemplu de răspuns

{
    "data": {
        "id": 88,
        "planogram_id": 4,
        "work_unit_id": 12,
        "label": "lângă casă",
        "status": "active",
        "installed_on": "2026-02-18",
        "removed_on": "2026-05-01",
        "local_note": null,
        "setup_cost": 12.5,
        "monthly_cost": 25,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Campanii /merch-campaigns

Campaniile ambelor module (module: spaces — zone de expunere; shelf — rafturi din planograme), scrise ca cel care a creat cheia. O campanie începe ca ciornă: locațiile (units) și regulile care numesc locurile din ele (rules) devin locurile ei. Acțiunea launch verifică locul și o trimite fiecărei locații, iar cancel o oprește. O campanie lansată își păstrează datele și locurile; se mai schimbă doar textul, partenerul, sumele și cererea de fotografii. Valoarea și costul le scrie doar cine vede sumele.

Drepturi: merch_campaigns:read, merch_campaigns:write

Adrese

  • GET /api/v1/merch-campaigns Listă
  • GET /api/v1/merch-campaigns/{id} O înregistrare
  • POST /api/v1/merch-campaigns Creare
  • PATCH /api/v1/merch-campaigns/{id} Modificare
  • DELETE /api/v1/merch-campaigns/{id} Ștergere
  • POST /api/v1/merch-campaigns/{id}/launch Lansează ciorna: verifică locul și o trimite fiecărei locații.
  • POST /api/v1/merch-campaigns/{id}/cancel Anulează o campanie lansată: nu mai pornește unde nu a fost pusă, iar unde este pusă trebuie scoasă.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
modulespaces | shelfobligatoriu spaces sau shelf — doar la creare.
titlestringobligatoriu Titlul campaniei.
partner_idinteger | null Partenerul care plătește (vezi /merch-partners); gol: campanie proprie.
instructionstext | null Instrucțiunile de implementare (text formatat, curățat).
starts_ondateobligatoriu Prima zi.
ends_ondateobligatoriu Ultima zi.
implement_daysinteger Câte zile are locația să o pună, de la început.
remove_daysinteger Câte zile are locația să o scoată, după sfârșit.
proof_requiredboolean Dacă locația trebuie să trimită fotografii la confirmare.
valuenumber | null Cât plătește partenerul pentru toată campania, fără TVA.
costnumber | null Cât costă compania (materiale, montaj), fără TVA.
currencystringdoar citire Moneda sumelor (din setările modulului).
statusdraft | launched | cancelleddoar citire draft (ciornă), launched (lansată) sau cancelled (anulată).
phasedraft | scheduled | running | ended | cancelleddoar citire draft, scheduled (urmează), running (în desfășurare), ended sau cancelled.
unitsarray Locațiile (id-uri de unități), împreună cu rules.
rulesarray Regulile care numesc locurile, împreună cu units. spaces: [{zone_type_id sau zone_id, face (A/B), quantity}]; shelf: [{planogram_id sau placement_id, position (raftul, de sus), quantity, products}].
targetsarraydoar citire Locurile rezultate: pe locație, zona și fața sau amplasarea și raftul, cu cantitatea.
launched_atdatetime | nulldoar citire Când a fost lansată.
cancelled_atdatetime | nulldoar citire Când a fost anulată.
created_atdatetimedoar citire Creată.
updated_atdatetimedoar citire Modificată ultima dată.

Filtre

modulespaces | shelfDoar acest modul.
statusdraft | launched | cancelledDoar cu această stare.
partner_idintegerDoar ale acestui partener.
active_ondateDoar cele care țin în această zi (YYYY-MM-DD).

Exemplu de cerere

POST https://compania-mea.harmoniq.ro/api/v1/merch-campaigns

{
    "module": "shelf",
    "title": "Dermalab – raftul de la ochi",
    "partner_id": 3,
    "starts_on": "2026-11-02",
    "ends_on": "2026-11-30",
    "implement_days": 3,
    "remove_days": 2,
    "proof_required": true,
    "value": 9600,
    "cost": 0,
    "units": [
        12,
        13
    ],
    "rules": [
        {
            "planogram_id": 4,
            "position": 2,
            "quantity": 6,
            "products": "Vitamina D3"
        }
    ]
}

Exemplu de răspuns

{
    "data": {
        "id": 15,
        "module": "shelf",
        "title": "Dermalab – raftul de la ochi",
        "partner_id": 3,
        "instructions": null,
        "starts_on": "2026-11-02",
        "ends_on": "2026-11-30",
        "implement_days": 3,
        "remove_days": 2,
        "proof_required": true,
        "value": 9600,
        "cost": 0,
        "currency": "RON",
        "status": "draft",
        "phase": "scheduled",
        "units": [
            12,
            13
        ],
        "rules": [
            {
                "planogram_id": 4,
                "position": 2,
                "quantity": 6,
                "products": "Vitamina D3"
            }
        ],
        "targets": [
            {
                "work_unit_id": 12,
                "placement_id": 88,
                "shelf_id": 210,
                "quantity": 6,
                "products": "Vitamina D3"
            }
        ],
        "launched_at": "2026-05-01T08:00:00Z",
        "cancelled_at": "2026-05-01T08:00:00Z",
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Implementarea în locații /merch-executions

O campanie lansată, într-o locație: cine o pune și până când, dacă este pusă, refuzată (cu motivul), în curs de scoatere sau gata. Acțiunile se fac ca cel care a creat cheia (cine implementează acolo sau, pentru reopen, cine conduce campania). Fotografiile se trimit ca imagini în base64; o campanie care le cere nu se poate confirma fără ele.

Drepturi: merch_executions:read, merch_executions:write

Adrese

  • GET /api/v1/merch-executions Listă
  • GET /api/v1/merch-executions/{id} O înregistrare
  • POST /api/v1/merch-executions/{id}/confirm Confirmă că este pusă (cu fotografii, dacă se cer).
  • POST /api/v1/merch-executions/{id}/refuse Spune că nu se poate pune, cu motivul.
  • POST /api/v1/merch-executions/{id}/reopen Cere din nou unei locații care a refuzat (cine conduce campania).
  • POST /api/v1/merch-executions/{id}/removed Confirmă că materialele au fost scoase.

Câmpuri

NumeTipDescriere
idintegerdoar citire Identificator.
campaign_idintegerdoar citire Campania (vezi /merch-campaigns).
modulespaces | shelfdoar citire spaces sau shelf (al campaniei).
work_unit_idintegerdoar citire Locația.
implementer_idinteger | nulldoar citire Cine o implementează anume; gol: managerii locației.
statuswaiting | pending | done | refused | removing | removed | cancelleddoar citire waiting (încă nu a început), pending (de pus), done (pusă), refused (refuzată), removing (de scos), removed (scoasă) sau cancelled.
latebooleandoar citire Dacă a fost pusă după termen sau nu e pusă și termenul a trecut.
due_ondate | nulldoar citire Până când trebuie pusă.
done_atdatetime | nulldoar citire Când a fost confirmată.
done_byinteger | nulldoar citire Cine a confirmat.
notetext | nulldoar citire Observațiile de la confirmare.
refused_atdatetime | nulldoar citire Când a fost refuzată.
refused_byinteger | nulldoar citire Cine a refuzat.
refusal_reasontext | nulldoar citire De ce nu se poate.
remove_due_ondate | nulldoar citire Până când trebuie scoasă.
removed_atdatetime | nulldoar citire Când s-a confirmat scoaterea.
removed_byinteger | nulldoar citire Cine a confirmat scoaterea.
created_atdatetimedoar citire Creată.
updated_atdatetimedoar citire Modificată ultima dată.

Filtre

campaign_idintegerDoar ale acestei campanii.
work_unit_idintegerDoar din această locație.
statuswaiting | pending | done | refused | removing | removed | cancelledDoar cu această stare.
modulespaces | shelfDoar acest modul.
latebooleantrue: doar cele întârziate.

/api/v1/merch-executions/{id}/confirm: photos (array) — Fotografii: [{name, content_base64}], JPEG/PNG/WebP, cel mult 10 MB fiecare, cel mult 10.; note (text) — Observații.

/api/v1/merch-executions/{id}/refuse: reason (text) — Motivul.

/api/v1/merch-executions/{id}/removed: photos (array) — Fotografii după scoatere (opțional): [{name, content_base64}].

Exemplu de răspuns

{
    "data": {
        "id": 501,
        "campaign_id": 15,
        "module": "shelf",
        "work_unit_id": 12,
        "implementer_id": 17,
        "status": "pending",
        "late": false,
        "due_on": "2026-11-04",
        "done_at": "2026-05-01T08:00:00Z",
        "done_by": 1,
        "note": null,
        "refused_at": "2026-05-01T08:00:00Z",
        "refused_by": 1,
        "refusal_reason": null,
        "remove_due_on": "2026-05-01",
        "removed_at": "2026-05-01T08:00:00Z",
        "removed_by": 1,
        "created_at": "2026-05-01T08:00:00Z",
        "updated_at": "2026-05-01T08:00:00Z"
    }
}

Vedeți ce poate face Harmoniq pentru echipa dumneavoastră

Testați gratuit toate modulele sau explorați o companie demo. Nu este nevoie de card.

sau vă pregătim o companie de probă cu structura dumneavoastră