Provider Directory Service — API Contracts
Status: populated Owner: TBD Last updated: 2026-04-17 Companion: 05 API Design · API_PATH_CONVENTIONS
1. Conventions
- Base path:
/api/v1 - Auth: Bearer JWT; required scopes below.
- Idempotency:
Idempotency-Keyon POST/PUT. - Optimistic lock:
If-Match: "<version>"on PUT/PATCH. - Pagination:
page+limit(default 20, max 200). - Errors:
{ error: { code, message, details? } }.
2. Practitioners
| Method | Path | Scope | Notes |
|---|---|---|---|
POST | /api/v1/practitioners | provider_directory:write | Create |
GET | /api/v1/practitioners?q=&kind=&specialty=&status=&nodeId= | provider_directory:read | Search + filter |
GET | /api/v1/practitioners/{id} | provider_directory:read | Get |
PUT | /api/v1/practitioners/{id} | provider_directory:write | Replace |
POST | /api/v1/practitioners/{id}/deactivate | provider_directory:admin | Deactivate |
POST | /api/v1/practitioners/{id}/suspend | provider_directory:admin | Suspend |
POST | /api/v1/practitioners/{id}/reinstate | provider_directory:admin | Reinstate |
POST body (excerpt):
{
"kind": "physician",
"names": [{"use":"official","family":"احمدی","given":["محمد"],"scriptCode":"ps"},
{"use":"official","family":"Ahmadi","given":["Mohammad"],"scriptCode":"en"}],
"identifiers": [{"system":"urn:oid:afg:mcn","value":"MCN-00123","authority":"AFG-MC","use":"official"}],
"telecom": [{"system":"email","value":"m.ahmadi@ibnsina.health"}],
"specialties": [{"system":"http://snomed.info/sct","code":"394802001","display":"General medicine"}],
"preferredLanguage": "ps"
}
Errors: 409 IDENTIFIER_CONFLICT, 422 SPECIALTY_UNKNOWN.
3. Credentials
| Method | Path | Scope | Notes |
|---|---|---|---|
POST | /api/v1/practitioners/{id}/credentials | provider_directory:write | Add |
PATCH | /api/v1/practitioners/{id}/credentials/{credId} | provider_directory:write | Update |
POST | /api/v1/practitioners/{id}/credentials/{credId}/revoke | provider_directory:admin | Revoke |
GET | /api/v1/practitioners/{id}/credentials | provider_directory:read | List |
4. Practitioner Roles
| Method | Path | Scope | Notes |
|---|---|---|---|
POST | /api/v1/practitioner-roles | provider_directory:write | Assign |
GET | /api/v1/practitioner-roles?practitionerId=&nodeId=&active= | provider_directory:read | List |
PATCH | /api/v1/practitioner-roles/{id} | provider_directory:write | Update privileges/period |
POST | /api/v1/practitioner-roles/{id}/end | provider_directory:admin | End |
Errors: 422 CREDENTIAL_REQUIRED, 409 PRACTITIONER_DEACTIVATED.
5. Healthcare Services
| Method | Path | Scope | Notes |
|---|---|---|---|
POST | /api/v1/healthcare-services | provider_directory:write | Create |
GET | /api/v1/healthcare-services?nodeId=&category=&active= | provider_directory:read | List |
PATCH | /api/v1/healthcare-services/{id} | provider_directory:write | Update |
DELETE | /api/v1/healthcare-services/{id} | provider_directory:admin | Deactivate |
6. Service Endpoints
| Method | Path | Scope | Notes |
|---|---|---|---|
POST | /api/v1/endpoints | provider_directory:write | Register |
GET | /api/v1/endpoints?orgNodeId=&type=&status= | provider_directory:read | List |
PATCH | /api/v1/endpoints/{id} | provider_directory:write | Update |
POST | /api/v1/endpoints/{id}/healthcheck | provider_directory:write | Trigger manual check |
7. Privileges (hot path)
| Method | Path | Scope | Notes |
|---|---|---|---|
GET | /api/v1/internal/practitioners/{id}/privileges?nodeId= | internal:any-service | Returns effective privileges at scope; p99 ≤ 30ms |
8. FHIR Projection
| FHIR | Method | Path |
|---|---|---|
| Practitioner | GET/POST/PUT | /fhir/R4/Practitioner[/{id}] |
| PractitionerRole | GET/POST/PUT | /fhir/R4/PractitionerRole[/{id}] |
| HealthcareService | GET/POST/PUT | /fhir/R4/HealthcareService[/{id}] |
| Endpoint | GET/POST/PUT | /fhir/R4/Endpoint[/{id}] |
Search parameters per FHIR R4 spec; name, identifier, specialty, active supported.
9. Rate Limits
| Class | Limit |
|---|---|
| Reads | 500 rps / tenant |
| Writes | 100 rps / tenant |
| Internal privilege check | 5000 rps / caller |
10. Error Response Example
{ "error": { "code": "CREDENTIAL_REQUIRED", "message": "Role 'consultant' requires an active 'license' credential", "details": { "missing": ["license"], "practitionerId": "prc_01H..." } } }