Skip to content

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.

ObjectWhat it holds
Client recordThe 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 careA platform animal (animalId) or a local pet for guests; status, cadence weeks, next due, alert text
Contacts and addressesYour copy of channels (email / phone / SMS / WhatsApp, opt-out) and service addresses (geocoded, gate / parking / power / water notes)
Notes, tags, tasks, consentsTyped notes (pinned / alert / private), your tag library, follow-up tasks with due dates, channel × purpose consent
LoyaltyStamp-card programs: every N visits earn a free service, a percent, an amount or credit
SegmentsSaved audiences from rules (status, tags, species, last visit, value, due, consent …) or hand-picked lists; export to CSV
Activity and statsAn immutable timeline per client and derived statistics (visits, no-shows, lifetime value, engagement and churn-risk scores)
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=25
GET /api/clientele/v1/me/clients/lookup?phone=4165551234
GET /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-01
GET /api/clientele/v1/lookups/client-statuses?locale=fr-CA

A 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).

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

PurposeChannelMeaning
MARKETING_EMAILEMAILOffers, news and promotions by e-mail.
MARKETING_TEXTSMSThe same by text message.
MARKETING_INAPPIN_APPThe 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 (EXPRESS or IMPLIED_EBR) and, for an implied one, when it lapses.

  • IN_APP is not a contact channel. It has no address, so adding it as a client contact is refused; it exists only in consents.

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

FeatureFREEBASICPRO
Client records50plan allowanceplan allowance
Analytics history90 days400 days1500 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.