New Features
Checkout Session — metadata Parameter
checkout.create_session() now accepts an optional metadata parameter for attaching arbitrary key-value pairs to a checkout session. The metadata is returned verbatim on the checkout.completed webhook payload’s metadata field, letting you correlate a completed checkout back to your own records.metadata are preserved exactly as provided — they are not transformed on the way to the API, so they survive the round-trip back through webhooks unchanged.New Features
Subscription Update — trialEnd Parameter
subscriptions.update() now accepts an optional trialEnd parameter to control the trial period when updating a subscription.Pass either:- The literal string
"now"to end any active trial immediately. - An ISO 8601 datetime string (e.g.
"2025-12-31 23:59:59") to set a new trial end date. The datetime must be in the future. Naive datetimes are interpreted as UTC. - Omit the parameter to preserve the existing trial behavior on the subscription.
trialEnd client-side — invalid datetime strings or past datetimes raise InvalidRequestError before the request is sent.New Features
Checkout Session — New Optional Parameters
Three new optional parameters oncheckout.create_session() give you more control over the hosted checkout page.discounts_enabled — controls whether the coupon/discount code field is shown. Defaults to True on the server.lock_email — when True, the email field is pre-filled and locked so the customer cannot change it. Defaults to False.default_billing_country — ISO 3166-1 alpha-2 country code (e.g. "US", "GB") used to pre-fill the billing address country field.New Features
Webhook Verification
A newvalidate_event helper lets you securely verify incoming webhook requests from Kelviq in one step. It validates the HMAC-SHA256 signature using the three headers Kelviq attaches to every webhook delivery, then returns the parsed event dictionary.validate_event(payload, headers, secret)payload— Raw request body asbytesorstr. Must be the unparsed body — do not pass a pre-parsed dictionary.headers— Any mapping of header name to value (e.g.request.headersin Flask). Header lookup is case-insensitive.secret— Your webhook signing secret (kq_whsec_...) from the Kelviq dashboard.
Dict[str, Any]. Raises WebhookVerificationError if a required header is missing, the signature format is invalid, or the signature does not match.WebhookVerificationError
New exception class raised by validate_event when verification fails. Extends Exception.New Features
License Management Module
A newclient.license module provides full lifecycle management for software licenses. All methods are available in both synchronous and asynchronous clients.license.activate(licenseKey, customerId?, instanceName?, metadata?)Activates a license key and creates a new instance. Returns a LicenseActivateResponse (Pydantic model) containing the instanceId, activatedAt, expiresOn, and the full LicenseDetails object.license.deactivate(licenseKey, instanceId)Deactivates a specific license instance. Returns a LicenseDeactivateResponse with message and deactivatedAt.license.validate(licenseKey, instanceId?)Validates a license key and optionally a specific instance. Returns a LicenseValidateResponse with valid, code, detail, metadata, and the full LicenseDetails.New Pydantic Models
LicenseDetails— Full license object withid,licenseKey,activatedOn,expiresOn,activationUsage,activationLimit,enabled,customer,plan, andsubscription.LicenseCustomer—customerId,name,emailnested withinLicenseDetails.LicensePlan— Expanded withdescription,version,isLatest, andproduct(nestedLicensePlanProductmodel).LicensePlanProduct—id,identifier,name,taxCode,createdOn,modifiedOn.LicenseActivateResponse,LicenseDeactivateResponse,LicenseValidateResponse— Typed Pydantic response models for each operation.
SubscriptionData New Fields
Three new fields derived from the subscription’s recurrence string are now included in SubscriptionData (returned within LicenseDetails.subscription and customer subscription summaries):billingType—"SUBSCRIPTION"if the plan has a recurrence,"ONE_TIME"otherwise.recurrenceUnit— Integer unit from the recurrence string (e.g.1from"1 month"), orNone.recurrenceType— Recurrence period in uppercase (e.g."MONTH"), orNone.
New Features
Customer Portal Module
A newclient.portal module lets you create pre-authenticated customer portal sessions server-side and redirect customers directly to their self-serve portal. Available on both synchronous and asynchronous clients.portal.create_session(customerId)CreatePortalSessionResponse (Pydantic model) with:token(str) — Session token authenticating the portal session.email(str) — The customer’s email address.customerPortalUrl(str) — Pre-authenticated URL to redirect the customer to.
New Features
Entitlements Aggregation Engine
When a customer has multiple active subscriptions, the API can return duplicatefeatureId entries. The SDK now automatically aggregates them into a single Entitlement model while preserving the raw data.| Field | Aggregation Strategy |
|---|---|
hasAccess | True if any raw entry grants access |
usageLimit | Summed across all entries (for METER feature types) |
currentUsage | Summed across all entries (for METER feature types) |
remaining | Computed as usageLimit - currentUsage |
hardLimit | True if any entry has a hard limit |
Note:resetAtis intentionally not aggregated at the top level because each subscription item can have a different reset date. Access individual reset dates viaentitlement.items[i].resetAt.
New Entitlement Pydantic Model
A new model representing an aggregated entitlement:featureId,featureType,hasAccess,hardLimit,usageLimit,currentUsage,remainingitems: List[EntitlementDetail]— the raw entries that were aggregated into this model
get_entitlements(customerId) — All Entitlements as a Map
Returns a Dict[str, Entitlement] keyed by featureId. Each value is an aggregated model with an .items list containing the original raw entries.get_raw_entitlement(customerId, featureId) — Raw API Response for a Feature
Returns the raw API response (CheckEntitlementsResponse) for a specific feature without any aggregation.get_raw_entitlements(customerId) — Full Raw API Response
Returns the raw API response for all entitlements without any aggregation.Enum Helpers for IDE Autocompletion
Newstr-based Enum classes:ChargePeriod—ONE_TIME,MONTHLY,YEARLY,WEEKLY,DAILY,THREE_MONTHS,SIX_MONTHSCancellationType—IMMEDIATE,CURRENT_PERIOD_ENDS,SPECIFIC_DATE
"MONTHLY") continue to work everywhere — fully backward-compatible.Changed
get_entitlement(customerId, featureId)now returnsOptional[Entitlement](aggregated) instead of rawCheckEntitlementsResponse. Useget_raw_entitlement()for the original response.get_all_entitlementsremoved — Useget_entitlements()instead.resetAtremoved from top-levelEntitlement— Access individual reset dates via the.itemslist.
New Features
Entitlements Aggregation Engine
When a customer has multiple active subscriptions, the API can return duplicatefeatureId entries. The SDK now automatically aggregates them into a single Entitlement model while preserving the raw data.| Field | Aggregation Strategy |
|---|---|
hasAccess | True if any raw entry grants access |
usageLimit | Summed across all entries (for METER feature types) |
currentUsage | Summed across all entries (for METER feature types) |
remaining | Computed as usageLimit - currentUsage |
hardLimit | True if any entry has a hard limit |
Note:resetAtis intentionally not aggregated at the top level because each subscription item can have a different reset date. Access individual reset dates viaentitlement.items[i].resetAt.
New Entitlement Pydantic Model
A new model representing an aggregated entitlement:featureId,featureType,hasAccess,hardLimit,usageLimit,currentUsage,remainingitems: List[EntitlementDetail]— the raw entries that were aggregated into this model
get_entitlements(customerId) — All Entitlements as a Map
Returns a Dict[str, Entitlement] keyed by featureId. Each value is an aggregated model with an .items list containing the original raw entries.get_raw_entitlement(customerId, featureId) — Raw API Response for a Feature
Returns the raw API response (CheckEntitlementsResponse) for a specific feature without any aggregation. Includes the customerId wrapper.get_raw_entitlements(customerId) — Full Raw API Response
Returns the raw API response for all entitlements without any aggregation.Enum Helpers for IDE Autocompletion
Newstr-based Enum classes that improve developer experience with IDE autocompletion and prevent typos:ChargePeriod—ONE_TIME,MONTHLY,YEARLY,WEEKLY,DAILY,THREE_MONTHS,SIX_MONTHSCancellationType—IMMEDIATE,CURRENT_PERIOD_ENDS,SPECIFIC_DATE
"MONTHLY") continue to work everywhere — the enums are fully backward-compatible.Changed
get_entitlement(customerId, featureId)now returnsOptional[Entitlement](aggregated) instead of rawCheckEntitlementsResponse. Useget_raw_entitlement()if you need the original response.get_all_entitlementsremoved — Useget_entitlements()instead, which returns aDict[str, Entitlement]keyed byfeatureId.resetAtremoved from top-levelEntitlement— Access individual reset dates via the.itemslist.
Fixed
- Removed invalid JavaScript-style comments (
// Server-generated UUID) from JSON response blocks in documentation. - Fixed
//comments to#comments in Python code snippets. - Fixed trailing comma in Checkout response JSON block.
- Fixed typo: “newly created customer” → “updated customer” in
customers.updatereturn description. - Removed placeholder text from “Supported Functionalities” section.
- Updated entitlements description to explain multi-subscription aggregation and the
itemsattribute.