POST /api/v1/clinic/doctors
Bulk upsert lekarzy. Idempotent po (clinic_id, external_id). created =
nowe mappings; updated = istniejące mappings z odświeżonym snapshotem User.
Auth: Bearer pk_live_* z scope doctors:write (więcej).
Request
POST /api/v1/clinic/doctors HTTP/1.1
Host: api.pandoktorek.pl
Authorization: Bearer pk_live_XXXXXXXX_<secret>
Content-Type: application/json
{
"doctors": [ /* DoctorIngestItem, max 500 */ ]
}
DoctorIngestItem
| Pole | Typ | Wymagane | Opis |
|---|---|---|---|
external_id | string (1-120) | ✅ | Twój ID z CRM. Stabilny — nie zmienia się dla tego samego lekarza |
first_name | string (1-100) | ✅ | Imię |
last_name | string (1-100) | ✅ | Nazwisko |
email | ✅ | Lekarz dostanie magic-link claim email (DEC-009) | |
phone | string (regex ^\+?\d{9,15}$) | — | E.164 lub krajowy |
pwz | string (regex ^\d{7}$) | — | Numer Prawa Wykonywania Zawodu (PL) |
specializations | string[] | — | Np. ["dermatologia", "wenerologia"] |
is_telehealth_enabled | bool | — | Czy lekarz robi telekonsultacje |
accepts_kids | bool | — | Czy przyjmuje dzieci |
:::info Email — własność lekarza
Email NIE jest nadpisywany przy update — lekarz mógł zmienić email po
claim. Zmiana wymaga /auth/request-verification z poziomu lekarza.
:::
Response 200
{
"created": 2,
"updated": 1,
"errors": []
}
created — nowe clinic_doctor_mappings rows. Każdy nowy lekarz dostaje
email magic-link z prośbą o claim profilu (DEC-009).
updated — istniejące mappings; User snapshot (first/last name, phone, pwz,
specializations, flags) został odświeżony. Lekarz NIE dostaje nowego emaila.
errors — partial failures (np. duplikat pwz w paczce). Pole obecne tylko
gdy len > 0.
Response 422 — walidacja
{
"detail": [
{
"loc": ["body", "doctors", 0, "pwz"],
"msg": "string does not match regex \"^\\d{7}$\"",
"type": "value_error.str.regex"
}
]
}
→ Errors
Pełen przykład
curl -X POST https://api.pandoktorek.pl/api/v1/clinic/doctors \
-H "Authorization: Bearer pk_live_XXXXXXXX_<secret>" \
-H "Content-Type: application/json" \
-d @- <<'EOF'
{
"doctors": [
{
"external_id": "mydr-12345",
"first_name": "Anna",
"last_name": "Kowalczyk",
"email": "anna.kowalczyk@klinika.pl",
"phone": "+48501234567",
"pwz": "1234567",
"specializations": ["dermatologia"],
"is_telehealth_enabled": true,
"accepts_kids": false
},
{
"external_id": "mydr-67890",
"first_name": "Jan",
"last_name": "Nowak",
"email": "jan.nowak@klinika.pl",
"specializations": ["kardiologia"],
"accepts_kids": true
}
]
}
EOF
Mapping table
Pandoktorek trzyma mapping clinic_doctor_mappings:
| clinic_id | external_id | doctor_user_id |
|-----------|-------------|----------------|
| clinic_A | mydr-12345 | uuid-... |
| clinic_A | mydr-67890 | uuid-... |
Re-push z innego clinic'u z tym samym external_id = osobny mapping (różne
clinic_id → różne lekarze logicznie, mimo że pwz mógłby być ten sam).
Doctor profile editing
Po claim'ie lekarz może edytować publiczny profil (bio, photo, degree)
przez /doktor/profil. Pola medyczne (specializations, pwz) — push'owane
przez ciebie — lekarz NIE może edytować (bo source-of-truth w klinice).
mode=external_managed (DEC-012): klinika zarządza w MyDr → cały sync
jednokierunkowy. mode=standalone: klinika edytuje też w panelu Pandoktorka,
ale ten endpoint nadal działa (wygrywa ostatni write).
Limity
- Max 500 doctors per request (paczki)
- Max 120 znaków
external_id - Max 100 znaków first/last name
- Rate limit: 10 000 requests/dobę per API key