Start with a partner account.
Request credentials and an approved launch origin. Available content and capabilities depend on your partner access.
Discuss your integration →API reference · v2026-08-23
Find the right exercises, open a prescribing workspace, and keep your catalog current. Explore the interface your development team can build on.
Request credentials and an approved launch origin. Available content and capabilities depend on your partner access.
Discuss your integration →Exchange client credentials for a short-lived access token. Keep secrets on your backend and send the token as a Bearer header.
Authentication endpoint →For a native catalog, import the snapshot pages, then apply incremental changes. Serve your cached catalog to clinicians.
Catalog sync guide →The integration surface
https://www.physicaltherapy365.com/api/v1Exercise content only: do not send patient, encounter, diagnosis, or contact data. Examples below are templates; reading this page does not make API calls.
11 endpoints
Run on your server. Replace example values and placeholders with your integration’s values.
curl --request POST 'https://www.physicaltherapy365.com/api/v1/oauth/token' \ --user "$PT365_CLIENT_ID:$PT365_CLIENT_SECRET" \ --data 'grant_type=client_credentials'
{
"required": true,
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"required": [
"grant_type"
],
"properties": {
"grant_type": {
"const": "client_credentials"
},
"client_id": {
"type": "string"
},
"client_secret": {
"type": "string",
"format": "password"
}
}
}
}
}
}Look up referenced data models →Access token
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Token"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}catalog:readRun on your server. Replace example values and placeholders with your integration’s values.
curl --request GET 'https://www.physicaltherapy365.com/api/v1/exercises?q=quad&status=active&limit=10' \ --header "Authorization: Bearer $PT365_ACCESS_TOKEN"
| Name | Location | Details |
|---|---|---|
qOptional | query | Search names, descriptions, targets, tags, and synonyms{"type":"string"} |
regionOptional | query | Body region{"type":"string"} |
categoryOptional | query | Exercise category{"type":"string"} |
levelOptional | query | Difficulty level{"type":"string"} |
equipmentOptional | query | Equipment text{"type":"string"} |
tagsOptional | query | Comma-separated tags{"type":"string"} |
statusOptional | query | Lifecycle status{"type":"string"} |
updated_afterOptional | query | ISO 8601 date-time{"type":"string"} |
cursorOptional | query | Opaque page cursor{"type":"string"} |
limitOptional | query | {"type":"integer","minimum":1,"maximum":100,"default":50} |
Exercise page
{
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Exercise"
}
},
"meta": {
"$ref": "#/components/schemas/PageMeta"
}
}
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}catalog:readRun on your server. Replace example values and placeholders with your integration’s values.
curl --request GET 'https://www.physicaltherapy365.com/api/v1/exercises/REPLACE_WITH_EXERCISE_ID' \ --header "Authorization: Bearer $PT365_ACCESS_TOKEN"
| Name | Location | Details |
|---|---|---|
idRequired | path | {"type":"string"} |
revisionOptional | query | Immutable content revision{"type":"string"} |
Exercise
{
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"$ref": "#/components/schemas/Exercise"
}
}
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}catalog:readRun on your server. Replace example values and placeholders with your integration’s values.
curl --request GET 'https://www.physicaltherapy365.com/api/v1/taxonomies' \ --header "Authorization: Bearer $PT365_ACCESS_TOKEN"
Taxonomies
Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Entitlement is independent of sandbox/production. A full-catalog pilot sees all published lifecycle records; ordinary sandbox clients see only the sample catalog. Begin change synchronization at changeCursor after importing every snapshot page.
catalog:readRun on your server. Replace example values and placeholders with your integration’s values.
curl --request GET 'https://www.physicaltherapy365.com/api/v1/catalog/manifest' \ --header "Authorization: Bearer $PT365_ACCESS_TOKEN"
Immutable snapshot manifest
{
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"$ref": "#/components/schemas/CatalogManifest"
}
}
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}catalog:readRun on your server. Replace example values and placeholders with your integration’s values.
curl --request GET 'https://www.physicaltherapy365.com/api/v1/catalog/snapshots/REPLACE_WITH_SNAPSHOT_ID?offset=0&limit=100' \ --header "Authorization: Bearer $PT365_ACCESS_TOKEN"
| Name | Location | Details |
|---|---|---|
idRequired | path | {"type":"string","format":"uuid"} |
offsetOptional | query | {"type":"integer","minimum":0,"default":0} |
limitOptional | query | {"type":"integer","minimum":1,"maximum":100,"default":100} |
Snapshot contents never change. Follow nextOffset until null; verify total and every image sha256 before activation.
{
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"$ref": "#/components/schemas/Exercise"
}
},
"meta": {
"type": "object",
"properties": {
"snapshotId": {
"type": "string"
},
"catalogRevision": {
"type": "string"
},
"total": {
"type": "integer"
},
"nextOffset": {
"type": [
"integer",
"null"
]
},
"changeCursor": {
"type": "string"
}
}
}
}
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}catalog:readRun on your server. Replace example values and placeholders with your integration’s values.
curl --request GET 'https://www.physicaltherapy365.com/api/v1/catalog/changes?cursor=REPLACE_WITH_CHANGE_CURSOR&limit=100' \ --header "Authorization: Bearer $PT365_ACCESS_TOKEN"
| Name | Location | Details |
|---|---|---|
cursorOptional | query | Opaque change cursor{"type":"string"} |
limitOptional | query | {"type":"integer","minimum":1,"maximum":250,"default":100} |
Ordered immutable lifecycle events. Fetch the exact event revision, then atomically persist the applied batch and nextCursor. Webhooks are reconciliation hints; poll every 15 minutes as recovery.
{
"application/json": {
"schema": {
"type": "object",
"properties": {
"data": {
"type": "array",
"items": {
"type": "object",
"properties": {
"sequence": {
"type": "integer"
},
"type": {
"enum": [
"exercise.published",
"exercise.updated",
"exercise.deprecated",
"exercise.withdrawn"
]
},
"exerciseId": {
"type": "string"
},
"revision": {
"type": "string"
},
"status": {
"enum": [
"active",
"deprecated",
"withdrawn"
]
},
"occurredAt": {
"type": "string",
"format": "date-time"
}
}
}
},
"meta": {
"type": "object",
"properties": {
"nextCursor": {
"type": "string"
},
"hasMore": {
"type": "boolean"
},
"catalogRevision": {
"type": "string"
}
}
}
}
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}picker:createRun on your server. Replace example values and placeholders with your integration’s values.
curl --request POST 'https://www.physicaltherapy365.com/api/v1/picker/sessions' \
--header "Authorization: Bearer $PT365_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"origin": "https://your-emr.example",
"clinicianId": "clinician-demo",
"initialSelection": []
}'{
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/PickerSessionRequest"
}
}
}
}Look up referenced data models →Picker launch URL
Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}webhooks:manageRun on your server. Replace example values and placeholders with your integration’s values.
curl --request GET 'https://www.physicaltherapy365.com/api/v1/webhooks' \ --header "Authorization: Bearer $PT365_ACCESS_TOKEN"
Webhook list
Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}webhooks:manageRun on your server. Replace example values and placeholders with your integration’s values.
curl --request POST 'https://www.physicaltherapy365.com/api/v1/webhooks' \
--header "Authorization: Bearer $PT365_ACCESS_TOKEN" \
--header 'Content-Type: application/json' \
--data '{
"url": "https://your-emr.example/webhooks/pt365",
"events": [
"exercise.updated"
]
}'{
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": false,
"required": [
"url",
"events"
],
"properties": {
"url": {
"type": "string",
"format": "uri",
"pattern": "^https://"
},
"events": {
"type": "array",
"uniqueItems": true,
"items": {
"enum": [
"exercise.published",
"exercise.updated",
"exercise.deprecated",
"exercise.withdrawn"
]
}
}
}
}
}
}
}Look up referenced data models →Webhook and one-time signing secret
Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}webhooks:manageRun on your server. Replace example values and placeholders with your integration’s values.
curl --request DELETE 'https://www.physicaltherapy365.com/api/v1/webhooks/REPLACE_WITH_WEBHOOK_ID' \ --header "Authorization: Bearer $PT365_ACCESS_TOKEN"
| Name | Location | Details |
|---|---|---|
idRequired | path | {"type":"string","format":"uuid"} |
Deleted
Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Request failed
{
"application/json": {
"schema": {
"$ref": "#/components/schemas/Error"
}
}
}Shared structures
These schemas define the fields used in requests and responses. Both this reference and the downloadable JSON use the same OpenAPI source.
{
"type": "object",
"required": [
"schemaVersion",
"snapshotId",
"catalogRevision",
"total",
"changeCursor",
"createdAt"
],
"properties": {
"schemaVersion": {
"const": 1
},
"snapshotId": {
"type": "string",
"format": "uuid"
},
"catalogRevision": {
"type": "string"
},
"total": {
"type": "integer",
"minimum": 0
},
"changeCursor": {
"type": "string",
"description": "Opaque event cursor captured atomically with this snapshot"
},
"createdAt": {
"type": "string",
"format": "date-time"
}
}
}{
"type": "object",
"required": [
"access_token",
"token_type",
"expires_in",
"scope",
"environment"
],
"properties": {
"access_token": {
"type": "string"
},
"token_type": {
"const": "Bearer"
},
"expires_in": {
"type": "integer"
},
"scope": {
"type": "string"
},
"environment": {
"enum": [
"sandbox",
"production"
]
}
}
}{
"type": "object",
"required": [
"error"
],
"properties": {
"error": {
"type": "object",
"required": [
"code",
"message",
"requestId"
],
"properties": {
"code": {
"type": "string"
},
"message": {
"type": "string"
},
"requestId": {
"type": "string"
},
"details": {}
}
}
}
}{
"type": "object",
"properties": {
"environment": {
"enum": [
"sandbox",
"production"
]
},
"total": {
"type": "integer"
},
"limit": {
"type": "integer"
},
"nextCursor": {
"type": [
"string",
"null"
]
},
"catalogRevision": {
"type": "string"
}
}
}{
"type": "object",
"additionalProperties": false,
"required": [
"exerciseId",
"revision",
"side"
],
"properties": {
"exerciseId": {
"type": "string"
},
"revision": {
"type": "string"
},
"side": {
"enum": [
"left",
"right",
"bilateral",
"not_applicable"
]
},
"sets": {
"type": "integer",
"minimum": 1,
"maximum": 99
},
"repetitions": {
"type": "integer",
"minimum": 1,
"maximum": 999
},
"holdSeconds": {
"type": "integer",
"minimum": 1,
"maximum": 3600
},
"durationMinutes": {
"type": "integer",
"minimum": 1,
"maximum": 240
},
"frequency": {
"type": "object",
"additionalProperties": false,
"required": [
"times",
"period"
],
"properties": {
"times": {
"type": "integer",
"minimum": 1,
"maximum": 20
},
"period": {
"enum": [
"day",
"week"
]
}
}
},
"resistance": {
"type": "string",
"maxLength": 80
},
"restSeconds": {
"type": "integer",
"minimum": 0,
"maximum": 3600
},
"customDosage": {
"type": "string",
"minLength": 1,
"maxLength": 200,
"description": "Written dosage overrides structured sets, repetitions, hold, duration, rest and frequency. The picker returns only one dosage format."
}
}
}{
"type": "object",
"additionalProperties": false,
"required": [
"origin",
"clinicianId"
],
"description": "No patient or encounter fields permitted",
"properties": {
"origin": {
"type": "string",
"format": "uri",
"description": "Exact registered HTTPS origin; sandbox credentials also permit HTTP localhost or loopback for local development. No path or trailing slash."
},
"clinicianId": {
"type": "string",
"pattern": "^[A-Za-z0-9._:-]{8,128}$"
},
"theme": {
"type": "object",
"additionalProperties": false,
"properties": {
"brandName": {
"type": "string",
"maxLength": 80
},
"primaryColor": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}$"
},
"backgroundColor": {
"type": "string",
"pattern": "^#[0-9A-Fa-f]{6}$"
}
}
},
"initialSelection": {
"type": "array",
"maxItems": 20,
"items": {
"$ref": "#/components/schemas/Prescription"
}
}
}
}{
"type": "object",
"required": [
"role",
"url",
"mimeType",
"width",
"height",
"sha256",
"alt"
],
"properties": {
"role": {
"enum": [
"start",
"end"
]
},
"url": {
"type": "string",
"format": "uri"
},
"mimeType": {
"const": "image/png"
},
"width": {
"type": "integer"
},
"height": {
"type": "integer"
},
"sha256": {
"type": "string"
},
"alt": {
"type": "string"
}
}
}{
"type": "object",
"required": [
"id",
"slug",
"revision",
"status",
"name",
"description",
"steps",
"media"
],
"properties": {
"id": {
"type": "string",
"pattern": "^ex_[0-9a-f]{20}$"
},
"slug": {
"type": "string"
},
"revision": {
"type": "string"
},
"status": {
"enum": [
"active",
"deprecated",
"withdrawn"
]
},
"publishedAt": {
"type": "string",
"format": "date-time"
},
"updatedAt": {
"type": "string",
"format": "date-time"
},
"replacementId": {
"type": "string"
},
"changeReason": {
"type": "string"
},
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"steps": {
"type": "array",
"items": {
"type": "string"
}
},
"cue": {
"type": "string"
},
"region": {
"enum": [
"Knee",
"Shoulder",
"Low Back",
"Neck",
"Hip",
"Ankle",
"Elbow / Wrist / Hand"
]
},
"category": {
"enum": [
"Mobility",
"Strength",
"Balance",
"Stretch"
]
},
"level": {
"enum": [
"Early",
"Foundation",
"Functional"
]
},
"target": {
"type": "string"
},
"equipment": {
"type": "array",
"items": {
"type": "string"
}
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"searchSynonyms": {
"type": "array",
"items": {
"type": "string"
}
},
"defaultPrescription": {
"type": "object"
},
"media": {
"type": "array",
"minItems": 2,
"maxItems": 2,
"items": {
"$ref": "#/components/schemas/Media"
}
}
}
}