Authentication
Every request to /api/public/v1 authenticates with an organization API
key sent as a bearer token:
curl https://api.plusmedical.ro/api/public/v1/locations \
-H "Authorization: Bearer pm_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" Key lifecycle
-
Keys are created by an organization admin in the PlusMedical app (Settings → API). The full
key (
pm_live_…, 48 characters) is shown exactly once — only a SHA-256 hash is stored. Treat it like a password. - Rotation: rotating a key issues a replacement (new secret, shown once). The old key keeps working for a 24-hour grace window so you can swap credentials without downtime, then expires automatically.
- Revocation is immediate and permanent. Keys can also carry an optional expiry date.
- Every API-key action is recorded in the organization's immutable audit log.
Scopes
Each key carries an explicit list of scopes; a request to a route whose scope the key lacks
returns 403 insufficient_scope naming the missing scope.
| Scope | Grants |
|---|---|
read:locations | GET /locations |
read:doctors | GET /doctors |
read:services | GET /services |
read:availability | GET /availability |
read:patients | GET /patients (contact data masked) |
write:patients | POST/PATCH /patients + unmasked contact data on reads |
read:appointments | GET /appointments |
write:appointments | POST /appointments + cancel/reschedule |
read:invoices | GET /invoices (issued documents only) |
No clinical scopes exist in v1. Visits, lab values, treatment plans and documents are not exposed through API keys — a deliberate GDPR-driven decision. Clinical access may arrive in v2 behind explicit patient consent.
Testing your integration
There is no separate sandbox in v1. The recommended pattern is a test organization: create a second organization on a trial/development subscription, issue keys there, and develop against its data. Keys always operate strictly inside their own organization — tenant isolation is enforced at the database level (PostgreSQL row-level security).