Providers and seats
Thea bills practices per provider seat, and only the practice admin can add or remove seats. The API never creates or activates a seat on its own. Staff and admins aren’t billed.
The roster
Section titled “The roster”GET /practices/{practice_id}/providers returns everyone on the practice’s
Thea roster:
{ "data": [ { "id": "2210", "practice_id": "152", "first_name": "Sam", "last_name": "Rivera", "email": "sam.rivera@riverbend.example", "npi": "1234567890", "role": "provider", "status": "active", "updated_at": "2026-10-02T18:11:40Z" } ], "has_more": false, "next_cursor": null}role |
Who | Can send cases and messages | Billed |
|---|---|---|---|
provider |
A clinician with a seat | Yes, for themselves | Yes |
staff |
Clinical staff | Yes, on a provider’s behalf | No |
admin |
Practice admins and billers | No, they can only see cases | No |
status is active, pending (waiting for the admin to approve a seat), or
inactive (removed or deactivated). Only active people can act.
Keep your copy current with the provider.activated, provider.deactivated,
and provider.updated webhooks, plus a periodic
updated_since sync.
Matching your clinicians
Section titled “Matching your clinicians”Keep a mapping from each of your clinicians and staff to a Thea roster id.
Match on NPI where both systems have it, otherwise on email. Plan for:
- A clinician with no NPI on record in one system.
- An email that differs between your system and Thea. Thea emails are unique: one account per email, across all practices.
- Clinicians who work at several practices or locations. They have one roster record in each Thea practice.
- Staff as well as providers. Staff need a mapping too, so they can create cases on a provider’s behalf.
- Ambiguous matches, such as two people with the same name and no NPI. Don’t guess; ask the practice admin to resolve them.
- Name and email changes, and people leaving (
provider.deactivated).
Who can send an eConsult
Section titled “Who can send an eConsult”Only show the option to send an eConsult to:
- Clinicians mapped to an
activeroster member with roleprovider, and - Staff mapped to an
activemember with rolestaff, who pick the provider they’re sending for.
Everyone else needs a seat first.
Requesting a seat
Section titled “Requesting a seat”For a clinician without an active seat, offer to request one:
curl -X POST "$THEA_API/practices/152/provider-requests" \ -H "Authorization: Bearer $THEA_PARTNER_KEY" \ -H "Thea-Practice-Key: $THEA_PRACTICE_KEY" \ -H "Content-Type: application/json" \ -d '{ "first_name": "Jordan", "last_name": "Okafor", "email": "jordan.okafor@riverbend.example", "npi": "1987654321" }'Thea emails the practice admin and returns 202 with the request’s status
(pending_admin_approval). If the admin approves, you get a
provider.activated webhook. Until then, show the clinician a pending state
and another way to send the referral, such as fax. Posting the same email again
returns the existing request, so you can check its status.
Seats that change mid-flow
Section titled “Seats that change mid-flow”A seat can be deactivated between showing the eConsult option and submitting
the case. POST /cases then returns
422 provider-not-active. Tell the
clinician, and fall back the same way.

