Sari la conținut
Perlato — software pentru clinici stomatologice
ProdusFuncționalitățiCum funcționeazăPrețuriSite clinicăFonduri europeneFAQResurse
Accesează App →Solicită Demo
Acasă›Dezvoltatori
Dezvoltatori · API v1

Perlato API v1 — integrări

API-ul leagă Perlato de alte sisteme ale clinicii (centrală telefonică în cloud, site, aplicații proprii): găsește pacientul după telefon, creează pacientul, creează programări și primește notificări (webhook-uri) când se schimbă ceva în agendă.

Actualizat: 5 octombrie 2026 · Planul Enterprise · Prețuri

Cuprins
  1. Pe scurt
  2. Adresa și autentificarea
  3. Pacienți
  4. Medici
  5. Programări
  6. Webhook-uri
  7. Date personale

Disponibil pe planul Enterprise. Cheile API și webhook-urile se configurează de proprietarul clinicii în Setări → Integrări.

Pe scurt

OperațieCerere
Caută pacient după telefonGET /api/v1/patients?phone=0722111222
Creează pacient (doar telefonul e obligatoriu)POST /api/v1/patients
Lista medicilorGET /api/v1/doctors
Programările dintr-un intervalGET /api/v1/appointments?from=…&to=…
Creează programarePOST /api/v1/appointments
Notificări la programare nouă / mutată / confirmată / anulatăwebhook-uri

Adresa și autentificarea

  • Adresa de bază: https://<clinica>.perlato.ro/api/v1 (aceeași adresă la care lucrează clinica în Perlato).
  • Fiecare cerere poartă cheia API în antet:
Authorization: Bearer plt_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

(X-Api-Key: plt_… e acceptat ca alternativă.)

  • Cheia se afișează o singură dată, la creare. Folosește câte o cheie pentru fiecare sistem conectat, ca să o poți revoca separat. O cheie revocată primește imediat 401.
  • Limite: 120 de cereri pe minut pentru fiecare cheie și 500 de creări (pacienți + programări) pe zi pentru fiecare cheie; peste limită: 429. Cererile repetate cu o cheie greșită sunt blocate temporar pe adresa IP.
  • În Setări → Integrări vezi, pentru fiecare cheie, când a fost folosită ultima dată și câte citiri și creări a făcut azi.

Păstrarea cheii

  • Cheia stă doar pe server (în configurația centralei sau a aplicației voastre), niciodată în cod care rulează în browser, într-o aplicație mobilă sau într-un depozit de cod.
  • Folosește întotdeauna https://. O cerere trimisă din greșeală pe http:// expune cheia înainte de redirecționare.
  • Cheile nu expiră. Schimb-o (creezi una nouă, apoi o revoci pe cea veche) cel puțin o dată pe an și ori de câte ori se schimbă furnizorul sau persoanele care au avut acces la ea.
  • Accesul nu se poate restrânge la anumite adrese IP; o cheie scăpată se revocă imediat din Setări → Integrări.
  • Corpurile cererilor și răspunsurilor sunt JSON (UTF-8).

Erori

CodCând
401Cheie lipsă, greșită sau revocată
403Planul clinicii nu include API-ul
404Pacientul nu există
409Intervalul e ocupat în calendar (medic sau cabinet)
422Date invalide (telefon, dată); mesajul e în câmpul detail
429Prea multe cereri

Exemplu: {"detail": "Număr de telefon invalid. Format acceptat: 07XXXXXXXX sau +407XXXXXXXX."}

Ce date expune API-ul

API-ul întoarce doar ce îi trebuie unui sistem de programări: numele, telefonul și emailul pacientului, iar pentru programări ora, durata, medicul, serviciul, statusul și sursa. Observațiile medicale din programări și din fișa pacientului nu se transmit prin API și nici prin webhook-uri.

Orele

  • În răspunsuri, fiecare programare are start în UTC (cu Z) și start_local în ora României.
  • În cereri, start e ISO 8601. Fără fus orar înseamnă ora României (2026-10-05T14:30:00); cu fus, e convertit (2026-10-05T14:30:00+03:00, 2026-10-05T11:30:00Z).

Pacienți

Caută după telefon

GET /api/v1/patients?phone=0722111222

Numărul e recunoscut în formatele 0722111222, 0722 111 222, 0722-111-222 și +40722111222. Pe același telefon pot exista mai mulți pacienți (de exemplu un copil pe telefonul părintelui), deci răspunsul e o listă, în ordinea creării.

curl -s "https://clinica.perlato.ro/api/v1/patients?phone=%2B40722111222" \
  -H "Authorization: Bearer $PERLATO_KEY"
{
  "patients": [
    {
      "id": "6c1f…",
      "name": "Maria Pop",
      "phone": "0722111222",
      "email": "",
      "created_at": "2026-09-12T08:15:00Z",
      "next_appointment": {
        "id": "a91d…",
        "patient_id": "6c1f…",
        "doctor_id": "d23…",
        "doctor_name": "Dr. Ionescu",
        "start": "2026-10-05T11:30:00Z",
        "start_local": "2026-10-05T14:30:00",
        "duration_minutes": 30,
        "service": "Urgență",
        "status": "scheduled",
        "source": "phone"
      }
    }
  ]
}

Niciun pacient → {"patients": []}.

Creează pacient

POST /api/v1/patients
{"phone": "0722111222", "name": "Maria Pop"}
  • phone e obligatoriu, name opțional. Fără nume, pacientul apare ca „Pacient nou 0722111222”, iar medicul îl completează apoi în fișă.
  • Sigur la apeluri repetate: dacă există deja un pacient cu acel telefon (și, când trimiți numele, cu un nume compatibil), primești pacientul existent cu 200 și "created": false. Altfel 201 și "created": true.
curl -s -X POST "https://clinica.perlato.ro/api/v1/patients" \
  -H "Authorization: Bearer $PERLATO_KEY" -H "Content-Type: application/json" \
  -d '{"phone": "0722111222"}'
{"patient": {"id": "6c1f…", "name": "Pacient nou 0722111222", "phone": "0722111222", "email": "", "created_at": "2026-10-03T20:41:00Z", "next_appointment": null}, "created": true}

Medici

GET /api/v1/doctors
{"doctors": [{"id": "d23…", "name": "Dr. Ionescu"}, {"id": "e45…", "name": "Dr. Pop"}]}

Programări

Lista

GET /api/v1/appointments?from=2026-10-05T00:00:00&to=2026-10-06T00:00:00&doctor_id=d23…
  • from, to opționale (implicit: de acum o oră, 7 zile înainte); intervalul maxim e de 62 de zile, iar from poate fi cel mult cu 31 de zile în urmă (API-ul e pentru programările apropiate, nu pentru arhivă).
  • Filtre opționale: doctor_id, patient_id.
  • status: scheduled (programată), confirmed (confirmată), completed (finalizată), cancelled (anulată), no_show (neprezentare).

Creează

POST /api/v1/appointments
{
  "patient_id": "6c1f…",
  "start": "2026-10-05T14:30:00",
  "duration_minutes": 30,
  "doctor_id": "d23…",
  "service": "Urgență — durere dentară",
  "notes": "Sunat la 02:10, durere 8/10"
}
  • Obligatorii: patient_id, start (în viitor, cel mult 400 de zile înainte). Implicit: duration_minutes 30 (între 5 și 600), service „Consultație”, fără medic.
  • notes se salvează în programare (le vede medicul în Perlato), dar nu mai sunt întoarse de API.
  • Programarea apare imediat în calendar, cu sursa „Telefon”, și primește reminderul obișnuit (WhatsApp/SMS) cu o zi înainte.
  • Dacă medicul (sau cabinetul) e ocupat în acel interval sau are o blocare în calendar → 409.
  • Sigur la reîncercare: aceeași cerere trimisă din nou (același pacient, aceeași oră, același medic, programarea încă activă) întoarce programarea existentă cu 200 și "created": false, nu o a doua programare — chiar dacă durata sau serviciul diferă. Programarea nouă: 201 și "created": true.
curl -s -X POST "https://clinica.perlato.ro/api/v1/appointments" \
  -H "Authorization: Bearer $PERLATO_KEY" -H "Content-Type: application/json" \
  -d '{"patient_id": "6c1f…", "start": "2026-10-05T14:30:00", "duration_minutes": 30, "doctor_id": "d23…", "service": "Urgență"}'
{"appointment": {"id": "a91d…", "patient_id": "6c1f…", "doctor_id": "d23…", "doctor_name": "Dr. Ionescu", "start": "2026-10-05T11:30:00Z", "start_local": "2026-10-05T14:30:00", "duration_minutes": 30, "service": "Urgență", "status": "scheduled", "source": "phone"}, "created": true}

Flux tipic pentru o centrală telefonică

  1. La apel: GET /patients?phone=<numărul apelantului> → afișezi medicului de gardă numele și următoarea programare.
  2. Număr necunoscut: POST /patients {"phone": …} (sigur și dacă îl apelezi la fiecare apel).
  3. Medicul programează: POST /appointments cu patient_id din pasul 1 sau 2.

Webhook-uri

Perlato trimite un POST la adresa ta când se întâmplă un eveniment, indiferent de unde vine schimbarea: calendarul din Perlato, programarea online, confirmarea pe WhatsApp sau API-ul.

Evenimente

TipCând
patient.createdPacient nou
appointment.createdProgramare nouă
appointment.rescheduledS-a schimbat ora, durata sau medicul
appointment.confirmedPacientul a confirmat (sau recepția a marcat confirmarea)
appointment.cancelledProgramare anulată
appointment.deletedProgramare ștearsă din calendar
pingTestul din Setări → Integrări

La configurare alegi evenimentele pe care le primești.

Cererea

POST https://adresa-ta/…
Content-Type: application/json
User-Agent: Perlato-Webhooks/1
X-Perlato-Event: appointment.created
X-Perlato-Delivery: 5b0e…          (id unic al livrării — îl poți folosi ca să ignori dublurile)
X-Perlato-Signature: t=1759517460,v1=4f2a…
{
  "id": "5b0e…",
  "type": "appointment.created",
  "created_at": "2026-10-03T20:51:00Z",
  "data": {
    "appointment": {"id": "a91d…", "patient_id": "6c1f…", "doctor_id": "d23…", "doctor_name": "Dr. Ionescu", "start": "2026-10-05T11:30:00Z", "start_local": "2026-10-05T14:30:00", "duration_minutes": 30, "service": "Urgență", "status": "scheduled", "source": "online"},
    "patient": {"id": "6c1f…", "name": "Maria Pop", "phone": "0722111222", "email": "", "created_at": "2026-09-12T08:15:00Z"}
  }
}
  • patient.created are doar data.patient.
  • appointment.deleted are data.appointment cu id, patient_id, start, doctor_id, service.
  • Conținutul (data.appointment, data.patient) e starea de la momentul evenimentului; o reîncercare retrimite aceeași stare.
  • Observațiile programării (notes) nu se trimit, pentru că pot conține informații medicale.
  • Importul în masă de pacienți nu generează câte un patient.created pentru fiecare rând.

Răspunsul tău și reîncercările

  • Răspunde cu orice cod 2xx (ideal în sub 10 secunde). Restul se procesează la tine, asincron.
  • Orice alt răspuns, o eroare de rețea sau peste 10 secunde → reîncercăm după 30 s, 2 min, 10 min, 1 h și 6 h; apoi livrarea e marcată eșuată (vizibilă în Setări → Integrări → Livrări).
  • Nu urmăm redirecționări (3xx = eșec).
  • Ordinea nu e garantată între reîncercări — folosește created_at.
  • Aceeași livrare poate sosi de două ori (de exemplu dacă răspunsul tău s-a pierdut): ignoră un id (din corp) deja procesat.
  • Antetele X-Perlato-Event și X-Perlato-Delivery sunt doar ajutătoare și nu sunt semnate; după verificarea semnăturii, folosește valorile type și id din corpul cererii.

Verificarea semnăturii

Fiecare webhook are un secret whsec_…, afișat o singură dată la creare. Semnătura e HMAC-SHA256(secret, "<t>.<corpul exact al cererii>"), în hexazecimal, unde t e momentul trimiterii (secunde Unix) din același antet. Respinge cererile cu semnătura greșită sau mai vechi de 5 minute.

Python

import hashlib, hmac, time

def verifica(secret: str, antet: str, corp: bytes) -> bool:
    try:
        parti = dict(p.split("=", 1) for p in antet.split(","))
        t, semnatura = int(parti["t"]), parti["v1"]
    except (KeyError, ValueError):
        return False
    if abs(time.time() - t) > 300:
        return False
    asteptat = hmac.new(secret.encode(), f"{t}.".encode() + corp, hashlib.sha256).hexdigest()
    return hmac.compare_digest(asteptat, semnatura)

Node.js

const crypto = require("crypto");

function verifica(secret, antet, corp /* Buffer, corpul brut */) {
  const parti = Object.fromEntries(String(antet || "").split(",").map((p) => p.split("=")));
  const t = Number(parti.t);
  if (!parti.v1 || !Number.isFinite(t) || Math.abs(Date.now() / 1000 - t) > 300) return false;
  const asteptat = Buffer.from(crypto.createHmac("sha256", secret).update(`${parti.t}.`).update(corp).digest("hex"));
  const primit = Buffer.from(parti.v1);
  return primit.length === asteptat.length && crypto.timingSafeEqual(asteptat, primit);
}

Folosește corpul brut, așa cum a sosit — nu JSON-ul re-serializat.

Cerințe pentru adresă

  • Doar https:// pe portul standard 443, cu certificat valid.
  • Adresa trebuie să fie publică: adresele din rețele interne (10.x, 192.168.x, localhost etc.) sunt refuzate.

Date personale

API-ul și webhook-urile transmit date ale pacienților (nume, telefon, programări), fără observațiile medicale. Când un pacient e șters definitiv din Perlato, copiile datelor lui din coada de webhook-uri se șterg și ele. Sistemul care le primește devine parte din prelucrarea datelor clinicii: păstrați cheile și secretele în siguranță, folosiți doar HTTPS și includeți furnizorul centralei în evidența GDPR a clinicii. Livrările păstrate în Perlato pentru diagnostic se șterg automat după 30 de zile.

© 2026 MPR DESIGN S.R.L. Toate drepturile rezervate.
Toate resurselePrețuriSecuritateAPI pentru integrăriDespreNoutățiSolicită demoConfidențialitate