Billing
Use Clerk.billing in your Android application to list Clerk Billing Plans and read billing information for a user or Organization, including their Subscription, statements, payment attempts, and credit balance. Billing methods are suspend functions that return ClerkResult, so handle both ClerkResult.Success and ClerkResult.Failure.
import com.clerk.api.Clerk
import com.clerk.api.network.serialization.ClerkResult
when (val result = Clerk.billing.getPlans()) {
is ClerkResult.Success -> {
val plans = result.value.data
}
is ClerkResult.Failure -> {
// Show an error state.
}
}The rest of the examples on this page use successOrElse { return } from com.clerk.api.network.serialization to return early on failure.
Check whether Billing is enabled
Clerk.commerceSettings reflects the Billing settings from the Clerk Dashboard. Use it to hide Billing UI when Billing isn't enabled for users or Organizations. Before the SDK loads the environment, it reports Billing as disabled.
val billing = Clerk.commerceSettings.billing
if (billing.user.enabled) {
// Show Billing UI for the user.
}
if (billing.organization.hasPaidPlans) {
// Show paid Plans for Organizations.
}Check Plan and Feature access
Use Clerk.has() to check whether the signed-in user or their has a Plan or Feature. It returns a Boolean synchronously, and it returns false when no user is signed in or the session isn't active.
if (Clerk.has(plan = "gold")) {
// Show content for the Gold Plan.
}
if (Clerk.has(feature = "widgets")) {
// Show the widgets Feature.
}A Plan or Feature slug without a prefix matches either the user's or the Active Organization's Subscription. Prefix it with user: or org: to check only one of them (e.g., org:widgets).
has() reads Plans and Features from the claims of the current session token, so a Subscription change is reflected after the token refreshes. For Role, Permission, and reverification checks, see Authorization checks.
Plans
List Plans
getPlans() lists your publicly visible Plans. Plans are for users by default. Pass forPayer = ForPayerType.ORGANIZATION to list Organization Plans.
val plans = Clerk.billing.getPlans(forPayer = ForPayerType.ORGANIZATION).successOrElse { return }.data
for (plan in plans) {
println("${plan.name} ${plan.fee?.amountFormatted} ${plan.features.map { it.name }}")
}BillingPlan includes the Plan's fee, annualMonthlyFee, features, and free trial settings. Amounts are BillingMoneyAmount values, which include a display-ready amountFormatted string and a currencySymbol.
Get a Plan
val plan = Clerk.billing.getPlan(id = "cplan_123").successOrElse { return }Subscriptions
Get a Subscription
getSubscription() returns the signed-in user's Subscription. Pass an Organization ID to get that Organization's Subscription instead.
val subscription = Clerk.billing.getSubscription().successOrElse { return }
val organizationSubscription = Clerk.billing.getSubscription(orgId = organization.id).successOrElse { return }A BillingSubscription contains one or more subscriptionItems, one per Plan. Each item has its own plan, planPeriod, status, and nextPayment. Dates such as nextPayment.date are Unix timestamps in milliseconds.
for (item in subscription.subscriptionItems) {
if (item.status != BillingSubscriptionStatus.ACTIVE) continue
println("${item.plan.name} ${item.planPeriod} ${item.nextPayment?.amount?.amountFormatted}")
}
subscription.nextPayment?.let { nextPayment ->
println("Next payment of ${nextPayment.amount.amountFormatted} on ${Instant.ofEpochMilli(nextPayment.date)}")
}val statements = Clerk.billing.getStatements().successOrElse { return }.data
for (statement in statements) {
println("${Instant.ofEpochMilli(statement.timestamp)} ${statement.totals.grandTotal.amountFormatted}")
}val statement = Clerk.billing.getStatement(id = "stmt_123").successOrElse { return }val payments = Clerk.billing.getPaymentAttempts().successOrElse { return }.data
for (payment in payments) {
println("${payment.amount.amountFormatted} ${payment.status}")
}val payment = Clerk.billing.getPaymentAttempt(id = "payment_123").successOrElse { return }Payment methods
Payment methods are listed from the payer: User for the signed-in user and Organization for an Organization.
val user = Clerk.user ?: return
val paymentMethods = user.getPaymentMethods().successOrElse { return }.data
for (paymentMethod in paymentMethods) {
println("${paymentMethod.cardType} ${paymentMethod.last4} ${paymentMethod.isDefault}")
}
val organizationPaymentMethods = organization.getPaymentMethods().successOrElse { return }.dataval creditBalance = Clerk.billing.getCreditBalance().successOrElse { return }
val balance = creditBalance.balance?.amountFormattedval entries = Clerk.billing.getCreditHistory().successOrElse { return }.dataOrganization Billing
Every method that reads a payer's Billing data accepts an optional orgId. Omit it to read the signed-in user's data, or pass an Organization ID to read that Organization's data. The user needs the org:sys_billing:read Permission in that Organization. Check it with organizationMembership.canReadBilling.
val organization = Clerk.organization ?: return
if (Clerk.organizationMembership?.canReadBilling != true) return
val statements = Clerk.billing.getStatements(orgId = organization.id).successOrElse { return }.dataPagination
List methods return a ClerkPaginatedResponse with the page's data and the totalCount across all pages. Use limit and offset to request a page. The defaults are limit = 20 and offset = 0.
val response = Clerk.billing.getStatements(limit = 20, offset = 20).successOrElse { return }
val statements = response.data
val hasMore = 20 + response.data.size < response.totalCountFeedback
Last updated on