Skip to content

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

Merged
dstaley merged 20 commits into
mainfrom
lamone/bill-1613-add-credits-information-in-the-userorg-profile
Jun 30, 2026
Merged

feat(clerk-js, localizations, ui): Add credits information in the user/org profile#8977
dstaley merged 20 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 to user and organization billing/subscriptions views, showing the current credit balance.
    • Added a Credit History page with navigation, loading state, and a localized table of credit ledger entries.
  • Bug Fixes
    • Billing subscription data now includes the payer reference needed to load credit views correctly.
  • Documentation
    • Added new localization strings for the Account Credits section and Credit History page (titles and table headers).

@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 30, 2026 4:24pm
swingset Ready Ready Preview, Comment Jun 30, 2026 4:24pm

Request Review

@changeset-bot

changeset-bot Bot commented Jun 24, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 2878666

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

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

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

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 config update
packages/clerk-js/bundlewatch.config.json
The bundlewatch file entry for ./dist/coinbase*.js is replaced without changing the size limit.

Sequence Diagram(s)

Included above in the hidden review stack artifact.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • mauricioabreu
  • paddycarver

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 got a tiny config-clang

🚥 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 summarizes the main feature: adding credits information to the user and organization profile.
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.

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

@l-armstrong l-armstrong changed the title feat: add credits information in the user/org profile feat(clerk-js, localizations, ui): add credits information in the user/org profile Jun 24, 2026
@l-armstrong l-armstrong force-pushed the lamone/bill-1613-add-credits-information-in-the-userorg-profile branch from f51ea07 to 68ba47e Compare June 24, 2026 19:24
@mauricioabreu mauricioabreu marked this pull request as ready for review June 24, 2026 20:35
@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-30T16:26:40.543Z

Summary

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

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


@clerk/shared

Current version: 4.22.1
Recommended bump: MINOR → 4.23.0

Subpath ./types

🟡 Non-breaking Changes (2)

Modified: __internal_LocalizationResource
Diff (before: 1947 lines, after: 1965 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;
// ... 823 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) (75%): The diff shows 1885 lines vs 1867 lines elided, indicating new fields were added to __internal_LocalizationResource; since LocalizationResource is defined as DeepPartial<DeepLocalizationWithoutObjects<__internal_LocalizationResource>>, this type is used as an output/definition base and consumers only provide partial overrides — new required fields on the internal type become optional on the public LocalizationResource input type via DeepPartial, so existing consumer code constructing LocalizationResource objects is unaffected.

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 variant to a union type used as an output/discriminator is non-breaking for consumers who only read values of this type, and the usage in MenuId merely extends the union further, so no existing well-typed consumer code that handles known variants is broken by the addition.

🟢 Additions (22)

Click to expand 22 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: BillingMoneyAmountJSON;

Added property BillingCreditLedgerJSON.amount

Added: BillingCreditLedgerJSON.created_at
+ created_at: number;

Added property BillingCreditLedgerJSON.created_at

Added: BillingCreditLedgerJSON.id
+ id: string;

Added property BillingCreditLedgerJSON.id

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

Added property BillingCreditLedgerJSON.object

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: BillingMoneyAmount;

Added property BillingCreditLedgerResource.amount

Added: BillingCreditLedgerResource.createdAt
+ createdAt: Date;

Added property BillingCreditLedgerResource.createdAt

Added: BillingCreditLedgerResource.id
+ id: string;

Added property BillingCreditLedgerResource.id

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: GetCreditBalanceParams
+ type GetCreditBalanceParams = {
+   orgId?: string;
+ };

Added type alias GetCreditBalanceParams

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

Added type alias GetCreditHistoryParams


Report generated by Break Check

Last ran on 2878666.

@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 Outdated
Comment thread packages/ui/src/components/AccountCredits/CreditHistoryPage.tsx Outdated
Comment on lines +35 to +39
<ProfileSection.Button
id='accountCredits'
localizationKey={localizationKeys(`${localizationRoot}.billingPage.accountCreditsSection.viewHistory`)}
sx={[t => ({ justifyContent: 'start', height: t.sizes.$8 })]}
onClick={() => void navigate('credit-history')}

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.

I think this is fine for now, but we should iterate on it because we now have three different types of buttons on the same page:

  1. Icon, label, no arrow
  2. Icon, label, arrow on hover
  3. No icon, label, no arrow on hover

Would be nice to have some consistent logic being used here for when a button needs an icon, and when it should show an arrow.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@dstaley dstaley merged commit 4306146 into main Jun 30, 2026
51 checks passed
@dstaley dstaley deleted the lamone/bill-1613-add-credits-information-in-the-userorg-profile branch June 30, 2026 17:25
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