Skip to content

feat(clerk-js, localizations, ui): Add credits information in the user/org profile#8977

Open
l-armstrong wants to merge 9 commits into
mainfrom
lamone/bill-1613-add-credits-information-in-the-userorg-profile
Open

feat(clerk-js, localizations, ui): Add credits information in the user/org profile#8977
l-armstrong wants to merge 9 commits into
mainfrom
lamone/bill-1613-add-credits-information-in-the-userorg-profile

Conversation

@l-armstrong

@l-armstrong l-armstrong commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Display the C2's remaining account credit and their account credit history in the user/org profile.

Description

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Added an Account Credits section showing current credit balance in user and organization profile/billing views.
    • Added a Credit History page with navigation, localized table headers, and formatted transaction rows.
    • Introduced billing APIs, React hooks, and typed resources for credit balance and credit history.
  • Bug Fixes
    • Billing subscription data now includes the payer reference needed for credit views.
  • Documentation
    • Added new localization strings for account credits and credit history UI.

@vercel

vercel Bot commented Jun 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
clerk-js-sandbox Ready Ready Preview, Comment Jun 25, 2026 3:13pm
swingset Ready Ready Preview, Comment Jun 25, 2026 3:13pm

Request Review

@changeset-bot

changeset-bot Bot commented Jun 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: bb4f24b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 23 packages
Name Type
@clerk/localizations Minor
@clerk/clerk-js Minor
@clerk/shared Minor
@clerk/ui Minor
@clerk/react Patch
@clerk/chrome-extension Patch
@clerk/electron Patch
@clerk/expo Patch
@clerk/astro Patch
@clerk/backend Patch
@clerk/expo-passkeys Patch
@clerk/express Patch
@clerk/fastify Patch
@clerk/headless Patch
@clerk/hono Patch
@clerk/msw Patch
@clerk/nextjs Patch
@clerk/nuxt Patch
@clerk/react-router Patch
@clerk/tanstack-react-start Patch
@clerk/testing Patch
@clerk/vue Patch
@clerk/swingset Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 50b20d1a-00c3-45df-a156-aea0e268744b

📥 Commits

Reviewing files that changed from the base of the PR and between 697cf41 and bb4f24b.

📒 Files selected for processing (1)
  • .changeset/fancy-rats-stick.md
✅ Files skipped from review due to trivial changes (1)
  • .changeset/fancy-rats-stick.md

📝 Walkthrough

Walkthrough

The PR adds billing credit balance and history APIs, shared types/resources/hooks, UI sections and routes, localization entries, release metadata, and two bundlewatch threshold increases.

Changes

Billing credits

Layer / File(s) Summary
Billing credit API and resources
packages/shared/src/types/billing.ts, packages/shared/src/types/json.ts, packages/clerk-js/src/core/modules/billing/namespace.ts, packages/clerk-js/src/core/resources/BillingCreditBalance.ts, packages/clerk-js/src/core/resources/BillingCreditLedger.ts, packages/clerk-js/src/core/resources/BillingSubscription.ts, packages/clerk-js/src/core/resources/internal.ts
BillingNamespace gains credit balance/history methods and new credit DTO/resource types, while BillingSubscription now stores payerId.
Credit query hooks and cache keys
packages/shared/src/react/stable-keys.ts, packages/shared/src/react/hooks/index.ts, packages/shared/src/react/hooks/useCreditBalance.tsx, packages/shared/src/react/hooks/useCreditHistory.tsx, packages/ui/src/contexts/components/Plans.tsx
New credit cache keys and hook exports are added, and the UI billing hooks call the new credit balance/history queries with payer-scoped params.
Account credits section and labels
packages/shared/src/types/elementIds.ts, packages/shared/src/types/localization.ts, packages/localizations/src/en-US.ts, packages/ui/src/components/AccountCredits/AccountCredits.tsx, packages/ui/src/components/AccountCredits/index.ts, packages/ui/src/components/OrganizationProfile/OrganizationBillingPage.tsx, packages/ui/src/components/UserProfile/BillingPage.tsx, .changeset/fancy-rats-stick.md
Account credits labels are added to the localization contracts and English strings, the balance section component is introduced, and both billing pages render it.
Credit history page and routes
packages/ui/src/components/AccountCredits/CreditHistoryPage.tsx, packages/ui/src/components/OrganizationProfile/OrganizationProfileRoutes.tsx, packages/ui/src/components/UserProfile/UserProfileRoutes.tsx
The credit history page formats and displays credit ledger rows, and both billing route trees add a credit-history route.

Bundlewatch thresholds

Layer / File(s) Summary
Dist size limits
packages/clerk-js/bundlewatch.config.json
The maxSize values for dist/clerk.legacy.browser.js and dist/clerk.native.js are increased by 1KB each.

Sequence Diagram(s)

Included above in the hidden review stack artifact.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • paddycarver
  • mauricioabreu

Poem

A bunny found credits in a leafy green trail 🐇
Then hopped through the routes with a flick of the tail
The balance said “here,” and the history sang
While bundles grew comfy with a tiny size pang

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the PR’s main feature: adding credits information to user and organization profiles across clerk-js, localizations, and ui.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands.

@pkg-pr-new

pkg-pr-new Bot commented Jun 24, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@8977

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@8977

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@8977

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@8977

@clerk/electron

npm i https://pkg.pr.new/@clerk/electron@8977

@clerk/electron-passkeys

npm i https://pkg.pr.new/@clerk/electron-passkeys@8977

@clerk/eslint-plugin

npm i https://pkg.pr.new/@clerk/eslint-plugin@8977

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@8977

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@8977

@clerk/express

npm i https://pkg.pr.new/@clerk/express@8977

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@8977

@clerk/hono

npm i https://pkg.pr.new/@clerk/hono@8977

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@8977

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@8977

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@8977

@clerk/react

npm i https://pkg.pr.new/@clerk/react@8977

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@8977

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@8977

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@8977

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@8977

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@8977

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@8977

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@8977

commit: bb4f24b

@l-armstrong l-armstrong changed the title feat(clerk-js, localizations, ui): add credits information in the user/org profile feat(clerk-js, localizations, ui): Add credits information in the user/org profile Jun 24, 2026
@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

API Changes Report

Generated by Break Check on 2026-06-25T15:14:34.669Z

Summary

Metric Count
Packages analyzed 19
Packages with changes 1
🔴 Breaking changes 0
🟡 Non-breaking changes 2
🟢 Additions 28

🤖 This report was reviewed by claude-sonnet-4-6.


@clerk/shared

Current version: 4.21.0
Recommended bump: MINOR → 4.22.0

Subpath ./types

🟡 Non-breaking Changes (2)

Modified: __internal_LocalizationResource
Diff (before: 1943 lines, after: 1961 lines). Click to expand.
// ... 845 unchanged lines elided ...
      };
      billingPage: {
        title: LocalizationValue;
+       accountCreditsSection: {
+         title: LocalizationValue;
+         viewHistory: LocalizationValue;
+       };
+       creditHistoryPage: {
+         title: LocalizationValue;
+         tableHeader__amount: LocalizationValue;
+         tableHeader__date: LocalizationValue;
+       };
        start: {
          headerTitle__payments: LocalizationValue;
          headerTitle__plans: LocalizationValue;
          headerTitle__subscriptions: LocalizationValue;
          headerTitle__statements: LocalizationValue;
        };
        statementsSection: {
          empty: LocalizationValue;
          itemCaption__paidForPlan: LocalizationValue;
          itemCaption__proratedCredit: LocalizationValue;
          itemCaption__payerCredit: LocalizationValue;
          itemCaption__subscribedAndPaidForPlan: LocalizationValue;
          notFound: LocalizationValue;
          tableHeader__date: LocalizationValue;
          tableHeader__amount: LocalizationValue;
          title: LocalizationValue;
          totalPaid: LocalizationValue;
        };
        switchPlansSection: {
          title: LocalizationValue;
        };
        subscriptionsListSection: {
          tableHeader__plan: LocalizationValue;
          tableHeader__startDate: LocalizationValue;
          tableHeader__edit: LocalizationValue;
          title: LocalizationValue;
          actionLabel__newSubscription: LocalizationValue;
          actionLabel__manageSubscription: LocalizationValue;
          actionLabel__switchPlan: LocalizationValue;
          overview: LocalizationValue;
        };
        paymentHistorySection: {
          empty: LocalizationValue;
          notFound: LocalizationValue;
          tableHeader__date: LocalizationValue;
          tableHeader__amount: LocalizationValue;
          tableHeader__status: LocalizationValue;
        };
        paymentMethodsSection: {
          title: LocalizationValue;
          add: LocalizationValue;
          addSubtitle: LocalizationValue;
          cancelButton: LocalizationValue;
          actionLabel__default: LocalizationValue;
          actionLabel__remove: LocalizationValue;
          formButtonPrimary__add: LocalizationValue;
          formButtonPrimary__pay: LocalizationValue;
          removeMethod: {
            title: LocalizationValue;
            messageLine1: LocalizationValue<'identifier'>;
            messageLine2: LocalizationValue;
            successMessage: LocalizationValue<'paymentMethod'>;
          };
          payWithTestCardButton: LocalizationValue;
        };
        subscriptionsSection: {
          actionLabel__default: LocalizationValue;
        };
      };
      plansPage: {
        title: LocalizationValue;
        alerts: {
          noPermissionsToManageBilling: LocalizationValue;
        };
      };
    };
    userButton: {
      action__manageAccount: LocalizationValue;
      action__signOut: LocalizationValue;
      action__signOutAll: LocalizationValue;
      action__addAccount: LocalizationValue;
      action__openUserMenu: LocalizationValue;
      action__closeUserMenu: LocalizationValue;
      label__userButtonPopover?: LocalizationValue;
      label__accountActions?: LocalizationValue;
      label__activeSessions?: LocalizationValue;
    };
    organizationSwitcher: {
      personalWorkspace: LocalizationValue;
      notSelected: LocalizationValue;
      action__createOrganization: LocalizationValue;
      action__manageOrganization: LocalizationValue;
      action__invitationAccept: LocalizationValue;
      action__suggestionsAccept: LocalizationValue;
      action__openOrganizationSwitcher: LocalizationValue;
      action__closeOrganizationSwitcher: LocalizationValue;
      suggestionsAcceptedLabel: LocalizationValue;
    };
    impersonationFab: {
      title: LocalizationValue<'identifier'>;
      action__signOut: LocalizationValue;
    };
    organizationProfile: {
      navbar: {
        title: LocalizationValue;
        description: LocalizationValue;
        general: LocalizationValue;
        members: LocalizationValue;
        billing: LocalizationValue;
        apiKeys: LocalizationValue;
        security: LocalizationValue;
      };
      badge__unverified: LocalizationValue;
      badge__automaticInvitation: LocalizationValue;
      badge__automaticSuggestion: LocalizationValue;
      badge__manualInvitation: LocalizationValue;
      badge__enterpriseSso: LocalizationValue;
      start: {
        headerTitle__members: LocalizationValue;
        membershipSeatUsageLabel: LocalizationValue<'count' | 'limit'>;
        headerTitle__general: LocalizationValue;
        profileSection: {
          title: LocalizationValue;
          primaryButton: LocalizationValue;
          uploadAction__title: LocalizationValue;
        };
      };
      profilePage: {
        title: LocalizationValue;
        successMessage: LocalizationValue;
        dangerSection: {
          title: LocalizationValue;
          leaveOrganization: {
            title: LocalizationValue;
            messageLine1: LocalizationValue;
            messageLine2: LocalizationValue;
            successMessage: LocalizationValue;
            actionDescription: LocalizationValue<'organizationName'>;
          };
          deleteOrganization: {
            title: LocalizationValue;
            messageLine1: LocalizationValue;
            messageLine2: LocalizationValue;
            actionDescription: LocalizationValue<'organizationName'>;
            successMessage: LocalizationValue;
          };
        };
        domainSection: {
          title: LocalizationValue;
          subtitle: LocalizationValue;
          primaryButton: LocalizationValue;
          menuAction__verify: LocalizationValue;
          menuAction__remove: LocalizationValue;
          menuAction__manage: LocalizationValue;
        };
      };
      createDomainPage: {
        title: LocalizationValue;
        subtitle: LocalizationValue;
      };
      verifyDomainPage: {
        title: LocalizationValue;
        subtitle: LocalizationValue<'domainName'>;
        subtitleVerificationCodeScreen: LocalizationValue<'emailAddress'>;
        formTitle: LocalizationValue;
        formSubtitle: LocalizationValue;
        resendButton: LocalizationValue;
      };
      verifiedDomainPage: {
        title: LocalizationValue<'domain'>;
        subtitle: LocalizationValue<'domain'>;
        start: {
          headerTitle__enrollment: LocalizationValue;
          headerTitle__danger: LocalizationValue;
        };
        enrollmentTab: {
          subtitle: LocalizationValue;
          manualInvitationOption__label: LocalizationValue;
          manualInvitationOption__description: LocalizationValue;
          automaticInvitationOption__label: LocalizationValue;
          automaticInvitationOption__description: LocalizationValue;
          automaticSuggestionOption__label: LocalizationValue;
          automaticSuggestionOption__description: LocalizationValue;
          calloutInfoLabel: LocalizationValue;
          calloutInvitationCountLabel: LocalizationValue<'count'>;
          calloutSuggestionCountLabel: LocalizationValue<'count'>;
        };
        dangerTab: {
          removeDomainTitle: LocalizationValue;
          removeDomainSubtitle: LocalizationValue;
          removeDomainActionLabel__remove: LocalizationValue;
          calloutInfoLabel: LocalizationValue;
        };
      };
      invitePage: {
        title: LocalizationValue;
        subtitle: LocalizationValue;
        successMessage: LocalizationValue;
        detailsTitle__inviteFailed: LocalizationValue<'email_addresses'>;
        formButtonPrimary__continue: LocalizationValue;
        formButtonPrimary__purchaseSeats: LocalizationValue;
        selectDropdown__role: LocalizationValue;
      };
      removeDomainPage: {
        title: LocalizationValue;
        messageLine1: LocalizationValue<'domain'>;
        messageLine2: LocalizationValue;
        successMessage: LocalizationValue;
      };
      securityPage: {
        title: LocalizationValue;
        removeDialog: {
          title: LocalizationValue;
          subtitle: LocalizationValue;
          confirmButton: LocalizationValue;
        };
        ssoSection: {
          title: LocalizationValue;
          badge__unconfigured: LocalizationValue;
          badge__inProgress: LocalizationValue;
          badge__active: LocalizationValue;
          badge__inactive: LocalizationValue;
          descriptionLine1: LocalizationValue;
          primaryButton__startConfiguration: LocalizationValue;
          primaryButton__continueConfiguration: LocalizationValue;
          domainLabel: LocalizationValue;
          menuAction__edit: LocalizationValue;
          menuAction__activate: LocalizationValue;
          menuAction__deactivate: LocalizationValue;
          menuAction__remove: LocalizationValue;
          tooltip: LocalizationValue<'role'>;
          tooltip__noRole: LocalizationValue;
          tooltipLabel: LocalizationValue;
        };
      };
      membersPage: {
        detailsTitle__emptyRow: LocalizationValue;
        action__invite: LocalizationValue;
        action__search: LocalizationValue;
        start: {
          headerTitle__members: LocalizationValue;
          headerTitle__invitations: LocalizationValue;
          headerTitle__requests: LocalizationValue;
        };
        activeMembersTab: {
          tableHeader__user: LocalizationValue;
          tableHeader__joined: LocalizationValue;
          tableHeader__role: LocalizationValue;
          tableHeader__actions: LocalizationValue;
          menuAction__remove: LocalizationValue;
        };
        invitedMembersTab: {
          tableHeader__invited: LocalizationValue;
          menuAction__revoke: LocalizationValue;
        };
        invitationsTab: {
          table__emptyRow: LocalizationValue;
          autoInvitations: {
            headerTitle: LocalizationValue;
            headerSubtitle: LocalizationValue;
            primaryButton: LocalizationValue;
          };
        };
        requestsTab: {
          tableHeader__requested: LocalizationValue;
          menuAction__approve: LocalizationValue;
          menuAction__reject: LocalizationValue;
          table__emptyRow: LocalizationValue;
          autoSuggestions: {
            headerTitle: LocalizationValue;
            headerSubtitle: LocalizationValue;
            primaryButton: LocalizationValue;
          };
        };
        alerts: {
          roleSetMigrationInProgress: {
            title: LocalizationValue;
            subtitle: LocalizationValue;
          };
        };
      };
      billingPage: {
        title: LocalizationValue;
+       accountCreditsSection: {
+         title: LocalizationValue;
+         viewHistory: LocalizationValue;
+       };
+       creditHistoryPage: {
+         title: LocalizationValue;
+         tableHeader__amount: LocalizationValue;
+         tableHeader__date: LocalizationValue;
+       };
        start: {
          headerTitle__payments: LocalizationValue;
          headerTitle__plans: LocalizationValue;
// ... 819 unchanged lines elided ...

Static analyzer: Breaking change in type alias __internal_LocalizationResource: Type changed: {locale:string;maintenanceMode:import("@clerk/shared").LocalizationValue;roles:{[r:string]:import("@clerk/shared").Loca…{locale:string;maintenanceMode:import("@clerk/shared").LocalizationValue;roles:{[r:string]:import("@clerk/shared").Loca…

🤖 AI review (reclassified as non-breaking) (70%): The elided diff shows 1863 vs 1881 lines, suggesting new properties were added to __internal_LocalizationResource; since this type is used as the source for DeepPartial<DeepLocalizationWithoutObjects<__internal_LocalizationResource>> (an output/read type for LocalizationResource), additions to it do not break consumers who only read from it. However, if consumers author objects typed as __internal_LocalizationResource directly (input position), new required properties would be breaking. The full diff is elided so exact changes cannot be confirmed, but the pattern (adding localization keys) is consistent with additions only.

Modified: ProfileSectionId
- type ProfileSectionId = 'profile' | 'username' | 'emailAddresses' | 'phoneNumbers' | 'connectedAccounts' | 'enterpriseAccounts' | 'web3Wallets' | 'password' | 'passkeys' | 'mfa' | 'danger' | 'activeDevices' | 'organizationProfile' | 'organizationDanger' | 'organizationDomains' | 'manageVerifiedDomains' | 'subscriptionsList' | 'paymentMethods' | 'sso' | 'ssoStatus' | 'enableSso' | 'ssoDomain' | 'ssoConfiguration' | 'configureAgain' | 'resetSso' | 'testSsoUrl' | 'testResults';
+ type ProfileSectionId = 'profile' | 'username' | 'emailAddresses' | 'phoneNumbers' | 'connectedAccounts' | 'enterpriseAccounts' | 'web3Wallets' | 'password' | 'passkeys' | 'mfa' | 'danger' | 'activeDevices' | 'organizationProfile' | 'organizationDanger' | 'organizationDomains' | 'manageVerifiedDomains' | 'subscriptionsList' | 'paymentMethods' | 'sso' | 'ssoStatus' | 'enableSso' | 'ssoDomain' | 'ssoConfiguration' | 'configureAgain' | 'resetSso' | 'testSsoUrl' | 'testResults' | 'accountCredits';

Static analyzer: Breaking change in type alias ProfileSectionId: Type changed: 'activeDevices'|'configureAgain'|'connectedAccounts'|'danger'|'emailAddresses'|'enableSso'|'enterpriseAccounts'|'manage…'accountCredits'|'activeDevices'|'configureAgain'|'connectedAccounts'|'danger'|'emailAddresses'|'enableSso'|'enterprise…

🤖 AI review (reclassified as non-breaking) (90%): A new variant 'accountCredits' was added to the ProfileSectionId union; adding a union member is non-breaking for consumers who read values of this type, and ProfileSectionId appears only as a source for MenuId (a union type used as output/discriminator), so no consumer switch/exhaustiveness check is required by the public API contract.

🟢 Additions (28)

Click to expand 28 changes
Added: BillingCreditBalanceJSON
+ interface BillingCreditBalanceJSON

Added interface BillingCreditBalanceJSON

Added: BillingCreditBalanceJSON.balance
+ balance: BillingMoneyAmountJSON | null;

Added property BillingCreditBalanceJSON.balance

Added: BillingCreditBalanceJSON.object
+ object: 'commerce_credit_balance';

Added property BillingCreditBalanceJSON.object

Added: BillingCreditBalanceResource
+ interface BillingCreditBalanceResource

Added interface BillingCreditBalanceResource

Added: BillingCreditBalanceResource.balance
+ balance: BillingMoneyAmount | null;

Added property BillingCreditBalanceResource.balance

Added: BillingCreditLedgerJSON
+ interface BillingCreditLedgerJSON

Added interface BillingCreditLedgerJSON

Added: BillingCreditLedgerJSON.amount
+ amount: number;

Added property BillingCreditLedgerJSON.amount

Added: BillingCreditLedgerJSON.created_at
+ created_at: number;

Added property BillingCreditLedgerJSON.created_at

Added: BillingCreditLedgerJSON.currency
+ currency: string;

Added property BillingCreditLedgerJSON.currency

Added: BillingCreditLedgerJSON.id
+ id: string;

Added property BillingCreditLedgerJSON.id

Added: BillingCreditLedgerJSON.object
+ object: 'commerce_credit_ledger';

Added property BillingCreditLedgerJSON.object

Added: BillingCreditLedgerJSON.payer_id
+ payer_id: string;

Added property BillingCreditLedgerJSON.payer_id

Added: BillingCreditLedgerJSON.source_id
+ source_id: string;

Added property BillingCreditLedgerJSON.source_id

Added: BillingCreditLedgerJSON.source_type
+ source_type: string;

Added property BillingCreditLedgerJSON.source_type

Added: BillingCreditLedgerResource
+ interface BillingCreditLedgerResource

Added interface BillingCreditLedgerResource

Added: BillingCreditLedgerResource.amount
+ amount: number;

Added property BillingCreditLedgerResource.amount

Added: BillingCreditLedgerResource.createdAt
+ createdAt: Date;

Added property BillingCreditLedgerResource.createdAt

Added: BillingCreditLedgerResource.currency
+ currency: string;

Added property BillingCreditLedgerResource.currency

Added: BillingCreditLedgerResource.id
+ id: string;

Added property BillingCreditLedgerResource.id

Added: BillingCreditLedgerResource.payerId
+ payerId: string;

Added property BillingCreditLedgerResource.payerId

Added: BillingCreditLedgerResource.sourceId
+ sourceId: string;

Added property BillingCreditLedgerResource.sourceId

Added: BillingCreditLedgerResource.sourceType
+ sourceType: string;

Added property BillingCreditLedgerResource.sourceType

Added: BillingNamespace.getCreditBalance
+ getCreditBalance: (params: GetCreditBalanceParams) => Promise<BillingCreditBalanceResource>;

Added property BillingNamespace.getCreditBalance

Added: BillingNamespace.getCreditHistory
+ getCreditHistory: (params: GetCreditHistoryParams) => Promise<ClerkPaginatedResponse<BillingCreditLedgerResource>>;

Added property BillingNamespace.getCreditHistory

Added: BillingSubscriptionJSON.payer_id
+ payer_id: string;

Added property BillingSubscriptionJSON.payer_id

Added: BillingSubscriptionResource.payerId
+ payerId: string;

Added property BillingSubscriptionResource.payerId

Added: GetCreditBalanceParams
+ type GetCreditBalanceParams = {
+   orgId?: string;
+   payerId: string;
+ };

Added type alias GetCreditBalanceParams

Added: GetCreditHistoryParams
+ type GetCreditHistoryParams = {
+   orgId?: string;
+   payerId: string;
+ };

Added type alias GetCreditHistoryParams


Report generated by Break Check

Last ran on bb4f24b.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (5)
packages/clerk-js/src/core/resources/BillingCreditLedger.ts (1)

7-35: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

extends BaseResource appears unnecessary here.

BillingCreditLedger extends BaseResource but uses none of its capabilities (no _fetch, withDefault, etc.), while the sibling BillingCreditBalance is a plain class. For consistency and to avoid pulling in BaseResource plumbing, consider making this a plain class implementing BillingCreditLedgerResource. If the inheritance is intentional (e.g., a future need for BaseResource helpers), disregard.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/clerk-js/src/core/resources/BillingCreditLedger.ts` around lines 7 -
35, BillingCreditLedger is inheriting BaseResource without using any
BaseResource behavior, so simplify it for consistency with BillingCreditBalance.
Update the BillingCreditLedger class to be a plain class that still implements
BillingCreditLedgerResource, and keep the existing constructor/fromJSON
data-mapping logic intact. If there is no current or planned use of BaseResource
helpers in BillingCreditLedger, remove the inheritance so the class is
self-contained.
packages/shared/src/types/billing.ts (3)

960-969: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add the @experimental JSDoc block to GetCreditBalanceParams.

GetCreditHistoryParams (Line 974) carries the @experimental notice, but GetCreditBalanceParams does not. Keep them consistent since both are reference-facing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared/src/types/billing.ts` around lines 960 - 969, Add the missing
`@experimental` JSDoc block to GetCreditBalanceParams so it matches
GetCreditHistoryParams and stays consistent with the other reference-facing
billing types. Update the GetCreditBalanceParams type definition in billing.ts
to include the same experimental notice alongside its existing property docs,
without changing the shape of the type.

Source: Path instructions


985-996: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document BillingCreditLedgerResource properties.

Unlike BillingSubscriptionResource and BillingCreditBalanceResource, the ledger properties (amount, currency, sourceType, sourceId, etc.) have no JSDoc. These render in the generated Clerk reference docs, so per-property descriptions help avoid customer-facing docs drift; the Docs team may want to review. Also consider documenting that amount/currency are raw values here rather than a BillingMoneyAmount like the balance resource, since that asymmetry is easy to misuse downstream (e.g. formatting in the history page).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared/src/types/billing.ts` around lines 985 - 996, Document the
fields on BillingCreditLedgerResource with per-property JSDoc so the generated
Clerk reference docs have clear descriptions for id, payerId, amount, currency,
sourceType, sourceId, and createdAt. Use the BillingSubscriptionResource and
BillingCreditBalanceResource typings as the style reference, and add a note near
amount/currency that these are raw values here rather than a BillingMoneyAmount
to avoid misuse in downstream formatting. Keep the comments aligned with the
BillingCreditLedgerResource interface so the Docs team can review the updated
public API wording.

Source: Path instructions


86-98: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add @returns to the new method JSDoc for docs consistency.

Every other BillingNamespace method documents its return shape with @returns (see getStatements, getPlan, etc.), which the generated Clerk reference docs render. getCreditBalance and getCreditHistory omit it. Since these are reference-facing APIs, the Docs team may need to review.

📝 Proposed JSDoc
   /**
    * Gets the credit balance for the current payer.
    *
+   * `@returns` A [`BillingCreditBalanceResource`](/docs/reference/types/billing-credit-balance-resource) object.
+   *
    * `@experimental` This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes.
    */
   getCreditBalance: (params: GetCreditBalanceParams) => Promise<BillingCreditBalanceResource>;

   /**
    * Gets the credit history for the current payer.
    *
+   * `@returns` A [`ClerkPaginatedResponse`](/docs/reference/types/clerk-paginated-response) of [`BillingCreditLedgerResource`](/docs/reference/types/billing-credit-ledger-resource) objects.
+   *
    * `@experimental` This is an experimental API for the Billing feature that is available under a public beta, and the API is subject to change. It is advised to [pin](https://clerk.com/docs/pinning) the SDK version and the clerk-js version to avoid breaking changes.
    */
   getCreditHistory: (params: GetCreditHistoryParams) => Promise<ClerkPaginatedResponse<BillingCreditLedgerResource>>;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/shared/src/types/billing.ts` around lines 86 - 98, Add `@returns`
JSDoc entries to the BillingNamespace methods getCreditBalance and
getCreditHistory in billing.ts so they match the rest of the namespace docs.
Keep the existing experimental notes, and document the return shapes for
BillingCreditBalanceResource and
ClerkPaginatedResponse<BillingCreditLedgerResource> in the same JSDoc blocks so
the generated reference docs include them consistently.

Sources: Coding guidelines, Path instructions

packages/ui/src/contexts/components/Plans.tsx (1)

98-114: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add explicit return types to the new exported hooks.

useCreditBalance and useCreditHistory are exported but lack explicit return types. Annotating them with the underlying result types (e.g. CreditBalanceResult / the credit-history query result) keeps the public surface self-documenting and stable.

As per coding guidelines: "Always define explicit return types for functions, especially public APIs".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ui/src/contexts/components/Plans.tsx` around lines 98 - 114, Add
explicit return type annotations to the exported hooks in Plans.tsx.
`useCreditBalance` and `useCreditHistory` are public APIs, so update their
signatures to return the appropriate underlying result types instead of relying
on inference. Use the existing symbols `useCreditBalance`, `useCreditHistory`,
`__experimental_useCreditBalance`, and `__internal_useCreditHistoryQuery` to
match the hook result types already returned.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/clerk-js/src/core/resources/BillingSubscription.ts`:
- Line 39: The BillingSubscription model currently declares payerId as non-null
even though it is assigned from backend data.payer_id in the resource
initializer, so it can be undefined at runtime if the response omits that field.
Update the payerId typing and assignment in BillingSubscription (including the
related parsing/serialization path around the class constructor or load method)
to reflect the actual API contract: either make payerId optional or provide a
safe default, and ensure any downstream accessors or consumers that rely on
payerId handle the missing case correctly.

In `@packages/ui/src/components/AccountCredits/CreditHistoryPage.tsx`:
- Line 23: Add an explicit return type to the exported CreditHistoryPage
component so its signature is unambiguous; update the CreditHistoryPage function
declaration itself to return JSX.Element (or the project’s equivalent React
component return type) rather than relying on inference.

---

Nitpick comments:
In `@packages/clerk-js/src/core/resources/BillingCreditLedger.ts`:
- Around line 7-35: BillingCreditLedger is inheriting BaseResource without using
any BaseResource behavior, so simplify it for consistency with
BillingCreditBalance. Update the BillingCreditLedger class to be a plain class
that still implements BillingCreditLedgerResource, and keep the existing
constructor/fromJSON data-mapping logic intact. If there is no current or
planned use of BaseResource helpers in BillingCreditLedger, remove the
inheritance so the class is self-contained.

In `@packages/shared/src/types/billing.ts`:
- Around line 960-969: Add the missing `@experimental` JSDoc block to
GetCreditBalanceParams so it matches GetCreditHistoryParams and stays consistent
with the other reference-facing billing types. Update the GetCreditBalanceParams
type definition in billing.ts to include the same experimental notice alongside
its existing property docs, without changing the shape of the type.
- Around line 985-996: Document the fields on BillingCreditLedgerResource with
per-property JSDoc so the generated Clerk reference docs have clear descriptions
for id, payerId, amount, currency, sourceType, sourceId, and createdAt. Use the
BillingSubscriptionResource and BillingCreditBalanceResource typings as the
style reference, and add a note near amount/currency that these are raw values
here rather than a BillingMoneyAmount to avoid misuse in downstream formatting.
Keep the comments aligned with the BillingCreditLedgerResource interface so the
Docs team can review the updated public API wording.
- Around line 86-98: Add `@returns` JSDoc entries to the BillingNamespace methods
getCreditBalance and getCreditHistory in billing.ts so they match the rest of
the namespace docs. Keep the existing experimental notes, and document the
return shapes for BillingCreditBalanceResource and
ClerkPaginatedResponse<BillingCreditLedgerResource> in the same JSDoc blocks so
the generated reference docs include them consistently.

In `@packages/ui/src/contexts/components/Plans.tsx`:
- Around line 98-114: Add explicit return type annotations to the exported hooks
in Plans.tsx. `useCreditBalance` and `useCreditHistory` are public APIs, so
update their signatures to return the appropriate underlying result types
instead of relying on inference. Use the existing symbols `useCreditBalance`,
`useCreditHistory`, `__experimental_useCreditBalance`, and
`__internal_useCreditHistoryQuery` to match the hook result types already
returned.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Repository UI (inherited)

Review profile: CHILL

Plan: Pro Plus

Run ID: 2e63fbf1-9fc8-4594-b074-906d797443be

📥 Commits

Reviewing files that changed from the base of the PR and between 8024cac and e050888.

📒 Files selected for processing (23)
  • packages/clerk-js/bundlewatch.config.json
  • packages/clerk-js/src/core/modules/billing/namespace.ts
  • packages/clerk-js/src/core/resources/BillingCreditBalance.ts
  • packages/clerk-js/src/core/resources/BillingCreditLedger.ts
  • packages/clerk-js/src/core/resources/BillingSubscription.ts
  • packages/clerk-js/src/core/resources/internal.ts
  • packages/localizations/src/en-US.ts
  • packages/shared/src/react/hooks/index.ts
  • packages/shared/src/react/hooks/useCreditBalance.tsx
  • packages/shared/src/react/hooks/useCreditHistory.tsx
  • packages/shared/src/react/stable-keys.ts
  • packages/shared/src/types/billing.ts
  • packages/shared/src/types/elementIds.ts
  • packages/shared/src/types/json.ts
  • packages/shared/src/types/localization.ts
  • packages/ui/src/components/AccountCredits/AccountCredits.tsx
  • packages/ui/src/components/AccountCredits/CreditHistoryPage.tsx
  • packages/ui/src/components/AccountCredits/index.ts
  • packages/ui/src/components/OrganizationProfile/OrganizationBillingPage.tsx
  • packages/ui/src/components/OrganizationProfile/OrganizationProfileRoutes.tsx
  • packages/ui/src/components/UserProfile/BillingPage.tsx
  • packages/ui/src/components/UserProfile/UserProfileRoutes.tsx
  • packages/ui/src/contexts/components/Plans.tsx

Comment thread packages/clerk-js/src/core/resources/BillingSubscription.ts
Comment thread packages/ui/src/components/AccountCredits/CreditHistoryPage.tsx Outdated
Comment thread .changeset/fancy-rats-stick.md Outdated
'@clerk/ui': minor
---

Display the C2s Account Credits in the user/org profile.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💭 Maybe we should mention Billing somewhere here

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also keep in mind that "C2" is an internal term, and likely not recognizable to our end users

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants