PortalInvitation
The PortalInvitation model represents a patient portal invite or password reset link that Canvas created for a user. Canvas creates one each time it creates a portal link to send, including through Send Invite, even when the send then fails, and each time a plugin mints a link with patient_portal_http.get_login_url(). The user is usually a patient, or a representative’s login when a patient shares portal access. Use it to see whether a patient opened their link, set a password with it, or let it expire, and to find patients who need a new link.
The model records the link’s history, not the link: you can’t read its URL from it. To react to a link as its state changes, handle the portal invitation events.
Basic usage #
To get an invitation by identifier, use the get method on the PortalInvitation model manager:
from canvas_sdk.v1.data import PortalInvitation
invitation = PortalInvitation.objects.get(id="d2194110-5c9a-4842-8733-ef09ea5ead11")
A user’s invitations are available from the CanvasUser through the portal_invitations accessor:
from canvas_sdk.v1.data import Patient
patient = Patient.objects.get(id="b80b1cdc2e6a4aca90ccebc02e683f35")
invitations = patient.user.portal_invitations.order_by("-created")
Filtering #
Invitations can be filtered by any attribute that exists on the model.
By status #
Filter on status with a PortalInvitationStatus value. For example, to find links that expired before the patient ever opened them:
from canvas_sdk.v1.data import PortalInvitation, PortalInvitationStatus
expired_unopened = PortalInvitation.objects.filter(
status=PortalInvitationStatus.EXPIRED, first_opened_at__isnull=True
)
Links a patient can still use #
is_redeemable is true while a link hasn’t been claimed and hasn’t expired. Check it before you send a patient another link:
from canvas_sdk.v1.data import Patient
patient = Patient.objects.get(id="b80b1cdc2e6a4aca90ccebc02e683f35")
has_live_link = patient.user.portal_invitations.filter(is_redeemable=True).exists()
Status #
Each invitation has one status, chosen in this order:
claimedwhen the link was used to set a password.expiredwhen the link has passedexpires_ator can no longer be used. A link that expired after the patient opened it staysexpired; checkfirst_opened_atto tell the two apart.openedwhen the patient opened the link at least once.pendingotherwise.
A link that Canvas couldn’t use when someone opened it records the time and reason in last_rejected_at and last_rejection_reason. Those fields don’t change status, first_opened_at, or is_redeemable.
Opening a link that was already used to set a password records the reason already_claimed, and status stays claimed. A link that lapsed without being claimed records expired.
Links created before Canvas recorded claims have no claimed_at. A link of that age that was used to set a password shows status expired, and reopening it records expired, not already_claimed. Before you send a new link in response to expired, check is_portal_registered on the CanvasUser to confirm the patient hasn’t already registered.
Attributes #
PortalInvitation #
| Field Name | Type | Description |
|---|---|---|
| id | UUID | The target ID on portal invitation events |
| dbid | Integer | |
| created | DateTime | When the link was created |
| modified | DateTime | When the link was last opened, claimed, or refused. Passing expires_at doesn’t change it |
| user | CanvasUser | The user the link signs in |
| expires_at | DateTime | When the link stops working |
| first_opened_at | DateTime | When the link was first opened successfully, or None if it never was |
| first_opened_user_agent | String | The browser user agent of that first open, or None |
| claimed_at | DateTime | When the link was used to set a password, or None |
| last_rejected_at | DateTime | When Canvas last couldn’t use the link after it was opened, or None |
| last_rejection_reason | PortalInvitationRejectionReason | Why Canvas last couldn’t use the link, or None |
| status | PortalInvitationStatus | See Status |
| is_redeemable | Boolean | Whether the link can still be used: not claimed and not expired |
Enumeration types #
PortalInvitationStatus #
| Value | Label |
|---|---|
| pending | Pending |
| opened | Opened |
| claimed | Claimed |
| expired | Expired |
PortalInvitationRejectionReason #
| Value | Label | Description |
|---|---|---|
| expired | Expired | The link had passed expires_at or could no longer be used when it was opened |
| different_account | Different account | Another account was signed in on the browser that opened it |
| already_claimed | Already claimed | The link was already used to set a password, so the patient is registered |