Skip to content

TxCases V1 — Developer Guide

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.

Parameters

ParameterInRequiredTypeDescription
Organization-IDheaderYesstringThe organization ID
filterqueryNostringFilter criteria (see filter keys below)
responseFieldsqueryNostringURL-encoded comma-delimited list of fields to include, or ALL
pageSizequeryNostringNumber of records per page (default 100, maximum 500)
lastIdqueryNostringLargest txCase id from the previous page — preferred cursor

✅ Recommended: Use lastId with pageSize. Combine with lastModified and patient.id to keep queries narrow.

Filter Keys

Filter KeyOperatorsExample
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 lastModified range with no patient.id can return 408 on large tenants.

Ordering: Bulk GET does not apply a lastModified sort. lastId means id > previousId. Pass the largest id from 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.

Example Requests

Cases for a patient modified after a date:

GET /api/v1/txcases?pageSize=100&filter=patient.id==12000006542062,lastModified>=2025-01-01T00:00:00Z

Cases for one patient only:

GET /api/v1/txcases?pageSize=100&filter=patient.id==12000006542062

Subset of fields:

GET /api/v1/txcases?responseFields=name,status,patient&filter=patient.id==12000006542062

Next 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:00Z

GET — TxCase by ID — click to expand

Returns a single treatment case. Missing or non-numeric txCaseId → 404.

Parameters

ParameterInRequiredTypeDescription
txCaseIdpathYesintegerThe case ID (numeric, minimum 1)
Organization-IDheaderYesstringThe organization ID
responseFieldsqueryNostringComma-delimited list of fields to include, or ALL

Example Requests

Full case:

GET /api/v1/txcases/9000000000123

Subset of fields:

GET /api/v1/txcases/9000000000123?responseFields=name,status,patient

POST — 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.

Required Fields

FieldTypeDescription
userobjectLinked user { "id": <userId> }
patientobjectLinked patient { "id": <patientId> }
namestring1–50 characters. Unique per patient treatment plan
proceduresarrayPatient procedures { "id": <patientProcedureId> } to place on the first visit

Optional Fields

FieldTypeDescription
notestringMax 250 characters
showNotebooleanWhether the note is shown in the planner
expirationDatedateMust be a future date when set
showExpirationDatebooleanWhether the expiration date is shown
statusstringNEW, PRESENTED, ACCEPTED, REJECTED. Defaults to NEW
providerSignatureobjectLinked signature { "id": … }
witnessSignatureobjectLinked signature { "id": … }

providerSignatureDate and witnessSignatureDate are set when the matching signature is sent. Do not write those dates.

Conditional / scenario notes

ScenarioExtra rule
Duplicate name for the same patient400 — TxCase with name '…' already exists
procedures element missing id or wrong type400 — each element must be a PatientProcedureV1 id
Empty body400

Example — required fields only

POST /api/v1/txcases
Content-Type: application/json
{
  "user": { "id": 12000006542001 },
  "patient": { "id": 12000006542062 },
  "name": "Recommended treatment",
  "procedures": [{ "id": 8000000000456 }]
}

Example — note, expiration, and status

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"
}

Example — signatures on create

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.

Example — duplicate name (400)

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.

Example — invalid procedures (400)

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.

Parameters

ParameterInRequiredTypeDescription
txCaseIdpathYesintegerThe case ID
Organization-IDheaderYesstringThe organization ID
responseFieldsqueryNostringComma-delimited list of fields to include, or ALL

Writable properties

PropertyNotes
name1–50 characters; uniqueness still applies
note, showNoteSame rules as create
expirationDate, showExpirationDateFuture date when set
statusNEW, 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.

Example — note and status

PUT /api/v1/txcases/9000000000123
Content-Type: application/json
{
  "note": "Accepted at consult",
  "status": "ACCEPTED"
}

Example — rename

PUT /api/v1/txcases/9000000000123
Content-Type: application/json
{
  "name": "Accepted treatment plan"
}

Duplicate name on the same patient plan → 400.

Example — expiration

PUT /api/v1/txcases/9000000000123
Content-Type: application/json
{
  "expirationDate": "2026-12-31",
  "showExpirationDate": true
}

Example — signatures

PUT /api/v1/txcases/9000000000123
Content-Type: application/json
{
  "providerSignature": { "id": 7000000000100 },
  "witnessSignature": { "id": 7000000000101 }
}

Example — same status (no-op)

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.

Parameters

ParameterInRequiredTypeDescription
txCaseIdpathYesintegerThe case ID
Organization-IDheaderYesstringThe organization ID
deleteTypequeryYesstringDELETE or MOVE_AND_DELETE
deleteTypeBehavior
DELETESoft-cancels patient procedures on the case’s visits and deletes the visits and case
MOVE_AND_DELETEUnassigns those procedures in Treatment Planner, then deletes the case

Example — cancel procedures and delete

DELETE /api/v1/txcases/9000000000123?deleteType=DELETE

Example — unassign procedures and delete

DELETE /api/v1/txcases/9000000000123?deleteType=MOVE_AND_DELETE

Example — missing deleteType (400)

DELETE /api/v1/txcases/9000000000123

Example — invalid deleteType (400)

DELETE /api/v1/txcases/9000000000123?deleteType=INVALID_TYPE

GET — 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.

Parameters

ParameterInRequiredTypeDescription
Organization-IDheaderYesstringThe organization ID
filterqueryYesstringids with -> (IN)
responseFieldsqueryYesstringMust include isCompleted. id is also allowed. ALL is not valid

Empty responseFields or an unknown name → 400.

Example Requests

GET /api/v1/txcases/calculated?filter=ids->[9000000000123,9000000000124]&responseFields=isCompleted

Missing responseFields → 400:

GET /api/v1/txcases/calculated?filter=ids->[9000000000123]

ALL is not valid → 400:

GET /api/v1/txcases/calculated?filter=ids->[9000000000123]&responseFields=ALL

GET — Calculated by ID — click to expand

Same calculated fields for one case. Missing txCaseId → 404. Missing responseFields → 400.

Example Requests

GET /api/v1/txcases/9000000000123/calculated?responseFields=isCompleted

Missing responseFields → 400:

GET /api/v1/txcases/9000000000123/calculated

GET — 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).

Response data fields

FieldTypeDescription
caseTotalnumberSum of visit amounts
discountnumberSum of visit discounts
guarantorPortionnumberSum of visit guarantor portions
visitsarrayPer-visit rows

Visit row fields

visitId, code, Th, surface, description, provider, amount, discount, guarantorPortion

Example Request

GET /api/v1/txcases/9000000000123/amount

GET — 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==12000006542062

Count with a date bound:

GET /api/v1/txcases/totalcount?filter=patient.id==12000006542062,lastModified>=2025-01-01T00:00:00Z

See Bulk GET — Total Count Behavior.


StreamAPI 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:

FieldTypeDescription
dataobject or arrayTxCase record(s), calculated rows, amount object, or { totalCount }
warningsarrayNon-fatal warnings
errorsarrayField-level or structural errors

Bulk GET data is an array and includes meta.pagination (limit, offset, and total when present).

TxCaseV1 object (summary)

FieldDescription
idCase identifier
typeAlways TxCaseV1
nameUnique per patient plan
statusNEW, PRESENTED, ACCEPTED, REJECTED
note, showNotePlanner note
expirationDate, showExpirationDateOptional expiration
userRequired on create; omit on update
patientLinked patient
providerSignature, witnessSignatureLinked signatures
providerSignatureDate, witnessSignatureDateSet when the matching signature is sent; do not send on write
lastModifiedLast modification timestamp

Errors & Warnings

HTTP Status Code Errors — click to expand

400 — Bad Request

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.

401 — Unauthorized

MessageAuthentication is required and has failed or has not been provided.
FixProvide a valid Bearer token in the Authorization header.

403 — Forbidden

MessageThe request is understood, but it has been refused or access is not allowed.
FixConfirm credentials and organization access with your integration administrator.

404 — Not Found

No case for txCaseId in this organization, or the path id is not a valid numeric id.

408 — Request Timeout

MessageThe request timed out.
FixRetry. Narrow lastModified and add patient.id on bulk GET.

429 — Too Many Requests

MessageRate limit exceeded.
FixImplement exponential backoff. See the rate limiting guide.

500 — Unexpected Error

MessageAn unexpected error occurred.
FixRetry. If the issue persists, contact support.

Field-level validation — click to expand

name

Error: TxCase with name '…' already exists

WhyAnother case on the same patient plan already uses that name.
FixChoose a unique name.

procedures

Error: Each element must be an object with an id of PatientProcedureV1

WhyA list entry is null, missing id, or not a patient procedure.
FixSend { "id": <patientProcedureId> } for existing chart procedures — not practice procedure ids.

deleteType

Error: deleteType must have a value in [DELETE,MOVE_AND_DELETE]

WhyThe query is missing or not one of the two values.
FixAdd ?deleteType=DELETE or ?deleteType=MOVE_AND_DELETE.

Calculated responseFields

Error: List of calculated fields should not be empty / field does not exist

WhyresponseFields was omitted or included a name other than isCompleted / id.
FixUse responseFields=isCompleted. Do not send ALL.

status

Error: status should not be empty / invalid enum

Whystatus was null or not NEW, PRESENTED, ACCEPTED, or REJECTED.
FixOmit status to leave it unchanged, or send a valid enum value.