ssm.ro Docs

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=M00212

Parametri

ParametruÎnTipObligatoriuDescriere
organizatiequerystringDaNumele organizației
marcaquerystringDaMarca — cheia unică de identificare a angajatului

Răspunsuri

CodDescriere
200 OKObiect 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 ErrorEroare 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/contacts

Creează 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

CodDescriere
200 OKContactul a fost creat — returnează obiectul Employee
404 Not FoundOrganizația nu a fost găsită
422 Unprocessable EntityDate invalide — răspuns JSON cu detalii eroare
500 Server ErrorEroare internă server

Modificare contact existent

PATCH /v1/contacts/update

Actualizează 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

CodDescriere
200 OKContactul a fost actualizat — returnează obiectul Employee
204 No ContentNicio modificare efectuată — datele trimise sunt identice cu cele existente
404 Not FoundContactul nu a fost găsit
422 Unprocessable EntityDate invalide — răspuns JSON cu detalii eroare
500 Server ErrorEroare 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țieCodExplicație
cnp deja folosit de alt angajat422CNP-ul trebuie să fie unic în organizație
cnp cu format greșit422CNP invalid (format valid: 13 cifre)
limba în afara valorilor acceptate422Sunt permise doar ro, en
dataIncepereActivitate cu dată invalidăignoratO dată neparsabilă este tratată ca goală (fără eroare)
telefon prea scurt (sub 9 cifre)ignoratNumă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:

Contractmarcaemail
Contract principalM00212ion.popescu@exemplu.ro
Al doilea contractM00478ion.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țiemarcaemail
demo-organizationM00212ion.popescu@exemplu.ro
demo-productieM00478ion.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țieSoluție recomandată
Ambele contracte aparțin aceleiași entitățiAlias-uri de email
Contractele aparțin unor entități sau divizii gestionate separatOrganizații diferite
Angajatul trebuie să aibă un singur cont de autentificareOrganizaț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.