MedTrainer Public API (1.0.0)
The MedTrainer Public API allows external integrations to search and manage core directory resources such as locations, divisions, and practitioners.
This specification describes the available endpoints, request parameters, payloads, authentication requirements, and expected responses for clients integrating with the platform.
Most resource endpoints return FHIR-aligned JSON with content type
application/fhir+json. Protected endpoints accept authentication through
either the X-API-Key header or Authorization: Bearer <token>.
This guide walks you through how to generate an API Key from the platform. This key will allow you to authenticate and interact with the available APIs.
Before you begin, make sure you have:
A valid account and access to the platform
Proper permissions to generate an API Key (Super Admin / Admin)
Logged into the platform
1. Log in to the platform
Sign in to the MedTrainer platform using your credentials.
2. Open Organization settings
Once you're in:
On the left-side menu
Click on Organization
3. Expand “Organization Management” and find the “API keys manager”
Inside Organization Settings:
Expand “Organization Management” menu
Here you’ll find all options to configure the organization
Look for “API keys manager” option and click on it
4. Create a new API Key group
In the “API keys manager” page:
Click on “Create API key group”
Fill the following fields:
name
description
Confirm the action by clicking the “Create” button.
5. Activate the API Key “Default”
After generating the API key group:
On the “API Keys Manager” page, you will see the newly created API key group, along with a “Default” API key in an “Inactive” status.
To activate the “Default” API key:
Click on the status to expand the available options.
Once the list is expanded, select the “Active” status
Search locations
Returns a FHIR Bundle with location resources.
Authorizations:
query Parameters
| _count | integer >= 1 Default: 20 Number of resources to return. Must be a positive integer. |
| _page | integer >= 1 Default: 1 1-based page number. Must be a positive integer. |
| _elements | string Example: _elements=id,name Comma-separated field selector. For location and division searches, the implemented selectors are
For practitioners, nested selectors are allowed, including values such
as Whitespace around values is trimmed. Unknown selectors are preserved in pagination links but ignored when each resource is built. Pagination |
Responses
Response samples
- 200
- 400
- 401
- 422
- 429
- 500
{- "resourceType": "Bundle",
- "type": "searchset",
- "total": 3,
- "link": [
- {
- "relation": "self",
- "url": "/api/v1/locations?_count=2&_page=2&_elements=id%2Cname"
}, - {
- "relation": "first",
- "url": "/api/v1/locations?_count=2&_page=1&_elements=id%2Cname"
}, - {
- "relation": "previous",
- "url": "/api/v1/locations?_count=2&_page=1&_elements=id%2Cname"
}, - {
- "relation": "last",
- "url": "/api/v1/locations?_count=2&_page=2&_elements=id%2Cname"
}
], - "entry": [
- {
- "resource": {
- "resourceType": "Location",
- "id": "LOC-003",
- "name": "Location test from php host"
}
}
]
}Create a location
Authorizations:
Request Body schema: application/jsonrequired
| name required | string [ 1 .. 100 ] characters Required location name. Cannot be blank or whitespace-only. |
| locations | Array of strings[ items non-empty ] Optional list of child location public IDs. Each value cannot be blank or whitespace-only. |
Responses
Request samples
- Payload
{- "name": "North Campus",
- "locations": [
- "LOC-001",
- "LOC-002"
]
}Response samples
- 200
- 201
- 400
- 401
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Location created successfully.",
- "id": "LOC-001"
}
}
]
}Update a location
Updates a location identified by publicId.
Authorizations:
path Parameters
| publicId required | string Example: LOC-001 Public location identifier. |
Request Body schema: application/jsonrequired
| name required | string [ 1 .. 100 ] characters Required location name. Cannot be blank or whitespace-only. |
| locations | Array of strings[ items non-empty ] Optional list of child location public IDs. Each value cannot be blank or whitespace-only. |
Responses
Request samples
- Payload
{- "name": "North Campus",
- "locations": [
- "LOC-001"
]
}Response samples
- 200
- 400
- 401
- 404
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Location updated successfully.",
- "id": "LOC-001"
}
}
]
}Update a location with PATCH
Updates a location identified by publicId using the same request
body and validation rules as PUT.
Authorizations:
path Parameters
| publicId required | string Example: LOC-001 Public location identifier. |
Request Body schema: application/jsonrequired
| name required | string [ 1 .. 100 ] characters Required location name. Cannot be blank or whitespace-only. |
| locations | Array of strings[ items non-empty ] Optional list of child location public IDs. Each value cannot be blank or whitespace-only. |
Responses
Request samples
- Payload
{- "name": "North Campus",
- "locations": [
- "LOC-001"
]
}Response samples
- 200
- 400
- 401
- 404
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Location updated successfully.",
- "id": "LOC-001"
}
}
]
}Search divisions
Returns a FHIR Bundle with division resources.
Authorizations:
query Parameters
| _count | integer >= 1 Default: 20 Number of resources to return. Must be a positive integer. |
| _page | integer >= 1 Default: 1 1-based page number. Must be a positive integer. |
| _elements | string Example: _elements=id,name Comma-separated field selector. For location and division searches, the implemented selectors are
For practitioners, nested selectors are allowed, including values such
as Whitespace around values is trimmed. Unknown selectors are preserved in pagination links but ignored when each resource is built. Pagination |
Responses
Response samples
- 200
- 400
- 401
- 422
- 429
- 500
{- "resourceType": "Bundle",
- "type": "searchset",
- "total": 3,
- "link": [
- {
- "relation": "self",
- "url": "/api/v1/divisions?_count=2&_page=2"
}, - {
- "relation": "first",
- "url": "/api/v1/divisions?_count=2&_page=1"
}, - {
- "relation": "previous",
- "url": "/api/v1/divisions?_count=2&_page=1"
}, - {
- "relation": "last",
- "url": "/api/v1/divisions?_count=2&_page=2"
}
], - "entry": [
- {
- "resource": {
- "resourceType": "Division",
- "id": "DIV-003",
- "name": "East Division",
- "locations": [
- {
- "reference": "LOC-010"
}, - {
- "reference": "LOC-011"
}
]
}
}
]
}Create a division
Creates a division with a non-blank name and at least one linked location public ID.
Authorizations:
Request Body schema: application/jsonrequired
| name required | string [ 1 .. 254 ] characters Required division name. Cannot be blank or whitespace-only. |
| locations required | Array of strings non-empty [ items non-empty ] Required list of location public IDs. At least one value must be provided, and each value cannot be blank or whitespace-only. |
Responses
Request samples
- Payload
{- "name": "North Division",
- "locations": [
- "LOC-001"
]
}Response samples
- 200
- 201
- 400
- 401
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Division created successfully.",
- "id": "DIV-001"
}
}
]
}Get a division by ID
Authorizations:
path Parameters
| divisionId required | string Example: DIV-001 Public division identifier. |
Responses
Response samples
- 200
- 400
- 401
- 404
- 429
- 500
{- "resourceType": "Division",
- "id": "DIV-123",
- "name": "Clinical Division",
- "locations": [
- {
- "reference": "LOC-001"
}, - {
- "reference": "LOC-002"
}
]
}Update a division
Accepts partial updates. Send at least one of name or locations.
Authorizations:
path Parameters
| divisionId required | string Example: DIV-001 Public division identifier. |
Request Body schema: application/jsonrequired
| name required | string [ 1 .. 254 ] characters Conditionally required division name. Send |
| locations | Array of strings[ items non-empty ] Conditionally required list of location public IDs. Send |
Responses
Request samples
- Payload
{- "name": "Updated Division"
}Response samples
- 200
- 400
- 401
- 404
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Division updated successfully.",
- "id": "DIV-001"
}
}
]
}Update a division with PATCH
Accepts the same payload as PUT and is routed to the same update handler.
Authorizations:
path Parameters
| divisionId required | string Example: DIV-001 Public division identifier. |
Request Body schema: application/jsonrequired
| name required | string [ 1 .. 254 ] characters Conditionally required division name. Send |
| locations | Array of strings[ items non-empty ] Conditionally required list of location public IDs. Send |
Responses
Request samples
- Payload
{- "name": "Updated Division"
}Response samples
- 200
- 400
- 401
- 404
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Division updated successfully.",
- "id": "DIV-001"
}
}
]
}Create a practitioner
Creates a practitioner/provider profile for the company resolved from the API key.
Authorizations:
Request Body schema: application/jsonrequired
| resourceType | string^\s*Practitioner\s*$ Optional resource type discriminator. When present it must equal |
| id | string non-empty Optional public practitioner identifier. If present it cannot be blank or whitespace-only. |
required | object (PractitionerWriteName) Practitioner name payload.
Every string field below is constrained to letters, numbers, spaces,
apostrophes, periods, and hyphens. The character allowlist regex
enforced server-side is |
| birthDate | string (MmDdYyyyDateString) ^(0[1-9]|1[0-2])/(0[1-9]|[12][0-9]|3[01])/[0-... Date string in The value must represent a real calendar date accepted by server-side
validation, not just a string that matches the pattern. For example,
|
| gender | string [ 1 .. 100 ] characters ^[A-Za-z0-9 .'\-]+$ Only letters, numbers, spaces, apostrophes, periods, and hyphens are allowed. Maximum 100 characters. |
required | object (PractitionerWriteTelecom) Practitioner telecom payload.
|
object (PractitionerWriteAddress) Optional address payload used for both Validation is asymmetric between the two usages. When this schema is
referenced as
The same regex and length rules are not enforced when the schema
is referenced as | |
object (PractitionerWriteAddress) Optional address payload used for both Validation is asymmetric between the two usages. When this schema is
referenced as
The same regex and length rules are not enforced when the schema
is referenced as | |
required | object (PractitionerWriteExtension) Practitioner extension payload. |
Responses
Request samples
- Payload
{- "resourceType": "Practitioner",
- "id": "EMP-PUB-002",
- "name": {
- "given": "John",
- "family": "Doe",
- "middle": "Allen"
}, - "birthDate": "01/01/1990",
- "gender": "male",
- "telecom": {
- "email": "john.payload1@example.com",
- "phone": "1234567890",
- "primaryEmail": "john.primary@example.com",
- "personalEmail": "john.personal@example.com"
}, - "address": {
- "line": [
- "Main Street 1",
- "Suite 10"
], - "city": "Miami",
- "state": "FL",
- "postalCode": "33101",
- "country": "USA"
}, - "mailingAddress": {
- "line": [
- "Billing Street 9",
- "Floor 4"
], - "city": "Orlando",
- "state": "FL",
- "postalCode": "32801",
- "country": "UNITED STATES"
}, - "extension": {
- "employment": {
- "positionId": "pos770",
- "departmentId": "dep1",
- "hireDate": "06/15/2020"
}, - "user": {
- "location": "loc4857",
- "userType": "admin",
- "division": "div8",
- "password": "<set-at-request-time>",
- "status": "Active",
- "statusReason": "Contracted"
}, - "provider": {
- "npiNumber": "1234567890",
- "caqhId": "1234567890"
}
}
}Response samples
- 200
- 201
- 400
- 401
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Provider created successfully.",
- "id": "EMP-PUB-002"
}
}
]
}Search practitioners
Returns a FHIR Bundle of practitioner resources. _elements supports
comma-separated selectors and may include nested paths such as
telecom.email, address.city, extension.user.status,
extension.user.statusReason,
extension.user.userType, or extension.provider.npiNumber.
_elements values are normalized by trimming surrounding whitespace.
Unknown selectors are preserved in pagination links but ignored when
building each practitioner resource.
Authorizations:
query Parameters
| _count | integer >= 1 Default: 20 Number of resources to return. Must be a positive integer. |
| _page | integer >= 1 Default: 1 1-based page number. Must be a positive integer. |
| _elements | string Example: _elements=id,name Comma-separated field selector. For location and division searches, the implemented selectors are
For practitioners, nested selectors are allowed, including values such
as Whitespace around values is trimmed. Unknown selectors are preserved in pagination links but ignored when each resource is built. Pagination |
Responses
Response samples
- 200
- 400
- 401
- 422
- 429
- 500
{- "resourceType": "Bundle",
- "type": "searchset",
- "total": 3,
- "link": [
- {
- "relation": "self",
- "url": "/api/v1/practitioner?_count=2&_page=2&_elements=name%2Ctelecom.email"
}, - {
- "relation": "first",
- "url": "/api/v1/practitioner?_count=2&_page=1&_elements=name%2Ctelecom.email"
}, - {
- "relation": "previous",
- "url": "/api/v1/practitioner?_count=2&_page=1&_elements=name%2Ctelecom.email"
}, - {
- "relation": "last",
- "url": "/api/v1/practitioner?_count=2&_page=2&_elements=name%2Ctelecom.email"
}
], - "entry": [
- {
- "resource": {
- "resourceType": "Practitioner",
- "name": {
- "given": "Katherine",
- "family": "Johnson"
}, - "telecom": {
- "email": "katherine@example.test"
}
}
}
]
}Get a practitioner by public ID
Returns a single practitioner resource. If _elements is omitted, the
full practitioner payload returned by the backing service is emitted.
_elements accepts the same nested selector syntax as practitioner
search and trims surrounding whitespace before filtering.
Authorizations:
path Parameters
| publicId required | string Example: PRAC-001 Public practitioner identifier. |
query Parameters
| _elements | string Example: _elements=id,name Comma-separated field selector. For location and division searches, the implemented selectors are
For practitioners, nested selectors are allowed, including values such
as Whitespace around values is trimmed. Unknown selectors are preserved in pagination links but ignored when each resource is built. Pagination |
Responses
Response samples
- 200
- 400
- 401
- 404
- 422
- 429
- 500
{- "resourceType": "Practitioner",
- "name": {
- "given": "Ada",
- "family": "Lovelace"
}, - "telecom": {
- "email": "ada@example.test"
}
}Update a practitioner
Updates a practitioner/provider profile identified by publicId.
The request body is a partial update: every top-level field is optional. Only the fields you send are forwarded to the backing service, so omitted fields retain their existing values. Any field that is present is validated with the same format/length/pattern rules as the create payload.
Authorizations:
path Parameters
| publicId required | string Example: PRAC-001 Public practitioner identifier. |
Request Body schema: application/jsonrequired
| resourceType | string^\s*Practitioner\s*$ Optional resource type discriminator. When present it must equal |
object (PractitionerUpdateName) Practitioner name payload for partial updates. All fields are optional — send only the fields you want to change. Every string field below is constrained to letters, numbers, spaces,
apostrophes, periods, and hyphens. The character allowlist regex
enforced server-side is | |
| birthDate | string (MmDdYyyyDateString) ^(0[1-9]|1[0-2])/(0[1-9]|[12][0-9]|3[01])/[0-... Date string in The value must represent a real calendar date accepted by server-side
validation, not just a string that matches the pattern. For example,
|
| gender | string [ 1 .. 100 ] characters ^[A-Za-z0-9 .'\-]+$ Only letters, numbers, spaces, apostrophes, periods, and hyphens are allowed. Maximum 100 characters. |
object (PractitionerUpdateTelecom) Practitioner telecom payload for partial updates. All fields are optional — send only the fields you want to change. Any provided string must contain at least one non-whitespace character. | |
object (PractitionerWriteAddress) Optional address payload used for both Validation is asymmetric between the two usages. When this schema is
referenced as
The same regex and length rules are not enforced when the schema
is referenced as | |
object (PractitionerWriteAddress) Optional address payload used for both Validation is asymmetric between the two usages. When this schema is
referenced as
The same regex and length rules are not enforced when the schema
is referenced as | |
object (PractitionerUpdateExtension) Practitioner extension payload for partial updates. All nested objects and their fields are optional — send only the pieces you want to change. The practitioner user status fields are nested under |
Responses
Request samples
- Payload
{- "resourceType": "Practitioner",
- "name": {
- "given": "John",
- "family": "Doe",
- "middle": "Allen"
}, - "birthDate": "01/01/1990",
- "gender": "male",
- "telecom": {
- "email": "john.payload1@example.com",
- "phone": "1234567890",
- "primaryEmail": "john.primary@example.com",
- "personalEmail": "john.personal@example.com"
}, - "address": {
- "line": [
- "Main Street 1",
- "Suite 10"
], - "city": "Miami",
- "state": "FL",
- "postalCode": "33101",
- "country": "USA"
}, - "mailingAddress": {
- "line": [
- "Billing Street 9",
- "Floor 4"
], - "city": "Orlando",
- "state": "FL",
- "postalCode": "32801",
- "country": "UNITED STATES"
}, - "extension": {
- "employment": {
- "positionId": "pos770",
- "departmentId": "dep1",
- "hireDate": "06/15/2020"
}, - "user": {
- "location": "loc4857",
- "userType": "admin",
- "division": "div8",
- "password": "<set-at-request-time>",
- "status": "Active",
- "statusReason": "Contracted"
}, - "provider": {
- "npiNumber": "1234567890",
- "caqhId": "1234567890"
}
}
}Response samples
- 200
- 400
- 401
- 404
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Practitioner updated successfully.",
- "id": "EMP-PUB-002"
}
}
]
}Update a practitioner with PATCH
Accepts the same payload as PUT and is routed to the same update
handler. Both verbs behave as partial updates: send only the fields
you want to change.
Authorizations:
path Parameters
| publicId required | string Example: PRAC-001 Public practitioner identifier. |
Request Body schema: application/jsonrequired
| resourceType | string^\s*Practitioner\s*$ Optional resource type discriminator. When present it must equal |
object (PractitionerUpdateName) Practitioner name payload for partial updates. All fields are optional — send only the fields you want to change. Every string field below is constrained to letters, numbers, spaces,
apostrophes, periods, and hyphens. The character allowlist regex
enforced server-side is | |
| birthDate | string (MmDdYyyyDateString) ^(0[1-9]|1[0-2])/(0[1-9]|[12][0-9]|3[01])/[0-... Date string in The value must represent a real calendar date accepted by server-side
validation, not just a string that matches the pattern. For example,
|
| gender | string [ 1 .. 100 ] characters ^[A-Za-z0-9 .'\-]+$ Only letters, numbers, spaces, apostrophes, periods, and hyphens are allowed. Maximum 100 characters. |
object (PractitionerUpdateTelecom) Practitioner telecom payload for partial updates. All fields are optional — send only the fields you want to change. Any provided string must contain at least one non-whitespace character. | |
object (PractitionerWriteAddress) Optional address payload used for both Validation is asymmetric between the two usages. When this schema is
referenced as
The same regex and length rules are not enforced when the schema
is referenced as | |
object (PractitionerWriteAddress) Optional address payload used for both Validation is asymmetric between the two usages. When this schema is
referenced as
The same regex and length rules are not enforced when the schema
is referenced as | |
object (PractitionerUpdateExtension) Practitioner extension payload for partial updates. All nested objects and their fields are optional — send only the pieces you want to change. The practitioner user status fields are nested under |
Responses
Request samples
- Payload
{- "resourceType": "Practitioner",
- "name": {
- "given": "John",
- "family": "Doe",
- "middle": "Allen"
}, - "birthDate": "01/01/1990",
- "gender": "male",
- "telecom": {
- "email": "john.payload1@example.com",
- "phone": "1234567890",
- "primaryEmail": "john.primary@example.com",
- "personalEmail": "john.personal@example.com"
}, - "address": {
- "line": [
- "Main Street 1",
- "Suite 10"
], - "city": "Miami",
- "state": "FL",
- "postalCode": "33101",
- "country": "USA"
}, - "mailingAddress": {
- "line": [
- "Billing Street 9",
- "Floor 4"
], - "city": "Orlando",
- "state": "FL",
- "postalCode": "32801",
- "country": "UNITED STATES"
}, - "extension": {
- "employment": {
- "positionId": "pos770",
- "departmentId": "dep1",
- "hireDate": "06/15/2020"
}, - "user": {
- "location": "loc4857",
- "userType": "admin",
- "division": "div8",
- "password": "<set-at-request-time>"
}, - "provider": {
- "npiNumber": "1234567890",
- "caqhId": "1234567890"
}
}
}Response samples
- 200
- 400
- 401
- 404
- 422
- 429
- 500
{- "resourceType": "OperationOutcome",
- "issue": [
- {
- "severity": "information",
- "code": "informational",
- "details": {
- "text": "Practitioner updated successfully.",
- "id": "EMP-PUB-002"
}
}
]
}