Reference: TxCases (V1) Endpoint Documentation
Treatment-plan cases (TxCaseV1) group planned work for a patient. Creating a case also creates a treatment option and a first visit that holds the supplied patient procedures. Procedures are not returned on the case itself — read them from Visits V1 or PatientProcedures V1.
This guide covers the published TxCases V1 operations: bulk list, get by id, create, update, delete, calculated isCompleted, case amount, and total count.
There is no /v1/txcases/async endpoint.
All TxCases V1 endpoints require an Organization-ID header.
⚠️ Rate Limited: TxCases endpoints are rate limited. See the rate limiting guide for details.
GET — Bulk List TxCases — click to expand
Returns a paginated list of treatment cases matching the filter criteria.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
Organization-ID | header | Yes | string | The organization ID |
filter | query | No | string | Filter criteria (see filter keys below) |
responseFields | query | No | string | URL-encoded comma-delimited list of fields to include, or ALL |
pageSize | query | No | string | Number of records per page (default 100, maximum 500) |
lastId | query | No | string | Largest txCase id from the previous page — preferred cursor |
✅ Recommended: Use
lastIdwithpageSize. Combine withlastModifiedandpatient.idto keep queries narrow.
| Filter Key | Operators | Example |
|---|---|---|
patient.id | == | ?filter=patient.id==12000006542062 |
lastModified | >, >=, <, <= | ?filter=lastModified>=2025-01-01T00:00:00Z |
patient.id== resolves to cases on that patient's treatment plan. If the patient has no plan in the organization, the result is empty (200 / data: []).
⚠️ Date-limiting filters: If you omit a date-limiting filter such as
lastModified, one may be applied automatically. Supply your own date bound for predictable results.
⚠️ Narrow your query: A very wide
lastModifiedrange with nopatient.idcan return 408 on large tenants.
Ordering: Bulk GET does not apply a
lastModifiedsort.lastIdmeansid > previousId. Pass the largestidfrom the previous page.
Empty results: 200 with
data: []means no cases matched; it does not indicate invalid filter values.
When lastId is present, meta.pagination.total is omitted. Use total count when you need a count. See Bulk GET — Total Count Behavior.
Cases for a patient modified after a date:
GET /api/v1/txcases?pageSize=100&filter=patient.id==12000006542062,lastModified>=2025-01-01T00:00:00ZCases for one patient only:
GET /api/v1/txcases?pageSize=100&filter=patient.id==12000006542062Subset of fields:
GET /api/v1/txcases?responseFields=name,status,patient&filter=patient.id==12000006542062Next page — send lastId as the largest id from the previous data array (not the last row if that row is not the max id):
GET /api/v1/txcases?pageSize=100&lastId=9000000000123&filter=patient.id==12000006542062,lastModified>=2025-01-01T00:00:00ZGET — TxCase by ID — click to expand
Returns a single treatment case. Missing or non-numeric txCaseId → 404.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
txCaseId | path | Yes | integer | The case ID (numeric, minimum 1) |
Organization-ID | header | Yes | string | The organization ID |
responseFields | query | No | string | Comma-delimited list of fields to include, or ALL |
Full case:
GET /api/v1/txcases/9000000000123Subset of fields:
GET /api/v1/txcases/9000000000123?responseFields=name,status,patientPOST — Create TxCase — click to expand
Creates a treatment case. Returns 201 with the created resource in data.
Side effects: Creating a case also creates a treatment option and a first visit (duration 60) that contains the supplied patient procedures. Those procedures are not returned on the TxCase body — list visits with filter=txCase.id==<id>.
Linked-model writes are { "id": … } only. Do not send url or type.
| Field | Type | Description |
|---|---|---|
user | object | Linked user { "id": <userId> } |
patient | object | Linked patient { "id": <patientId> } |
name | string | 1–50 characters. Unique per patient treatment plan |
procedures | array | Patient procedures { "id": <patientProcedureId> } to place on the first visit |
| Field | Type | Description |
|---|---|---|
note | string | Max 250 characters |
showNote | boolean | Whether the note is shown in the planner |
expirationDate | date | Must be a future date when set |
showExpirationDate | boolean | Whether the expiration date is shown |
status | string | NEW, PRESENTED, ACCEPTED, REJECTED. Defaults to NEW |
providerSignature | object | Linked signature { "id": … } |
witnessSignature | object | Linked signature { "id": … } |
providerSignatureDate and witnessSignatureDate are set when the matching signature is sent. Do not write those dates.
| Scenario | Extra rule |
|---|---|
Duplicate name for the same patient | 400 — TxCase with name '…' already exists |
procedures element missing id or wrong type | 400 — each element must be a PatientProcedureV1 id |
| Empty body | 400 |
POST /api/v1/txcases
Content-Type: application/json{
"user": { "id": 12000006542001 },
"patient": { "id": 12000006542062 },
"name": "Recommended treatment",
"procedures": [{ "id": 8000000000456 }]
}POST /api/v1/txcases
Content-Type: application/json{
"user": { "id": 12000006542001 },
"patient": { "id": 12000006542062 },
"name": "Present at next recare",
"procedures": [{ "id": 8000000000456 }],
"note": "Discuss crown vs implant",
"showNote": true,
"expirationDate": "2026-12-31",
"showExpirationDate": false,
"status": "PRESENTED"
}POST /api/v1/txcases
Content-Type: application/json{
"user": { "id": 12000006542001 },
"patient": { "id": 12000006542062 },
"name": "Signed case",
"procedures": [{ "id": 8000000000456 }],
"providerSignature": { "id": 7000000000100 },
"witnessSignature": { "id": 7000000000101 }
}The response includes providerSignatureDate and witnessSignatureDate. Do not send those dates.
A second POST with the same name for the same patient:
POST /api/v1/txcases
Content-Type: application/json{
"user": { "id": 12000006542001 },
"patient": { "id": 12000006542062 },
"name": "Recommended treatment",
"procedures": [{ "id": 8000000000457 }]
}Returns 400 with source name.
Practice procedure ids (or a missing id) are rejected. Each element must be a patient procedure:
{
"user": { "id": 12000006542001 },
"patient": { "id": 12000006542062 },
"name": "Bad procedures",
"procedures": [{ "id": "a" }]
}Returns 400 with source procedures.
PUT — Update TxCase — click to expand
Updates the case identified by txCaseId. Only included properties change. Missing case → 404.
user is frozen after create — omit it on PUT.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
txCaseId | path | Yes | integer | The case ID |
Organization-ID | header | Yes | string | The organization ID |
responseFields | query | No | string | Comma-delimited list of fields to include, or ALL |
| Property | Notes |
|---|---|
name | 1–50 characters; uniqueness still applies |
note, showNote | Same rules as create |
expirationDate, showExpirationDate | Future date when set |
status | NEW, PRESENTED, ACCEPTED, REJECTED |
providerSignature, witnessSignature | { "id": … } only |
Sending the already saved status is a no-op: 200, and status may be omitted from the response.
PUT /api/v1/txcases/9000000000123
Content-Type: application/json{
"note": "Accepted at consult",
"status": "ACCEPTED"
}PUT /api/v1/txcases/9000000000123
Content-Type: application/json{
"name": "Accepted treatment plan"
}Duplicate name on the same patient plan → 400.
PUT /api/v1/txcases/9000000000123
Content-Type: application/json{
"expirationDate": "2026-12-31",
"showExpirationDate": true
}PUT /api/v1/txcases/9000000000123
Content-Type: application/json{
"providerSignature": { "id": 7000000000100 },
"witnessSignature": { "id": 7000000000101 }
}If the case is already ACCEPTED:
PUT /api/v1/txcases/9000000000123
Content-Type: application/json{
"status": "ACCEPTED"
}Returns 200. status may be omitted from the response.
DELETE — TxCase — click to expand
Deletes the case. Query deleteType is required. Missing or invalid deleteType → 400. Missing case → 404.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
txCaseId | path | Yes | integer | The case ID |
Organization-ID | header | Yes | string | The organization ID |
deleteType | query | Yes | string | DELETE or MOVE_AND_DELETE |
deleteType | Behavior |
|---|---|
DELETE | Soft-cancels patient procedures on the case’s visits and deletes the visits and case |
MOVE_AND_DELETE | Unassigns those procedures in Treatment Planner, then deletes the case |
DELETE /api/v1/txcases/9000000000123?deleteType=DELETEDELETE /api/v1/txcases/9000000000123?deleteType=MOVE_AND_DELETEDELETE /api/v1/txcases/9000000000123DELETE /api/v1/txcases/9000000000123?deleteType=INVALID_TYPEGET — Calculated (bulk) — click to expand
Returns isCompleted for one or more cases. filter and responseFields are required. ALL is not valid.
isCompleted is true when the case’s patient procedures are completed.
| Parameter | In | Required | Type | Description |
|---|---|---|---|---|
Organization-ID | header | Yes | string | The organization ID |
filter | query | Yes | string | ids with -> (IN) |
responseFields | query | Yes | string | Must include isCompleted. id is also allowed. ALL is not valid |
Empty responseFields or an unknown name → 400.
GET /api/v1/txcases/calculated?filter=ids->[9000000000123,9000000000124]&responseFields=isCompletedMissing responseFields → 400:
GET /api/v1/txcases/calculated?filter=ids->[9000000000123]ALL is not valid → 400:
GET /api/v1/txcases/calculated?filter=ids->[9000000000123]&responseFields=ALLGET — Calculated by ID — click to expand
Same calculated fields for one case. Missing txCaseId → 404. Missing responseFields → 400.
GET /api/v1/txcases/9000000000123/calculated?responseFields=isCompletedMissing responseFields → 400:
GET /api/v1/txcases/9000000000123/calculatedGET — Amount by ID — click to expand
Returns fee totals for the case and a row per visit. Missing case → 404.
The case total field is caseTotal (not caseAmount).
| Field | Type | Description |
|---|---|---|
caseTotal | number | Sum of visit amounts |
discount | number | Sum of visit discounts |
guarantorPortion | number | Sum of visit guarantor portions |
visits | array | Per-visit rows |
visitId, code, Th, surface, description, provider, amount, discount, guarantorPortion
GET /api/v1/txcases/9000000000123/amountGET — Total Count — click to expand
Returns { "totalCount": <integer> } for cases matching the same filters as bulk GET (patient.id, lastModified).
Document only Organization-ID and filter. Pagination query parameters are not used on this path.
Count for one patient:
GET /api/v1/txcases/totalcount?filter=patient.id==12000006542062Count with a date bound:
GET /api/v1/txcases/totalcount?filter=patient.id==12000006542062,lastModified>=2025-01-01T00:00:00ZStreamAPI Webhooks — click to expand
For real-time case creates, updates, and deletes, use StreamAPI webhooks (SNS) instead of polling bulk GET. Setup: Creating and Setting Up Webhooks for the StreamAPI.
Domain type TxCaseV1. Operations: CREATE, UPDATE, DELETE.
Creating a case also creates a visit (see Visits V1), which can emit a separate VisitV1 CREATE event.
Response Structure — click to expand
A successful 200/201 response returns:
| Field | Type | Description |
|---|---|---|
data | object or array | TxCase record(s), calculated rows, amount object, or { totalCount } |
warnings | array | Non-fatal warnings |
errors | array | Field-level or structural errors |
Bulk GET data is an array and includes meta.pagination (limit, offset, and total when present).
| Field | Description |
|---|---|
id | Case identifier |
type | Always TxCaseV1 |
name | Unique per patient plan |
status | NEW, PRESENTED, ACCEPTED, REJECTED |
note, showNote | Planner note |
expirationDate, showExpirationDate | Optional expiration |
user | Required on create; omit on update |
patient | Linked patient |
providerSignature, witnessSignature | Linked signatures |
providerSignatureDate, witnessSignatureDate | Set when the matching signature is sent; do not send on write |
lastModified | Last modification timestamp |
HTTP Status Code Errors — click to expand
Invalid body or query. Common causes: missing required create fields, duplicate name, invalid procedures linked models, missing or invalid deleteType, empty or unknown calculated responseFields (including ALL), invalid status.
| Message | Authentication is required and has failed or has not been provided. |
| Fix | Provide a valid Bearer token in the Authorization header. |
| Message | The request is understood, but it has been refused or access is not allowed. |
| Fix | Confirm credentials and organization access with your integration administrator. |
No case for txCaseId in this organization, or the path id is not a valid numeric id.
| Message | The request timed out. |
| Fix | Retry. Narrow lastModified and add patient.id on bulk GET. |
| Message | Rate limit exceeded. |
| Fix | Implement exponential backoff. See the rate limiting guide. |
| Message | An unexpected error occurred. |
| Fix | Retry. If the issue persists, contact support. |
Field-level validation — click to expand
Error: TxCase with name '…' already exists
| Why | Another case on the same patient plan already uses that name. |
| Fix | Choose a unique name. |
Error: Each element must be an object with an id of PatientProcedureV1
| Why | A list entry is null, missing id, or not a patient procedure. |
| Fix | Send { "id": <patientProcedureId> } for existing chart procedures — not practice procedure ids. |
Error: deleteType must have a value in [DELETE,MOVE_AND_DELETE]
| Why | The query is missing or not one of the two values. |
| Fix | Add ?deleteType=DELETE or ?deleteType=MOVE_AND_DELETE. |
Error: List of calculated fields should not be empty / field does not exist
| Why | responseFields was omitted or included a name other than isCompleted / id. |
| Fix | Use responseFields=isCompleted. Do not send ALL. |
Error: status should not be empty / invalid enum
| Why | status was null or not NEW, PRESENTED, ACCEPTED, or REJECTED. |
| Fix | Omit status to leave it unchanged, or send a valid enum value. |