Client book (Clientele)
The client book is the provider-side roster behind every pet-professional workflow on United
Pet Club: who your clients are, which of their animals you care for, what you agreed with them,
and how the relationship is going. It lives in the Clientele bounded context and is exposed
through the gateway at /api/clientele/v1/…. Every call acts as the provider profile the
caller is signed in as (or acting for); another provider’s records are simply not found.
Core objects
Section titled “Core objects”| Object | What it holds |
|---|---|
| Client record | The relationship: a member profile or a guest (name + email / phone), status (PROSPECT, ACTIVE, LAPSED, INACTIVE, BLOCKED), source, role, vertical, VIP / flagged, referral, your client number |
| Animal under care | A platform animal (animalId) or a local pet for guests; status, cadence weeks, next due, alert text |
| Contacts and addresses | Your copy of channels (email / phone / SMS / WhatsApp, opt-out) and service addresses (geocoded, gate / parking / power / water notes) |
| Notes, tags, tasks, consents | Typed notes (pinned / alert / private), your tag library, follow-up tasks with due dates, channel × purpose consent |
| Loyalty | Stamp-card programs: every N visits earn a free service, a percent, an amount or credit |
| Segments | Saved audiences from rules (status, tags, species, last visit, value, due, consent …) or hand-picked lists; export to CSV |
| Activity and stats | An immutable timeline per client and derived statistics (visits, no-shows, lifetime value, engagement and churn-risk scores) |
Common calls
Section titled “Common calls”POST /api/clientele/v1/me/clients{ "guest": { "givenName": "Jane", "familyName": "Doe", "email": "jane@example.com", "phone": "+14165551234", "countryCode": "CA" }, "verticalCode": "GROOMING", "tags": ["VIP"], "address": { "addressFormatted": "1 Main St, Toronto, ON", "isDefaultService": true, "accessNotes": "Gate code 1234" }, "animals": [{ "name": "Rex", "speciesCode": "DOG", "breedName": "Labrador Retriever", "cadenceWeeks": 6 }], "consents": [{ "channelCode": "EMAIL", "purposeCode": "MARKETING", "isGranted": true }]}GET /api/clientele/v1/me/clients?search=jane&status=ACTIVE&tags=VIP&sort=-LAST_VISIT&page=1&pageSize=25GET /api/clientele/v1/me/clients/lookup?phone=4165551234GET /api/clientele/v1/me/clients/{id}POST /api/clientele/v1/me/clients/{id}/notes { "kindCode": "HANDLING", "body": "Nervous with dryers", "isAlert": true }POST /api/clientele/v1/me/tasks { "clientRecordId": "…", "kindCode": "REBOOK", "title": "Rebook Rex", "dueAtUtc": "2026-10-04T15:00:00Z" }POST /api/clientele/v1/me/clients/{id}/loyalty/stamp { "sourceEntityType": "Appointment", "sourceEntityId": "…" }POST /api/clientele/v1/me/segments { "name": "Due this month", "kindCode": "DYNAMIC", "rules": { "dueWithinDays": 30 } }POST /api/clientele/v1/me/imports { "fileName": "clients.csv", "csv": "Name,Email,Phone\n…" }GET /api/clientele/v1/me/analytics/overview?from=2026-08-01&to=2026-09-01GET /api/clientele/v1/lookups/client-statuses?locale=fr-CAA member sees the other side at GET /api/clientele/v1/my/providers (which providers hold them
as a client, what is held, consents, loyalty) and may disconnect or claim a guest record that
matches their verified email / phone (GET /my/claimable, POST /my/claimable/{id}/claim).
Marketing consent
Section titled “Marketing consent”A consent is one channel × purpose pair per client. Read the codes from the lookups (localized, no sign-in):
GET /api/clientele/v1/lookups/contact-channels and GET /api/clientele/v1/lookups/consent-purposes.
The marketing purposes follow Canada’s anti-spam law (CASL):
| Purpose | Channel | Meaning |
|---|---|---|
MARKETING_EMAIL | EMAIL | Offers, news and promotions by e-mail. |
MARKETING_TEXT | SMS | The same by text message. |
MARKETING_INAPP | IN_APP | The same as messages inside United Pet Club, to a client who is a platform member (added 2026-10-17). |
-
Implied consent is derived, never set by you. A completed booking implies the marketing purposes for 24 months after the visit (text only when the client has a phone, in-app only when the client has a member profile). It never overrides an express grant, and never returns after the client withdrew it themselves.
-
An express grant needs evidence. Granting a marketing purpose on the client’s behalf must say how and when the client agreed, or the call is refused as a validation error:
PUT /api/clientele/v1/me/clients/{id}/consents[{ "channelCode": "IN_APP", "purposeCode": "MARKETING_INAPP", "isGranted": true,"evidence": "Ticked the in-app offers box on the intake form, 2026-10-12" }]The answer lists the client’s consents with their
basis(EXPRESSorIMPLIED_EBR) and, for an implied one, when it lapses. -
IN_APPis not a contact channel. It has no address, so adding it as a client contact is refused; it exists only in consents.
Responses and errors
Section titled “Responses and errors”Every response is the platform envelope with a resultCode from the Clientele category
(ClienteleClient, ClienteleEngage, ClienteleInsights, ClienteleAdmin). Notable rejections:
…_VL_Duplicate_RJ (409, the contact already belongs to one of your clients),
…_VL_Allowance_RJ (403, the plan’s client allowance is used up),
…_VL_Tier_RJ (403, a higher plan tier unlocks segments / loyalty / import / detailed
analytics), …_VL_State_RJ (409, merged or forgotten records cannot change).
Plan tiers
Section titled “Plan tiers”| Feature | FREE | BASIC | PRO |
|---|---|---|---|
| Client records | 50 | plan allowance | plan allowance |
| Analytics history | 90 days | 400 days | 1500 days |
| Segments, loyalty, CSV import | — | ✓ | ✓ |
| Cohorts, breakdowns, at-risk, funnel, top clients | — | — | ✓ |
Feature codes: CLIENTELE_CLIENTS, CLIENTELE_HISTORY_DAYS, CLIENTELE_SEGMENTS,
CLIENTELE_LOYALTY, CLIENTELE_IMPORT, CLIENTELE_ANALYTICS_DETAIL.