Contacte
Endpoint-uri pentru gestionarea contactelor (angajaților) în platforma ssm.ro: preluare, creare și modificare.
Endpoint-urile de contacte permit sincronizarea angajaților din sistemul tău HR cu platforma ssm.ro. Un contact reprezintă un angajat înrolat în organizația ta.
Preluare contact
GET /v1/contacts?organizatie={organizatie}&marca={marca}Returnează datele unui contact pe baza mărcii (cheia unică de identificare) și a numelui organizației. Marca se transmite ca parametru de query, deci sunt acceptate și mărcile care conțin caractere URL-unsafe, atâta timp cât valoarea este codificată cu encodeURIComponent().
Exemplu request:
GET /v1/contacts?organizatie=demo-organization&marca=M00212Parametri
| Parametru | În | Tip | Obligatoriu | Descriere |
|---|---|---|---|---|
organizatie | query | string | Da | Numele organizației |
marca | query | string | Da | Marca — cheia unică de identificare a angajatului |
Răspunsuri
| Cod | Descriere |
|---|---|
200 OK | Obiect Employee |
404 Not Found | { "error": "Contactul nu a fost gasit" } — marca nu există |
422 Unprocessable Entity | { "error": "Marca este obligatorie" } — parametrul marca lipsește sau este gol |
500 Server Error | Eroare internă server |
Ruta veche GET /v1/contacts/{id} — depreciată
Depreciat din septembrie 2026
Ruta care primește marca în calea URL (GET /v1/contacts/{id}) este depreciată,
pentru că mărcile care conțin caractere URL-unsafe nu pot fi transmise corect printr-un
segment de cale. Folosiți GET /v1/contacts?marca=, cu marca codificată prin
encodeURIComponent(). Ruta veche rămâne funcțională, dar nu mai este întreținută.
Creare contact nou
POST /v1/contactsCreează un contact nou în organizație. Dacă marca există deja, operațiunea va eșua.
Request body
Content-Type: application/json — obiect Employee. Câmpurile obligatorii sunt organizatie, marca, nume, departament, post și cor — vezi Câmpuri obligatorii.
Exemplu:
{
"nume": "Ion",
"prenume": "Popescu",
"email": "ion.popescu@exemplu.ro",
"departament": "Finanțe",
"codDepartament": "D163",
"cor": "Referent bancar",
"post": "Tesa",
"marca": "M00212",
"marcaSuperior": "M00132",
"adresa": "Str. Soarelui nr. 2",
"localitate": "Brașov",
"judet": "Brașov",
"dataNasterii": "1981-08-24",
"locatieFizica": "Office 101",
"status": "activ",
"organizatie": "demo-organization",
"echipaPSI": "Nu",
"telefon": "+40722333444",
"cnp": "1800101221144",
"limba": "ro",
"calificare": "Inginer",
"cetatenie": "Romana",
"nationalitate": "Romania",
"dataIncepereActivitate": "2020-01-15"
}Răspunsuri
| Cod | Descriere |
|---|---|
200 OK | Contactul a fost creat — returnează obiectul Employee |
404 Not Found | Organizația nu a fost găsită |
422 Unprocessable Entity | Date invalide — răspuns JSON cu detalii eroare |
500 Server Error | Eroare internă server |
Modificare contact existent
PATCH /v1/contacts/updateActualizează datele unui contact existent, identificat prin câmpul marca. Sunt actualizate doar câmpurile trimise în body cu o valoare nevidă — un câmp absent, null sau "" este ignorat.
Valorile goale nu șterg datele existente
Un câmp trimis cu null sau "" — la fel ca unul absent din body — este ignorat: valoarea
existentă în platformă rămâne neschimbată. Pentru a anula o informație trebuie să trimiți un șir
de caractere nevid — vezi Ștergerea unei informații mai jos.
Request body
Content-Type: application/json — obiect Employee complet. Câmpurile obligatorii (organizatie, marca, nume, departament, post, cor) trebuie trimise și la PATCH, chiar dacă valoarea lor nu se modifică; organizatie și marca identifică contactul.
Exemplu:
{
"nume": "Ion",
"prenume": "Popescu",
"email": "ion.popescu@exemplu.ro",
"departament": "Finanțe",
"codDepartament": "D163",
"cor": "Referent bancar",
"post": "Tesa",
"marca": "M00212",
"marcaSuperior": "M00132",
"marcaSuperior2": "M0081",
"marcaInlocuitor": "M00301",
"adresa": "Str. Soarelui nr. 2",
"localitate": "Brașov",
"judet": "Brașov",
"dataNasterii": "1981-08-24",
"locatieFizica": "Office 101",
"status": "activ",
"organizatie": "demo-organization",
"echipaPSI": "Nu",
"telefon": "+40722333444",
"cnp": "1800101221144",
"limba": "ro",
"calificare": "Inginer",
"cetatenie": "Romana",
"nationalitate": "Romania",
"dataIncepereActivitate": "2020-01-15"
}Răspunsuri
| Cod | Descriere |
|---|---|
200 OK | Contactul a fost actualizat — returnează obiectul Employee |
204 No Content | Nicio modificare efectuată — datele trimise sunt identice cu cele existente |
404 Not Found | Contactul nu a fost găsit |
422 Unprocessable Entity | Date invalide — răspuns JSON cu detalii eroare |
500 Server Error | Eroare internă server |
Ștergerea unei informații
Pentru că valorile goale sunt ignorate, un câmp nu poate fi golit prin API. Pentru a anula o
informație existentă, trimite în locul ei orice șir de caractere nevid (ex: "-", "n/a",
"fara date"). Valoarea este salvată ca atare și o înlocuiește pe cea anterioară — platforma nu
tratează aceste valori în mod special.
Nu funcționează — câmpurile sunt ignorate, valorile existente rămân neschimbate:
{
"organizatie": "demo-organization",
"marca": "M00212",
"adresa": null,
"locatieFizica": "",
"calificare": null
}Funcționează — valorile existente sunt înlocuite:
{
"organizatie": "demo-organization",
"marca": "M00212",
"adresa": "-",
"locatieFizica": "-",
"calificare": "n/a"
}Doar pentru câmpurile text libere
Placeholder-ul funcționează pentru câmpurile text libere (adresa, localitate, judet,
dataNasterii, locatieFizica, calificare, cetatenie, nationalitate, cor, departament,
post). Câmpurile cu validare proprie — cnp, telefon, dataIncepereActivitate,
limba, status, echipaPSI — acceptă doar valorile documentate: un placeholder este fie
respins cu 422, fie ignorat, conform regulilor din tabelul de validări de mai jos.
Comportament câmpuri opționale
Sunt obligatorii la orice scriere (POST și PATCH) organizatie, marca, nume, departament, post și cor — lipsa oricăruia întoarce 422 / 400 (vezi Câmpuri obligatorii). Toate celelalte câmpuri sunt opționale. La PATCH, doar câmpurile trimise în body sunt actualizate; un câmp absent sau gol ("", null) este ignorat — valoarea existentă rămâne neschimbată, deci API-ul nu poate goli un câmp (vezi Ștergerea unei informații). În particular, un PATCH fără status nu suspendă angajatul, iar un POST fără status creează angajatul cu status activ.
Departamentul este identificat prin codDepartament. Dacă trimiți același codDepartament cu o valoare departament diferită, denumirea departamentului este actualizată (redenumire) — nu se creează un departament nou. Astfel, o redenumire în HR se propagă în platformă atâta timp cât codul rămâne același.
Validări câmpuri noi (422 Unprocessable Entity)
| Situație | Cod | Explicație |
|---|---|---|
cnp deja folosit de alt angajat | 422 | CNP-ul trebuie să fie unic în organizație |
cnp cu format greșit | 422 | CNP invalid (format valid: 13 cifre) |
limba în afara valorilor acceptate | 422 | Sunt permise doar ro, en |
dataIncepereActivitate cu dată invalidă | ignorat | O dată neparsabilă este tratată ca goală (fără eroare) |
telefon prea scurt (sub 9 cifre) | ignorat | Numărul este normalizat automat; valorile prea scurte sunt ignorate (fără eroare) |
Angajați cu mai multe contracte
În platformă, angajatul este identificat prin marca, iar contul de acces este identificat prin
email. Emailul trebuie să fie unic în cadrul unei organizații.
Prin urmare, o persoană cu mai multe contracte în aceeași organizație — deci cu mai multe valori
marca — are nevoie de un contact separat pentru fiecare contract, iar aceste contacte nu pot
folosi același cont.
Același email nu poate fi folosit de două ori în aceeași organizație
Dacă trimiți două contacte cu marca diferită dar cu același email în aceeași organizație,
al doilea contact nu poate fi creat — adresa este deja folosită. Fiecare marca din organizație
are nevoie de o adresă de email distinctă.
Sunt două soluții recomandate.
Soluția 1 — alias-uri de email (aceeași căsuță, adrese diferite)
Fiecare contract primește o adresă distinctă, dar toate adresele livrează în aceeași căsuță
poștală a angajatului. Cel mai simplu este sub-adresarea cu +, suportată de Google Workspace,
Microsoft 365 și de majoritatea serverelor de mail:
| Contract | marca | email |
|---|---|---|
| Contract principal | M00212 | ion.popescu@exemplu.ro |
| Al doilea contract | M00478 | ion.popescu+M00478@exemplu.ro |
{
"organizatie": "demo-organization",
"marca": "M00478",
"nume": "Ion",
"prenume": "Popescu",
"email": "ion.popescu+M00478@exemplu.ro",
"departament": "Producție",
"codDepartament": "D204",
"status": "activ"
}Dacă serverul de mail nu suportă sub-adresarea, se pot folosi alias-uri clasice, definite în serverul
de mail (ex: ion.popescu.2@exemplu.ro, redirecționat către aceeași căsuță).
Consecințe:
- angajatul primește notificările pentru ambele contracte în aceeași căsuță poștală;
- autentificarea se face separat, cu adresa fiecărui cont — sunt conturi distincte, cu documente și semnături separate;
- ambele contracte rămân în aceeași organizație și în aceeași structură organizatorică.
Soluția 2 — organizații diferite (un singur cont)
Dacă cele două contracte țin oricum de entități diferite, ele pot fi separate în organizații diferite din același cont comercial. Emailul trebuie să fie unic doar în interiorul unei organizații, deci aceeași adresă poate fi folosită în fiecare organizație, iar angajatul accesează ambele contracte cu un singur cont.
| Organizație | marca | email |
|---|---|---|
demo-organization | M00212 | ion.popescu@exemplu.ro |
demo-productie | M00478 | ion.popescu@exemplu.ro |
La nivel de API, fiecare contact se trimite către organizația lui, prin câmpul organizatie:
{
"organizatie": "demo-productie",
"marca": "M00478",
"nume": "Ion",
"prenume": "Popescu",
"email": "ion.popescu@exemplu.ro",
"status": "activ"
}Consecințe:
- angajatul folosește o singură adresă și un singur cont, comutând între organizații;
- organizațiile sunt complet izolate — structura organizatorică, documentele și rapoartele sunt separate (vezi Glosar);
- soluția are sens doar dacă separarea pe organizații este justificată și operațional (entități juridice, puncte de lucru sau divizii gestionate separat).
Cum alegi
| Situație | Soluție recomandată |
|---|---|
| Ambele contracte aparțin aceleiași entități | Alias-uri de email |
| Contractele aparțin unor entități sau divizii gestionate separat | Organizații diferite |
| Angajatul trebuie să aibă un singur cont de autentificare | Organizații diferite |
| Ambele contracte trebuie să apară în aceeași structură organizatorică | Alias-uri de email |
Sincronizare din HR
Dacă platforma ta HR emite câte o înregistrare per contract, sincronizarea trebuie să genereze
adresa distinctă (alias) sau să direcționeze înregistrarea către organizația corectă înainte de
apelul API — marca singură nu este suficientă pentru a evita coliziunea de email. Vezi
exemplul Node.js.