Skip to content

Entitlements

Entitlements are what a subject (a profile, account, animal, etc.) has the right to use right now — a feature flag (BOOLEAN), a counted quota (QUOTA / CREDIT), a measured capacity (STORAGE), a rate limit, or a time-bounded window (DURATION). They are granted from many sources (subscriptions, promotions, referrals, memberships) and your integration reads and draws them down through one consistent surface.

All routes are under /api/entitlement/v1/ and require your bearer token. The subject is polymorphic — { "kindCode": "PROFILE", "id": "<guid>" } (or ACCOUNT, ANIMAL, …).

POST /check is a side-effect-free probe — call it to decide whether to show or allow a feature.

POST /api/entitlement/v1/check
{ "subject": { "kindCode": "PROFILE", "id": "…" },
"definitionSysName": "televet.session.monthly",
"requestedQuantity": 1 }
{ "isAvailable": true, "availableQuantity": 7, "reservedQuantity": 0,
"hasActiveBoolean": false, "effectiveExpiresAtUtc": "…", "nextResetAtUtc": "…",
"blockingReasonCode": null }

/check is authoritative but advisory — always follow it with /consume for the actual draw.

POST /consume is the authoritative, atomic draw-down. An Idempotency-Key header is required — retries with the same key never double-charge and return the original result (idempotentReplay: true).

POST /api/entitlement/v1/consume
Idempotency-Key: <stable-key-for-this-action>
{ "subject": { … }, "definitionSysName": "televet.session.monthly", "quantity": 1,
"consumedByBcCode": "TELEVET", "consumedByEntityId": "<appointmentId>" }
{ "usageId": "…", "grantIdDrawnFrom": "…", "remainingQuantity": 6, "idempotentReplay": false }

Use a deterministic Idempotency-Key derived from the thing being consumed (e.g. the appointment id), so a retried request is recognised as the same operation.

To refund: POST /usage/{usageId}/reverse with a reversalReasonCode restores the quantity.

Reserve → confirm/release (multi-step flows)

Section titled “Reserve → confirm/release (multi-step flows)”

For flows where you hold capacity while the user completes a step (picking a slot, paying), use a reservation. Scarce/expensive definitions require it.

  1. POST /reserve (Idempotency-Key) → { reservationId, expiresAtUtc, reservedQuantity } — holds the quantity.
  2. POST /reservation/{id}/confirm → converts the hold into usage.
  3. POST /reservation/{id}/release → frees the hold (idempotent). Held reservations also auto-expire at their TTL.
MethodRouteReturns
GETsubject/{kind}/{id}/balancesAll current balances for a subject.
GETsubject/{kind}/{id}/definition/{sysName}/balanceOne balance.
GETsubject/{kind}/{id}/grants · /usagePaged grant / usage history.
GETdefinitions/{sysName}What an entitlement is (kind, unit, label).

A service provider’s Partner status (a rolling three-month average of on-platform booking volume at or above the threshold) is expressed as grants with source PARTNER_QUALIFICATION, minted and revoked by the platform — never by your integration. Read them like any other entitlement:

SysNameKindSubjectMeaning
PARTNER_STATUSBOOLEANthe brand profileThe provider is a Partner (or in its grace period).
PARTNER_CAMPAIGNSBOOLEANbrandMarketing email campaigns are available.
PARTNER_PRIORITY_SUPPORTBOOLEANbrandPriority support (before 2026-10-11; counts as the Guided support plan).
SUPPORT_GUIDED / SUPPORT_ASSISTED / SUPPORT_HANDS_ONBOOLEANprofileThe support plan held (bought, or included with Partner / Pro).
SUPPORT_HOURSQUOTA (minutes)profileBought hands-on support time, drawn after the plan’s included time.
SUPPORT_SESSIONSQUOTAprofileOne-off 30-minute live support sessions.
SCHEDULING_LEAD_TRACKINGBOOLEANbrandLead / abandoned-booking tracking.
PARTNER_HOSTED_SITEBOOLEANeach location profileThat location’s website carries no United Pet Club branding and may serve pages the business writes itself. The website itself is free for every verified business (since 2026-09-22) and needs no grant.
PARTNER_CUSTOM_DOMAINBOOLEANeach location profileThat site may use the provider’s own domain.
CAMPAIGN_EMAIL_SENDSQUOTA, resets monthlybrandMarketing emails the brand may send this month.

A location under a brand reads the brand-wide rights through its brand; the site and domain rights are granted per location. The same definitions may also be granted by a paid plan; they stack by the larger grant, so check the balance, not the grant list.

Litter Passes (LITTER_PASSES) and contracts (CONTRACTS)

Section titled “Litter Passes (LITTER_PASSES) and contracts (CONTRACTS)”

Since 2026-09-25 registering a litter is free on every plan: POST /api/breeding/v1/births draws no entitlement, for breeders and kennels alike. (KENNEL_LITTERS, LITTER_REGISTRATIONS and the Breeding_Litter_AD_AddonRequired_RJ / Breeding_Registry_AD_PlanLimit_RJ refusals are gone.)

The litter limit. Registration is limited only to stop abuse, and no entitlement or purchase changes the limit. Until 2026-10-12 it was a fair-use rate of five litters per profile per 24 hours (Breeding_Litter_AD_FairUse_RJ, 429). Since 2026-10-12 it is a ceiling on litters registered in a rolling 24 hours and on open litters (expected or born), set by the owner profile’s kind, verification, profile age and trust tier. Past it, the registration answers 409 Breeding_Litter_AD_Ceiling_RJ and nothing is written. The response’s data.ceiling says which limit was reached and how to get past it:

{
"ceiling": {
"featureCode": "LITTERS",
"window": "PER_DAY",
"limit": 1,
"used": 1,
"band": { "profileKindCode": "PERSON", "businessTypeCode": null, "verificationCode": "UNVERIFIED", "ageBandCode": "LT_30D" },
"resetsAtUtc": "2026-10-13T14:05:00+00:00",
"raisedBy": [ { "code": "VERIFY", "limit": 2, "allowed": null, "ageBandCode": null, "atUtc": null } ]
}
}
FieldMeaning
featureCodethe limited feature (LITTERS here)
windowSTANDING (held at once), PER_DAY (rolling 24 h) or FLAG (a yes/no feature; limit is null)
limit, usedthe limit that applies to this profile now (null = none) and how much is used
bandwhat set it: profileKindCode PERSON / BUSINESS / ORGANIZATION, businessTypeCode, verificationCode UNVERIFIED / VERIFIED, ageBandCode LT_30D / D30_90 / GTE_90D (profile age)
resetsAtUtcfor PER_DAY, when a slot frees again
raisedBywhat would raise it: VERIFY (verifying the profile) and / or ACCOUNT_AGE (ageBandCode, atUtc = when the profile reaches that age), each with the limit or allowed it would give

Do not retry a ceiling refusal unchanged: wait for resetsAtUtc, or let the member free a place (close a litter) or verify the profile. Breeding_Litter_AD_FairUse_RJ is no longer sent once this ships; treat it like a PER_DAY ceiling without detail if an older environment still answers it.

What is metered is the Litter Pass: one LITTER_PASSES unit, stamped on one litter by its owner, for that litter’s life. It unlocks the litter’s reservation queue, protected deposits on any plan, a contract per reservation, whole-litter sharing and full audience detail. Pro for kennels includes six passes a year; every other pass is bought, US$29 each. (Until 2026-10-12 the Breeder Pro and Rescue plans included passes too; they were retired.)

GET /api/breeding/v1/me/litter-meter
{
"model": "BREEDER",
"definitionSysName": "LITTER_PASSES",
"purchase": { "featureCode": "LITTER_PASSES", "quantity": 1 },
"mistakeRefundHours": 24
}

model is BREEDER or KENNEL_CATTERY and changes only wording; every other field is the same for every profile. To show the balance, read it for definitionSysName (GET /api/entitlement/v1/subject/PROFILE/{id}/definition/{sysName}/balance); then stamp the litter. The stamp, not the balance, decides:

POST /api/breeding/v1/births/{id}/pass → 200, the litter with litterPass { grantedAtUtc, sourceCode, revocableUntilUtc } and hasLitterPass: true
DELETE /api/breeding/v1/births/{id}/pass → 200 within 24 h of the grant (a unit the stamp drew returns to the balance); 409 Breeding_Litter_AD_PassLocked_RJ after

litterPass.sourceCode is PLAN when the stamp drew a unit and ADMIN when it drew none (metering off). A stamp on a litter that already holds a live pass answers 200 and draws nothing. With metering on and no pass left, the stamp answers Breeding_Litter_AD_PassRequired_RJ (402) with data.purchase = { "featureCode": "LITTER_PASSES", "quantity": 1 } — buy one with POST /api/sub/v1/checkout/feature-credits { "buyerProfileId", "featureCode": "LITTER_PASSES", "quantity": 1 } (the token acting as that profile; the purchase bills the account the profile belongs to) and retry once the payment settles. Every litter read carries hasLitterPass. Do not consume LITTER_PASSES yourself — the stamp does, keyed to the litter. Plan passes and bought passes add (MAX_PLUS_ADDONS, the plan’s drawn first); bought ones never expire or refill. Cancelling a litter within mistakeRefundHours of the grant returns the unit its stamp drew; a later cancel loses it.

Other services read the same pass, whether or not metering is on: joining, offering or accepting on a litter listing’s waitlist without one answers AnimalListing_Waitlist_AD_LitterPass_RJ (402, same purchase shape) today. The owner’s stamp clears it, so try the stamp before offering the purchase. A passed litter’s listing may take protected deposits on any plan (Protected deposits).

Contracts, once metering is on, are metered once, at create: POST /api/contract/v1/contracts reserves and confirms one CONTRACTS unit of the owning profile, from its bought packs, the soonest-expiring first. No plan includes contracts since 2026-10-12. Out of units it answers Contract_Signing_AD_Quota_RJ (402) with data.purchase = { "featureCode": "CONTRACTS", "quantity": 1 }: one purchase is one pack. Contracts sell in three packs, 10, 20 or 50 contracts (unitsPerPack on the price point), each lapsing 24 months after purchase (expiresAfterMonths 24). Name the pack with pricePointCode on POST /api/sub/v1/checkout/feature-credits; without it the cheapest pack (10) is sold. Packs stack. Prices: Platform prices. Updating, sending and signing draw nothing.

Breeder Pro was retired on 2026-10-12, and POST /api/sub/v1/checkout/plan-refill (its yearly bundle bought again) was removed with it: the route no longer exists. Grants a refill minted before then keep their effectiveExpiresAtUtc.

Mutations return a stable ENT-500xx code: ENT-50001 insufficient quantity, ENT-50003 definition inactive, ENT-50004 reservation required, ENT-50005 quantity out of range, ENT-50006 definition not found, ENT-50008 reservation expired. See Error handling for the envelope shape.