Caregivers & Pet Sharing
Vetty supports two complementary ways for a primary owner to extend access to their pets:
| Mechanism | Audience | Channel | Lifecycle |
|---|---|---|---|
| Pet share code | Clinics (vetdoctor app) | Short alphanumeric code or QR | Single-use or limited-redemption; can be revoked or expire on a date |
| Caregiver invite | Family / friend co-owners | Email-based invite token | Long-lived; explicit access level (view / full); revocable |
The two surfaces are independent — a pet can have any number of share codes and caregivers concurrently.
Pet share codes
When to use
When the owner walks into a clinic, hands the vet their phone, and wants the clinic to be able to add chart entries to this pet without a long onboarding form.
Owner flow (vetty)
- Owner navigates to Pets → [pet] → Share.
- App calls
POST /api/v1/owner/me/shareswith{pet_id, expires_at?, max_redemptions?}. - Backend mints a code via
PetShare::generateCode()(8-character human-friendly). - App displays the code + a QR encoding the same.
- Owner can revoke at any time (
POST /api/v1/owner/me/shares/{share}/revoke).
Clinic flow (vetdoctor)
- Clinic staff opens the QR scanner.
- App calls
POST /api/v1/shares/redeemwith{code, tenant_id, user_id}. - Backend validates: not revoked, not expired, redemption count under cap. Increments
redeemed_count. - Pet is now linked to the clinic's patient list under the active tenant.
Public landing
Unauthenticated GET /api/v1/shares/{code} returns a minimal preview (pet name, owner-supplied notes) so the QR-scan landing page can render before the staff member installs the app.
Caregiver invites
When to use
A spouse who also looks after the dog, a dog walker who needs read-only access to the vaccination record, a family member who occasionally takes the cat to the vet.
Owner flow (vetty)
- Owner opens Pets → [pet] → Caregivers → Invite.
- App calls
POST /api/v1/owner/me/pets/{pet}/caregiverswith{invited_email, invited_name?, access_level: "view"|"full"}. - Backend creates a
pet_caregiversrow with a freshinvite_token(48-char URL-safe). SendCaregiverInviteEmailJobis enqueued. The job:- Loads the row.
- Renders the
caregiver_invitetemplate viaTemplateRenderer::renderBySlug. - Builds the OutboundMessage (recipient =
invited_email, accept-URL with_rawsuffix to bypass HTML escaping). - Sends through the configured driver.
- Owner sees the row appear with status
pending.
Resend / revoke
- Resend:
POST /api/v1/owner/me/pets/{pet}/caregivers/{caregiver}/resend— re-fires the same job without minting a new token. - Revoke:
POST /api/v1/owner/me/pets/{pet}/caregivers/{caregiver}/revoke— setsrevoked_at. The token short-circuits inside the job and returns 410 if redeemed afterwards.
Invitee flow
- Caregiver receives the email, clicks the
accept_url(deep links into vetty if installed, otherwise lands on the web acceptance page). - After login, app calls
POST /api/v1/caregivers/acceptwith{token}. - Backend matches the token, sets
caregiver_user_idto the authenticated user, setsaccepted_at, and nulls out theinvite_token(one-shot). - Caregiver now sees the pet in their Shared with me tab (
GET /api/v1/owner/me/caregivers/shared-with-me).
Access levels
view— the caregiver can read the pet's profile, vaccinations, documents, health journal, and timeline. They cannot write anything.full— adds write access on the health journal, document upload, and order requests.
Policy enforcement happens in the controllers that load the pet — they look up pet_caregivers for the authenticated user and gate writes accordingly.
Architectural notes
- Tokens are stored in plaintext today (
Str::random(48)). The audit recommends hashing with SHA-256 on store and comparing hashes on accept (AUDIT.md§7). - The
caregiver_invitetemplate is platform-default; tenants don't override it because caregivers belong to the owner's account, not a tenant. - The job uses
$this->onQueue(...)in the constructor (not aqueue()method) — see Notifications for the full driver story.
Related docs
- Notifications module — driver, template renderer, opt-outs.
- Pet safety module — collar tag and lost-pet mode.
- Patient management — how shared pets surface across both apps.