From fa53b9b686e642e7e2f0735c842f5a9661b30c33 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 8 Jul 2025 12:25:23 +0300 Subject: [PATCH 01/36] add billing guide and reference page --- docs/custom-flows/checkout-new-payment.mdx | 147 ++++++++++ docs/hooks/use-checkout.mdx | 297 +++++++++++++++++++++ 2 files changed, 444 insertions(+) create mode 100644 docs/custom-flows/checkout-new-payment.mdx create mode 100644 docs/hooks/use-checkout.mdx diff --git a/docs/custom-flows/checkout-new-payment.mdx b/docs/custom-flows/checkout-new-payment.mdx new file mode 100644 index 0000000000..9e96a379af --- /dev/null +++ b/docs/custom-flows/checkout-new-payment.mdx @@ -0,0 +1,147 @@ +--- +title: Build a custom checkout flow for a new payment method +description: Learn how to use the Clerk API to build a custom checkout flow for a new payment method. +--- + + + +This guide will walk you through how to build a custom checkout flow with a new payment method. + + + ## Enable billing features + + To use billing features, you first need to ensure they are enabled for your application. Please follow the [Billing documentation](/docs/billing/overview) to enable them and setup your plans. + + ## Checkout flow + + To create a checkout session with a new payment card, you must: + + 1. Set up the checkout provider with plan details. + 1. Initialize the checkout session when the user is ready. + 1. Render the payment form for card collection. + 1. Confirm the payment with the collected payment method. + 1. Complete the checkout process and redirect the user. + + + + The following example: + + 1. Uses the [`useCheckout()`](/docs/hooks/use-checkout) hook to get to initiate and manage the checkout session. + 1. Uses the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to control the payment element, which is rendered by ``. + 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways. + 1. Copy from the Clerk Dashboard. + 1. Use the [Clerk Backend API](TBD). + 1. Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. + + This example is written for Next.js App Router but can be adapted for any React-based framework. + + ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 9], 13, 15, [20, 21], 23, 31,33, 39, 53, [63, 72], 82] }} + 'use client' + import * as React from 'react' + import { + CheckoutProvider, + useCheckout, + PaymentElementProvider, + PaymentElementForm, + usePaymentElement, + } from '@clerk/nextjs' + import { useRouter } from 'next/navigation' + + export default function CheckoutPage() { + return ( + + + + ) + } + + function CustomCheckout() { + const { checkout } = useCheckout() + const { status } = checkout + + if (status === 'awaiting_initialization') { + return + } + + return ( +
+ + + + + +
+ ) + } + + function CheckoutInitialization() { + const { start, status, fetchStatus } = useCheckout() + + return ( + + ) + } + + function PaymentSection() { + const { checkout } = useCheckout() + + const { isConfirming, confirm, complete, error } = checkout + + const { isFormReady, submit, isProviderReady } = usePaymentElement() + const [isProcessing, setIsProcessing] = React.useState(false) + const router = useRouter() + + const handleSubmit = async (e) => { + e.preventDefault() + if (!isFormReady || isProcessing) return + setIsProcessing(true) + + try { + // Submit payment form to get payment method + const { data, error } = await submit() + // Usually a validation error from stripe that you can ignore + if (error) { + return + } + // Confirm checkout with payment method + await confirm(data) + // Complete checkout and redirect + await complete({ redirectUrl: '/dashboard' }) + } catch (error) { + console.error('Payment failed:', error) + } finally { + setIsProcessing(false) + } + } + + return ( +
+ } /> + + {error &&
{error.message}
} + + + + ) + } + + function CheckoutSummary() { + const { checkout } = useCheckout() + const { plan, totals } = checkout + + return ( +
+

Order Summary

+ {plan?.name} + \({totals?.totalDueNow.amountFormatted}\) +
+ ) + } + ``` +
+
+
diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx new file mode 100644 index 0000000000..58828523cc --- /dev/null +++ b/docs/hooks/use-checkout.mdx @@ -0,0 +1,297 @@ +--- +title: useCheckout() +description: Clerk's useCheckout() hook provides state and methods to manage a subscription checkout flow. +--- + +The `useCheckout()` hook is the primary tool for managing checkout flows. It can be used to create, manage, and confirm a checkout session for a user or an organization's subscription plan. The hook provides the state of the current checkout process, such as its status and any errors, along with methods to initiate and complete the checkout. + +`useCheckout()` can be used in two ways: + +1. In conjunction with the [``](#checkout-components-and-hooks), which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. +2. As a standalone hook by passing configuration options directly to it. This is ideal for self-contained components that manage their own checkout flow. + +## Parameters + +The `useCheckout()` hook accepts an optional options object. These options are **required** if the hook is used without a `` wrapping your component tree. + + + * `options?` + * [`UseCheckoutOptions`](#usecheckoutoptions) + + An object containing the configuration for the checkout flow. + + +### `UseCheckoutOptions` + + + * `for?` + * `'organization'` + + Specifies that the checkout is for an organization. If omitted, the checkout defaults to the current user. + + *** + + * `planId` + * `string` + + The ID of the subscription plan to check out (e.g., `cplan_xxxx`). + + *** + + * `planPeriod` + * `'monthly' | 'yearly'` + + The billing period for the plan. + + +## Returns + +The hook returns an object containing a `checkout` object with the current state and methods to control the flow. + + + * `checkout` + * `object` + + An object containing the checkout resource properties, state helpers, and methods. + + +The `checkout` object contains the following: + +### Resource Properties + +These properties describe the checkout resource itself. They are `null` until the checkout process is started by calling the `start()` method. + + + * `id` + * `string | null` + + The unique identifier for the checkout resource. + + *** + * `paymentSource` + * `object | null` + + The payment source being used for the checkout. + + *** + * `plan` + * `object | null` + + The subscription plan details for the checkout. + + *** + * `externalClientSecret` + * `string | null` + + The client secret from an external payment provider, like Stripe, used to complete the payment on the client-side. + + *** + * `planPeriod` + * `'monthly' | 'yearly' | null` + + The billing period for the plan. + + *** + * `planPeriodStart` + * `Date | null` + + The start date of the plan period. + + *** + * `totals` + * `object | null` + + An object containing the total costs, taxes, and other pricing details. + + *** + * `isImmediatePlanChange` + * `boolean | null` + + Indicates if the plan change will take effect immediately. + + +### State Helpers + +These properties provide information about the current state of the hook's operations. + + + * `status` + * `'idle' | 'starting' | 'confirming' | 'complete' | 'error'` + + The current status of the checkout flow. + + *** + * `isStarting` + * `boolean` + + Returns `true` when the `start()` method is in progress. + + *** + * `isConfirming` + * `boolean` + + Returns `true` when the `confirm()` method is in progress. + + *** + * `error` + * `ClerkAPIResponseError | null` + + An error object if any part of the checkout process fails. + + *** + * `fetchStatus` + * `'idle' | 'fetching' | 'error'` + + The data fetching status for the checkout resource. + + +### Methods + +These methods are used to control the checkout flow. + + + * `start()` + * `() => Promise` + + Initializes the checkout process by creating a checkout resource on the server. + + *** + * `confirm()` + * `(params: ConfirmCheckoutParams) => Promise` + + Confirms the checkout, typically after the user has entered payment details. + + *** + * `complete()` + * `(params?: { redirectUrl: string }) => void` + + Finalizes the checkout process. Can optionally accept a `redirectUrl` to navigate the user to upon completion. + + *** + * `clear()` + * `() => void` + + Clears the current checkout state from the cache. + + +## Examples + +The `useCheckout()` hook can be used with a context provider for managing state across multiple components or as a standalone hook for more isolated use cases. + +", "Standalone Hook"]}> + + ### With `` + + Using the `` is the recommended approach when checkout state needs to be shared across multiple components. The provider is configured once, and any child component can access the checkout context by calling `useCheckout()`. + + The following example shows a `` that sets up the provider and a `` component that consumes the context to manage the checkout UI. + + + + ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} + import { CheckoutProvider } from '@clerk/clerk-react'; // Fictional import path + import { CheckoutFlow } from './CheckoutFlow'; + + export function SubscriptionPage() { + // The provider sets the context for the checkout flow. + // Any child component can now call `useCheckout()` to access this context. + return ( + +
+

Upgrade Your Plan

+

You are about to subscribe to our monthly plan.

+ +
+
+ ); + } + ``` +
+ + ```tsx {{ filename: 'src/components/CheckoutFlow.tsx', collapsible: true }} + import { useCheckout } from '@clerk/clerk-react'; // Fictional import path + + export function CheckoutFlow() { + // `useCheckout` reads context from the nearest `` + const { checkout } = useCheckout(); + const { start, status, isStarting, error } = checkout; + + const handleStartCheckout = async () => { + try { + // This will create the checkout session on the backend + await start(); + // Next steps would involve using a payment element (e.g., Stripe) + // and then calling `checkout.confirm()` and `checkout.complete()`. + } catch (e) { + console.error('Error starting checkout:', e); + } + }; + + return ( +
+

Current status: {status}

+ + {error && ( +

Error: {error.errors[0].message}

+ )} + {status === 'starting' &&

Redirecting to payment...

} +
+ ); + } + ``` +
+
+
+ + ### Standalone Hook + + For simple, self-contained components, you can use `useCheckout()` by passing the configuration options directly to the hook. This avoids the need to wrap the component in a provider. + + The following example shows an `` component that manages its own checkout flow. + + ```tsx {{ filename: 'src/components/UpgradeButton.tsx' }} + import { useCheckout } from '@clerk/clerk-react'; // Fictional import path + + export function UpgradeButton({ planId, planPeriod }) { + // Pass options directly to the hook when not using a provider. + const { checkout } = useCheckout({ + planId, + planPeriod, + for: 'user', + }); + + const { start, status, isStarting, error } = checkout; + + const handleStartCheckout = async () => { + try { + await start(); + // In a real app, you would now use the `externalClientSecret` + // from the checkout object to render a payment form. + console.log('Checkout started! Status:', checkout.status); + } catch (e) { + console.error('Error starting checkout:', e); + } + }; + + return ( +
+ + {error && ( +

Error: {error.errors[0].message}

+ )} +
+ ); + } + ``` +
+
\ No newline at end of file From 1b0b52afdff095c1ab8b581772e54bb734f9f8a8 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 8 Jul 2025 12:34:10 +0300 Subject: [PATCH 02/36] fix build --- ...yment.mdx => checkout-new-payment-method.mdx} | 4 ++-- docs/hooks/use-checkout.mdx | 4 ++-- docs/manifest.json | 16 ++++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) rename docs/custom-flows/{checkout-new-payment.mdx => checkout-new-payment-method.mdx} (94%) diff --git a/docs/custom-flows/checkout-new-payment.mdx b/docs/custom-flows/checkout-new-payment-method.mdx similarity index 94% rename from docs/custom-flows/checkout-new-payment.mdx rename to docs/custom-flows/checkout-new-payment-method.mdx index 9e96a379af..54b0393448 100644 --- a/docs/custom-flows/checkout-new-payment.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -27,11 +27,11 @@ This guide will walk you through how to build a custom checkout flow with a new The following example: 1. Uses the [`useCheckout()`](/docs/hooks/use-checkout) hook to get to initiate and manage the checkout session. - 1. Uses the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to control the payment element, which is rendered by ``. + 1. Uses the `usePaymentElement()` hook to control the payment element, which is rendered by ``. 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways. 1. Copy from the Clerk Dashboard. 1. Use the [Clerk Backend API](TBD). - 1. Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. + 1. Use the new `usePlans()` hook to get the plan details. This example is written for Next.js App Router but can be adapted for any React-based framework. diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 58828523cc..3d5e923015 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -7,7 +7,7 @@ The `useCheckout()` hook is the primary tool for managing checkout flows. It can `useCheckout()` can be used in two ways: -1. In conjunction with the [``](#checkout-components-and-hooks), which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. +1. In conjunction with the , which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. 2. As a standalone hook by passing configuration options directly to it. This is ideal for self-contained components that manage their own checkout flow. ## Parameters @@ -16,7 +16,7 @@ The `useCheckout()` hook accepts an optional options object. These options are * * `options?` - * [`UseCheckoutOptions`](#usecheckoutoptions) + * [`UseCheckoutOptions`](#use-checkout-options) An object containing the configuration for the checkout flow. diff --git a/docs/manifest.json b/docs/manifest.json index f90f2d40a4..37d4357225 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1076,6 +1076,11 @@ "title": "`useReverification()`", "wrap": false, "href": "/docs/hooks/use-reverification" + }, + { + "title": "`useCheckout()`", + "wrap": false, + "href": "/docs/hooks/use-checkout" } ] ] @@ -3781,6 +3786,17 @@ ] ] }, + { + "title": "Billing", + "items": [ + [ + { + "title": "Checkout with a new payment method", + "href": "/docs/custom-flows/checkout-new-payment-method" + } + ] + ] + }, { "title": "Account updates", "items": [ From 0ca1396697d8a969e62e68871a78aed5ab64c157 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 8 Jul 2025 12:38:41 +0300 Subject: [PATCH 03/36] format --- .../checkout-new-payment-method.mdx | 2 +- docs/hooks/use-checkout.mdx | 196 +++++++++--------- 2 files changed, 102 insertions(+), 96 deletions(-) diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index 54b0393448..12c26ffeae 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -35,7 +35,7 @@ This guide will walk you through how to build a custom checkout flow with a new This example is written for Next.js App Router but can be adapted for any React-based framework. - ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 9], 13, 15, [20, 21], 23, 31,33, 39, 53, [63, 72], 82] }} + ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 9], 14, 16, [21, 22], 24, 32, 34, 40, 54, [64, 73], 83] }} 'use client' import * as React from 'react' import { diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 3d5e923015..16c160f929 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -7,16 +7,16 @@ The `useCheckout()` hook is the primary tool for managing checkout flows. It can `useCheckout()` can be used in two ways: -1. In conjunction with the , which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. -2. As a standalone hook by passing configuration options directly to it. This is ideal for self-contained components that manage their own checkout flow. +1. In conjunction with the , which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. +1. As a standalone hook by passing configuration options directly to it. This is ideal for self-contained components that manage their own checkout flow. ## Parameters The `useCheckout()` hook accepts an optional options object. These options are **required** if the hook is used without a `` wrapping your component tree. - * `options?` - * [`UseCheckoutOptions`](#use-checkout-options) + - `options?` + - [`UseCheckoutOptions`](#use-checkout-options) An object containing the configuration for the checkout flow. @@ -24,22 +24,22 @@ The `useCheckout()` hook accepts an optional options object. These options are * ### `UseCheckoutOptions` - * `for?` - * `'organization'` + - `for?` + - `'organization'` Specifies that the checkout is for an organization. If omitted, the checkout defaults to the current user. - *** + --- - * `planId` - * `string` + - `planId` + - `string` The ID of the subscription plan to check out (e.g., `cplan_xxxx`). - *** + --- - * `planPeriod` - * `'monthly' | 'yearly'` + - `planPeriod` + - `'monthly' | 'yearly'` The billing period for the plan. @@ -49,8 +49,8 @@ The `useCheckout()` hook accepts an optional options object. These options are * The hook returns an object containing a `checkout` object with the current state and methods to control the flow. - * `checkout` - * `object` + - `checkout` + - `object` An object containing the checkout resource properties, state helpers, and methods. @@ -62,50 +62,57 @@ The `checkout` object contains the following: These properties describe the checkout resource itself. They are `null` until the checkout process is started by calling the `start()` method. - * `id` - * `string | null` + - `id` + - `string | null` The unique identifier for the checkout resource. - *** - * `paymentSource` - * `object | null` + --- + + - `paymentSource` + - `object | null` The payment source being used for the checkout. - *** - * `plan` - * `object | null` + --- + + - `plan` + - `object | null` The subscription plan details for the checkout. - *** - * `externalClientSecret` - * `string | null` + --- + + - `externalClientSecret` + - `string | null` The client secret from an external payment provider, like Stripe, used to complete the payment on the client-side. - *** - * `planPeriod` - * `'monthly' | 'yearly' | null` + --- + + - `planPeriod` + - `'monthly' | 'yearly' | null` The billing period for the plan. - *** - * `planPeriodStart` - * `Date | null` + --- + + - `planPeriodStart` + - `Date | null` The start date of the plan period. - *** - * `totals` - * `object | null` + --- + + - `totals` + - `object | null` An object containing the total costs, taxes, and other pricing details. - *** - * `isImmediatePlanChange` - * `boolean | null` + --- + + - `isImmediatePlanChange` + - `boolean | null` Indicates if the plan change will take effect immediately. @@ -115,32 +122,36 @@ These properties describe the checkout resource itself. They are `null` until th These properties provide information about the current state of the hook's operations. - * `status` - * `'idle' | 'starting' | 'confirming' | 'complete' | 'error'` + - `status` + - `'idle' | 'starting' | 'confirming' | 'complete' | 'error'` The current status of the checkout flow. - *** - * `isStarting` - * `boolean` + --- + + - `isStarting` + - `boolean` Returns `true` when the `start()` method is in progress. - *** - * `isConfirming` - * `boolean` + --- + + - `isConfirming` + - `boolean` Returns `true` when the `confirm()` method is in progress. - *** - * `error` - * `ClerkAPIResponseError | null` + --- + + - `error` + - `ClerkAPIResponseError | null` An error object if any part of the checkout process fails. - *** - * `fetchStatus` - * `'idle' | 'fetching' | 'error'` + --- + + - `fetchStatus` + - `'idle' | 'fetching' | 'error'` The data fetching status for the checkout resource. @@ -150,26 +161,29 @@ These properties provide information about the current state of the hook's opera These methods are used to control the checkout flow. - * `start()` - * `() => Promise` + - `start()` + - `() => Promise` Initializes the checkout process by creating a checkout resource on the server. - *** - * `confirm()` - * `(params: ConfirmCheckoutParams) => Promise` + --- + + - `confirm()` + - `(params: ConfirmCheckoutParams) => Promise` Confirms the checkout, typically after the user has entered payment details. - *** - * `complete()` - * `(params?: { redirectUrl: string }) => void` + --- + + - `complete()` + - `(params?: { redirectUrl: string }) => void` Finalizes the checkout process. Can optionally accept a `redirectUrl` to navigate the user to upon completion. - *** - * `clear()` - * `() => void` + --- + + - `clear()` + - `() => void` Clears the current checkout state from the cache. @@ -189,47 +203,44 @@ The `useCheckout()` hook can be used with a context provider for managing state ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} - import { CheckoutProvider } from '@clerk/clerk-react'; // Fictional import path - import { CheckoutFlow } from './CheckoutFlow'; + import { CheckoutProvider } from '@clerk/clerk-react' // Fictional import path + import { CheckoutFlow } from './CheckoutFlow' export function SubscriptionPage() { // The provider sets the context for the checkout flow. // Any child component can now call `useCheckout()` to access this context. return ( - +

Upgrade Your Plan

You are about to subscribe to our monthly plan.

- ); + ) } ```
+ ```tsx {{ filename: 'src/components/CheckoutFlow.tsx', collapsible: true }} - import { useCheckout } from '@clerk/clerk-react'; // Fictional import path + import { useCheckout } from '@clerk/clerk-react' // Fictional import path export function CheckoutFlow() { // `useCheckout` reads context from the nearest `` - const { checkout } = useCheckout(); - const { start, status, isStarting, error } = checkout; + const { checkout } = useCheckout() + const { start, status, isStarting, error } = checkout const handleStartCheckout = async () => { try { // This will create the checkout session on the backend - await start(); + await start() // Next steps would involve using a payment element (e.g., Stripe) // and then calling `checkout.confirm()` and `checkout.complete()`. } catch (e) { - console.error('Error starting checkout:', e); + console.error('Error starting checkout:', e) } - }; + } return (
@@ -237,17 +248,16 @@ The `useCheckout()` hook can be used with a context provider for managing state - {error && ( -

Error: {error.errors[0].message}

- )} + {error &&

Error: {error.errors[0].message}

} {status === 'starting' &&

Redirecting to payment...

}
- ); + ) } ```
+ ### Standalone Hook @@ -256,7 +266,7 @@ The `useCheckout()` hook can be used with a context provider for managing state The following example shows an `` component that manages its own checkout flow. ```tsx {{ filename: 'src/components/UpgradeButton.tsx' }} - import { useCheckout } from '@clerk/clerk-react'; // Fictional import path + import { useCheckout } from '@clerk/clerk-react' // Fictional import path export function UpgradeButton({ planId, planPeriod }) { // Pass options directly to the hook when not using a provider. @@ -264,34 +274,30 @@ The `useCheckout()` hook can be used with a context provider for managing state planId, planPeriod, for: 'user', - }); + }) - const { start, status, isStarting, error } = checkout; + const { start, status, isStarting, error } = checkout const handleStartCheckout = async () => { try { - await start(); + await start() // In a real app, you would now use the `externalClientSecret` // from the checkout object to render a payment form. - console.log('Checkout started! Status:', checkout.status); + console.log('Checkout started! Status:', checkout.status) } catch (e) { - console.error('Error starting checkout:', e); + console.error('Error starting checkout:', e) } - }; + } return (
- {error && ( -

Error: {error.errors[0].message}

- )} + {error &&

Error: {error.errors[0].message}

}
- ); + ) } ```
- \ No newline at end of file + From fc60f8c9065040b223d618976218aacef1d96cad Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 8 Jul 2025 13:10:50 +0300 Subject: [PATCH 04/36] add payment element --- .../checkout-new-payment-method.mdx | 2 +- docs/hooks/use-payment-element.mdx | 171 ++++++++++++++++++ docs/manifest.json | 5 + 3 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 docs/hooks/use-payment-element.mdx diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index 12c26ffeae..fe90c23e12 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -27,7 +27,7 @@ This guide will walk you through how to build a custom checkout flow with a new The following example: 1. Uses the [`useCheckout()`](/docs/hooks/use-checkout) hook to get to initiate and manage the checkout session. - 1. Uses the `usePaymentElement()` hook to control the payment element, which is rendered by ``. + 1. Uses the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to control the payment element, which is rendered by ``. 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways. 1. Copy from the Clerk Dashboard. 1. Use the [Clerk Backend API](TBD). diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx new file mode 100644 index 0000000000..759173e4b2 --- /dev/null +++ b/docs/hooks/use-payment-element.mdx @@ -0,0 +1,171 @@ +--- +title: usePaymentElement() +description: Clerk's usePaymentElement() hook provides methods and state for interacting with a payment form. +--- + +The `usePaymentElement()` hook is used to control the payment form rendered by the `` component. It provides the necessary state and methods to submit payment details to a payment provider like Stripe. + +This hook must be used within a component that is a descendant of the `` component. It is typically used in a checkout flow that prompts a user to add a new payment method, or for adding a new payment method outside of a checkout. + +## Payment Element Components + +The `usePaymentElement()` hook works in conjunction with the `` and `` components. + +### `` + +This provider component sets up the context for the payment element. It fetches all the necessary data from the payment provider (e.g., Stripe) and makes it available to its children. + + + - `checkout?` + - `CommerceCheckoutResource` + + An optional checkout resource object. When provided, the payment element is scoped to the specific checkout session. + + --- + + - `for?` + - `'user' | 'org'` + + Specifies whether the payment method is being added for a user or an organization. Defaults to `'user'`. + + --- + + - `stripeAppearance?` + - `object` + + An optional object to customize the appearance of the Stripe Payment Element. This allows you to match the form's styling to your application's theme. + + --- + + - `paymentDescription?` + - `string` + + An optional description to display to the user within the payment element UI. + + +### `` + +This component renders the actual payment form from the provider (e.g., the Stripe Payment Element). It should be rendered as a child of ``. + + + - `fallback?` + - `ReactNode` + + Optional fallback content, such as a loading skeleton, to display while the payment form is being initialized. + + +## Parameters + +The `usePaymentElement()` hook does not accept any parameters. It derives its state and configuration from the nearest ``. + +## Returns + +The hook returns an object containing state helpers and methods to interact with the payment form. + + + - `submit` + - `() => Promise<{ data: { gateway: 'stripe'; paymentToken: string } | null; error: PaymentElementError | null}>` + + A function that submits the payment form data to the payment provider. It returns a promise that resolves with either a `data` object containing a payment token on success, or an `error` object on failure. + + --- + + - `reset` + - `() => Promise` + + A function that resets the payment form to its initial, empty state. + + --- + + - `isFormReady` + - `boolean` + + Returns `true` when the payment form UI has been rendered and is ready for user input. This is useful for disabling a submit button until the form is interactive. + + --- + + - `isProviderReady` + - `boolean` + + Returns `true` when the underlying payment provider (e.g., Stripe.js) has been fully initialized. + + --- + + - `provider` + - `{ name: 'stripe' } | undefined` + + An object containing information about the initialized payment provider. It is `undefined` until `isProviderReady` is `true`. + + +## Examples + +The following example demonstrates the basic structure for adding a new payment method. A parent component, ``, sets up the provider and renders the form. A child component, ``, uses the `usePaymentElement()` hook to handle the form submission. + + + + ```tsx {{ filename: 'src/components/AddPaymentMethodView.tsx' }} + import { PaymentElementProvider, PaymentElementForm } from '@clerk/nextjs' + import { PaymentForm } from './PaymentForm' + import { PaymentFormSkeleton } from './PaymentFormSkeleton' + + export function AddPaymentMethodView() { + // The provider configures the payment context for a user. + return ( + +

Add a new payment method

+

Your payment details will be saved securely for future purchases.

+ + {/* The form component renders the payment UI */} + }> + {/* The child component handles form interaction */} + + +
+ ) + } + ``` +
+ + + ```tsx {{ filename: 'src/components/PaymentForm.tsx' }} + import { usePaymentElement } from '@clerk/nextjs' + import { useState } from 'react' + + export function PaymentForm() { + // The hook provides the state and methods to control the form. + const { submit, isFormReady, isProviderReady } = usePaymentElement() + const [isSubmitting, setIsSubmitting] = useState(false) + + const handleSubmit = async (e: React.FormEvent) => { + e.preventDefault() + if (!isFormReady) { + return + } + + setIsSubmitting(true) + setError(null) + + const { data, error } = await submit() + + // Usually a validation error from stripe that you can ignore + if (error) { + setIsSubmitting(false) + return + } + + console.log('Payment token created:', data.paymentToken) + setIsSubmitting(false) + } + + return ( +
+ {/* The actual payment fields are rendered by */} + + + ) + } + ``` +
+
diff --git a/docs/manifest.json b/docs/manifest.json index 37d4357225..03c277fa4f 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1081,6 +1081,11 @@ "title": "`useCheckout()`", "wrap": false, "href": "/docs/hooks/use-checkout" + }, + { + "title": "`usePaymentElement()`", + "wrap": false, + "href": "/docs/hooks/use-payment-element" } ] ] From aa288dff67ff0d53ac5ded5ccb1a981c7179ac7f Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 8 Jul 2025 13:37:46 +0300 Subject: [PATCH 05/36] add payment method guide --- docs/custom-flows/add-new-payment-methods.mdx | 114 ++++++++++++++++++ docs/manifest.json | 4 + 2 files changed, 118 insertions(+) create mode 100644 docs/custom-flows/add-new-payment-methods.mdx diff --git a/docs/custom-flows/add-new-payment-methods.mdx b/docs/custom-flows/add-new-payment-methods.mdx new file mode 100644 index 0000000000..5b9efbeedb --- /dev/null +++ b/docs/custom-flows/add-new-payment-methods.mdx @@ -0,0 +1,114 @@ +--- +title: Add a new payment method +description: Learn how to use Clerk's components to allow users to add a new payment method to their account. +--- + + + +This guide will walk you through how to build a flow for adding a new payment method. This is a common feature in a user's billing or account settings page, allowing them to pre-emptively add a payment method for future use. + + + ### Enable billing features + + To use billing features, you first need to ensure they are enabled for your application. Please follow the [Billing documentation](/docs/billing/overview) to enable them and set up your plans. + + ### Add payment method flow + + To add a new payment method for a user, you must: + + 1. Set up the [``](/docs/hooks/use-payment-element) to create a context for the user's payment actions. + 1. Render the [``](/docs/hooks/use-payment-element) to display the secure payment fields from your provider. + 1. Use the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to submit the form and create a payment token. + 1. Use the [`useUser()`](/docs/hooks/use-user) hook to attach the newly created payment method to the user. + + + + The following example demonstrates how to create a billing page where a user can add a new payment method. It is split into two components: + + - **``**: This component sets up the ``. + - **``**: This component renders the payment form and handles the submission logic using the `usePaymentElement` and `useUser` hooks. + + + + This component is responsible for setting up the provider context. It specifies that the payment actions within its children are `for` the `user`. + + ```tsx {{ filename: 'src/components/UserBillingPage.tsx' }} + import { PaymentElementProvider } from '@clerk/nextjs' + import { AddPaymentMethodForm } from './AddPaymentMethodForm' + + export function UserBillingPage() { + return ( +
+

Billing Settings

+

Manage your saved payment methods.

+ + + + +
+ ) + } + ``` +
+ + + This component contains the form and the logic to handle the submission. It uses `usePaymentElement` to get the `submit` function and `useUser` to get the `user` object. When the form is submitted, it first creates a payment token and then attaches it to the user. + + ```tsx {{ filename: 'src/components/AddPaymentMethodForm.tsx' }} + import { usePaymentElement, useUser, PaymentElementForm } from '@clerk/nextjs' + import { useState } from 'react' + + export function AddPaymentMethodForm() { + const { user } = useUser() + const { submit, isFormReady } = usePaymentElement() + const [isSubmitting, setIsSubmitting] = useState(false) + const [error, setError] = useState(null) + + const handleAddPaymentMethod = async (e: React.FormEvent) => { + e.preventDefault() + if (!isFormReady || !user) { + return + } + + setError(null) + setIsSubmitting(true) + + try { + // 1. Submit the form to the payment provider to get a payment token + const { data, error } = await submit() + + // Usually a validation error from stripe that you can ignore. + if (error) { + setIsSubmitting(false) + return + } + + // 2. Use the token to add the payment source to the user + await user.addPaymentSource(result.data) + + // 3. Handle success (e.g., show a confirmation, clear the form) + alert('Payment method added successfully!') + } catch (err: any) { + setError(err.message || 'An unexpected error occurred.') + } finally { + setIsSubmitting(false) + } + } + + return ( +
+

Add a new payment method

+ + + {error &&

{error}

} + + ) + } + ``` +
+
+
+
+
diff --git a/docs/manifest.json b/docs/manifest.json index 03c277fa4f..8df0a80a04 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -3798,6 +3798,10 @@ { "title": "Checkout with a new payment method", "href": "/docs/custom-flows/checkout-new-payment-method" + }, + { + "title": "Add a new payment method", + "href": "/docs/custom-flows/add-new-payment-methods" } ] ] From ae95ca121234f0eda420d0b878392e93e7aa5927 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 9 Jul 2025 14:14:44 +0300 Subject: [PATCH 06/36] fix incorrect usage --- docs/custom-flows/checkout-new-payment-method.mdx | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index fe90c23e12..d58d350eff 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -49,7 +49,7 @@ This guide will walk you through how to build a custom checkout flow with a new export default function CheckoutPage() { return ( - + ) @@ -77,21 +77,23 @@ This guide will walk you through how to build a custom checkout flow with a new function CheckoutInitialization() { const { start, status, fetchStatus } = useCheckout() + if (status === 'awaiting_initialization') { + return + } + return ( - ) } function PaymentSection() { const { checkout } = useCheckout() - const { isConfirming, confirm, complete, error } = checkout - const { isFormReady, submit, isProviderReady } = usePaymentElement() + const { isFormReady, submit } = usePaymentElement() const [isProcessing, setIsProcessing] = React.useState(false) - const router = useRouter() const handleSubmit = async (e) => { e.preventDefault() From 4acef190b799e7dc508a068f474399bdb7436bc6 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 9 Jul 2025 18:34:32 +0300 Subject: [PATCH 07/36] example with existing methods --- .../checkout-existing-payment-method.mdx | 169 +++++++++++ docs/hooks/use-payment-methods.mdx | 266 ++++++++++++++++++ docs/manifest.json | 9 + 3 files changed, 444 insertions(+) create mode 100644 docs/custom-flows/checkout-existing-payment-method.mdx create mode 100644 docs/hooks/use-payment-methods.mdx diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx new file mode 100644 index 0000000000..8110f605a0 --- /dev/null +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -0,0 +1,169 @@ +--- +title: Build a custom checkout flow with an existing payment method +description: Learn how to use the Clerk API to build a custom checkout flow using an existing payment method. +--- + + + +This guide will walk you through how to build a custom checkout flow using an existing payment method. + + + ## Enable billing features + + To use billing features, you first need to ensure they are enabled for your application. Please follow the [Billing documentation](/docs/billing/overview) to enable them and setup your plans. + + ## Checkout flow + + To create a checkout session with an existing payment method, you must: + + 1. Set up the checkout provider with plan details. + 1. Initialize the checkout session when the user is ready. + 1. Fetch and display the user's existing payment methods. + 1. Confirm the payment with the selected payment method. + 1. Complete the checkout process and redirect the user. + + + + The following example: + + 1. Uses the [`useCheckout()`](/docs/hooks/use-checkout) hook to initiate and manage the checkout session. + 1. Uses the [`usePaymentMethods()`](/docs/hooks/use-payment-methods) hook to fetch the user's existing payment methods. + 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways: + 1. Copy from the Clerk Dashboard. + 1. Use the [Clerk Backend API](TBD). + 1. Use the new `usePlans()` hook to get the plan details. + + This example is written for Next.js App Router but can be adapted for any React-based framework. + + ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 8], 13, 14, 16, 17, 22, [25, 27], [54, 57], [70, 76], [101, 103]] }} + 'use client' + import * as React from 'react' + import { + __experimental_CheckoutProvider as CheckoutProvider, + __experimental_useCheckout as useCheckout, + __experimental_usePaymentMethods as usePaymentMethods, + SignedIn, + } from '@clerk/nextjs' + import { useMemo, useState } from 'react' + + export default function CheckoutPage() { + return ( + + + + + + ) + } + + function CustomCheckout() { + const { checkout } = useCheckout() + const { status } = checkout + + if (status === 'awaiting_initialization') { + return + } + + return ( +
+ + +
+ ) + } + + function CheckoutInitialization() { + const { checkout } = useCheckout() + const { start, status, fetchStatus } = checkout + + if (status !== 'awaiting_initialization') { + return null + } + + return ( + + ) + } + + function PaymentSection() { + const { checkout } = useCheckout() + const { data, isLoading } = usePaymentMethods({ + for: 'user', + pageSize: 20, + }) + + const { isConfirming, confirm, complete, error } = checkout + + const [isProcessing, setIsProcessing] = useState(false) + const [selectedMethod, setSelectedMethod] = useState<(typeof data)[number] | null>(null) + + const defaultMethod = useMemo(() => data?.find((method) => method.isDefault), [data]) + + const submitSelectedMethod = async () => { + if (isProcessing) return + setIsProcessing(true) + + try { + // Confirm checkout with payment method + await confirm({ + paymentSourceId: (selectedMethod || defaultMethod)?.id, + }) + // Complete checkout and redirect + await complete({ redirectUrl: '/dashboard' }) + } catch (error) { + console.error('Payment failed:', error) + } finally { + setIsProcessing(false) + } + } + + if (isLoading) { + return
Loading...
+ } + + return ( + <> + + + {error &&
{error.message}
} + + + + ) + } + + function CheckoutSummary() { + const { checkout } = useCheckout() + const { plan, totals } = checkout + + return ( +
+

Order Summary

+ {plan?.name} + \({totals?.totalDueNow.amountFormatted}\) +
+ ) + } + ``` +
+
+
diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx new file mode 100644 index 0000000000..da98a459a0 --- /dev/null +++ b/docs/hooks/use-payment-methods.mdx @@ -0,0 +1,266 @@ +--- +title: '`usePaymentMethods()`' +description: Access and manage payment methods in your React application with Clerk's usePaymentMethods() hook. +--- + +The `usePaymentMethods()` hook provides access to the payment methods associated with a user or organization. It returns a paginated list of payment methods and includes methods for managing them. + +## Parameters + +`usePaymentMethods()` accepts a single object with the following properties: + + + - `for?` + - `'user' | 'organization'` + + Specifies whether to fetch payment methods for the current user or organization. Defaults to `'user'`. + + --- + + - `pageSize?` + - `number` + + The number of payment methods to fetch per page. Defaults to `10`. + + --- + + - `initialPage?` + - `number` + + The page number to start fetching from. Defaults to `1`. + + --- + + - `infinite?` + - `boolean` + + When `true`, enables infinite pagination mode where new pages are appended to existing data. When `false`, each page replaces the previous data. Defaults to `false`. + + --- + + - `keepPreviousData?` + - `boolean` + + When `true`, the previous data will be kept while loading the next page. This helps prevent layout shifts. Defaults to `false`. + + +## Returns + +The hook returns an object with the following properties: + + + - `data` + - `PaymentMethod[] | null` + + An array of payment method objects, or `null` if the data hasn't been loaded yet. + + --- + + - `isLoading` + - `boolean` + + `true` while the initial data is being fetched. + + --- + + - `isFetching` + - `boolean` + + `true` while any request is in flight, including background updates. + + --- + + - `hasNextPage` + - `boolean` + + `true` if there are more pages available to load. + + --- + + - `hasPreviousPage` + - `boolean` + + `true` if there are previous pages available to load. + + --- + + - `fetchNext` + - `() => Promise` + + Function to fetch the next page of payment methods. + + --- + + - `fetchPrevious` + - `() => Promise` + + Function to fetch the previous page of payment methods. + + --- + + - `pageCount` + - `number` + + The total number of available pages. + + --- + + - `count` + - `number` + + The total number of payment methods available. + + +### `PaymentMethod` + +Each payment method object contains the following properties: + + + - `id` + - `string` + + The unique identifier for the payment method. + + --- + + - `type` + - `'card'` + + The type of payment method. Currently, only card payments are supported. + + --- + + - `cardType` + - `string` + + The type of card (e.g., 'visa', 'mastercard'). + + --- + + - `last4` + - `string` + + The last 4 digits of the card number. + + --- + + - `expirationDate` + - `string` + + The expiration date of the card in 'MM/YY' format. + + --- + + - `isDefault` + - `boolean` + + Whether this is the default payment method. + + +## Examples + +### Basic Usage + +The following example shows how to fetch and display a user's payment methods: + +```tsx +import { usePaymentMethods } from '@clerk/nextjs' + +function PaymentMethodsList() { + const { data, isLoading } = usePaymentMethods({ + for: 'user', + pageSize: 10, + }) + + if (isLoading) { + return
Loading payment methods...
+ } + + return ( +
    + {data?.map((method) => ( +
  • + {method.cardType} **** {method.last4} + {method.isDefault ? ' (Default)' : null} +
  • + ))} +
+ ) +} +``` + +### Infinite Pagination + +This example demonstrates how to implement infinite scrolling with payment methods: + +```tsx +import { usePaymentMethods } from '@clerk/nextjs' + +function InfinitePaymentMethods() { + const { data, isLoading, hasNextPage, fetchNext } = usePaymentMethods({ + for: 'user', + infinite: true, + pageSize: 20, + }) + + if (isLoading) { + return
Loading...
+ } + + return ( +
+
    + {data?.map((method) => ( +
  • + {method.cardType} ending in {method.last4} +
    + Expires: {method.expirationDate} +
  • + ))} +
+ + {hasNextPage && } +
+ ) +} +``` + +### With Checkout Flow + +Here's an example of using `usePaymentMethods` in a checkout flow to select an existing payment method: + +```tsx +import { usePaymentMethods, useCheckout } from '@clerk/nextjs' + +function CheckoutPaymentSelection() { + const { data, isLoading } = usePaymentMethods({ for: 'user' }) + const { checkout } = useCheckout() + const { confirm, complete } = checkout + + const handlePaymentSubmit = async (paymentMethodId: string) => { + try { + // Confirm checkout with selected payment method + await confirm({ paymentSourceId: paymentMethodId }) + // Complete checkout and redirect + await complete({ redirectUrl: '/dashboard' }) + } catch (error) { + console.error('Payment failed:', error) + } + } + + if (isLoading) { + return
Loading payment methods...
+ } + + return ( +
+

Select a payment method

+ {data?.map((method) => ( + + ))} +
+ ) +} +``` diff --git a/docs/manifest.json b/docs/manifest.json index 8df0a80a04..ee03598009 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1086,6 +1086,11 @@ "title": "`usePaymentElement()`", "wrap": false, "href": "/docs/hooks/use-payment-element" + }, + { + "title": "`usePaymentMethods()`", + "wrap": false, + "href": "/docs/hooks/use-payment-methods" } ] ] @@ -3799,6 +3804,10 @@ "title": "Checkout with a new payment method", "href": "/docs/custom-flows/checkout-new-payment-method" }, + { + "title": "Checkout with an existing payment method", + "href": "/docs/custom-flows/checkout-existing-payment-method" + }, { "title": "Add a new payment method", "href": "/docs/custom-flows/add-new-payment-methods" From ce5d418e6d649822e08ca3e1484c43086e25ec33 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 9 Jul 2025 18:48:51 +0300 Subject: [PATCH 08/36] include control components --- .../checkout-existing-payment-method.mdx | 11 ++++++---- .../checkout-new-payment-method.mdx | 10 +++++++-- docs/hooks/use-checkout.mdx | 21 +++++++++++++++++++ 3 files changed, 36 insertions(+), 6 deletions(-) diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index 8110f605a0..1a2a044a9f 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -35,7 +35,7 @@ This guide will walk you through how to build a custom checkout flow using an ex This example is written for Next.js App Router but can be adapted for any React-based framework. - ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 8], 13, 14, 16, 17, 22, [25, 27], [54, 57], [70, 76], [101, 103]] }} + ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 9], 14, 15, 17, 18, 23, [26, 28], [55, 58], [71, 77], [102, 104]] }} 'use client' import * as React from 'react' import { @@ -43,15 +43,18 @@ This guide will walk you through how to build a custom checkout flow using an ex __experimental_useCheckout as useCheckout, __experimental_usePaymentMethods as usePaymentMethods, SignedIn, + ClerkLoaded, } from '@clerk/nextjs' import { useMemo, useState } from 'react' export default function CheckoutPage() { return ( - - - + + + + + ) } diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index d58d350eff..4635d732ee 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -35,7 +35,7 @@ This guide will walk you through how to build a custom checkout flow with a new This example is written for Next.js App Router but can be adapted for any React-based framework. - ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 9], 14, 16, [21, 22], 24, 32, 34, 40, 54, [64, 73], 83] }} + ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 11], 16, 18, [23, 24], 26, 34, 36, 42, 56, [66, 75], 85] }} 'use client' import * as React from 'react' import { @@ -44,13 +44,19 @@ This guide will walk you through how to build a custom checkout flow with a new PaymentElementProvider, PaymentElementForm, usePaymentElement, + SignedIn, + ClerkLoaded, } from '@clerk/nextjs' import { useRouter } from 'next/navigation' export default function CheckoutPage() { return ( - + + + + + ) } diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 16c160f929..608ba37a20 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -5,6 +5,27 @@ description: Clerk's useCheckout() hook provides state and methods to manage a s The `useCheckout()` hook is the primary tool for managing checkout flows. It can be used to create, manage, and confirm a checkout session for a user or an organization's subscription plan. The hook provides the state of the current checkout process, such as its status and any errors, along with methods to initiate and complete the checkout. +> [!IMPORTANT] +> For the best user experience and to prevent potential errors, always wrap components using `useCheckout()` with both `` and `` components. This ensures that the user is properly authenticated and Clerk is fully initialized before accessing checkout functionality. +> +> ```tsx +> import { ClerkLoaded, SignedIn } from '@clerk/nextjs'; +> +> function CheckoutPage() { +> return ( +> +> +> +> +> +> ); +> } +> ``` + +This addition will help developers avoid common issues and follow best practices when implementing checkout flows with Clerk. + +Would you like me to suggest any other places where this information might be relevant to include? + `useCheckout()` can be used in two ways: 1. In conjunction with the , which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. From a357c20208581176670014aca8ce3dff0bb660a5 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 9 Jul 2025 19:27:51 +0300 Subject: [PATCH 09/36] add custom flow to overview --- docs/billing/overview.mdx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/docs/billing/overview.mdx b/docs/billing/overview.mdx index f2c9fcac9a..2298181ac4 100644 --- a/docs/billing/overview.mdx +++ b/docs/billing/overview.mdx @@ -13,4 +13,11 @@ Clerk billing allows your customers to purchase recurring subscriptions to your - [Billing for B2B SaaS](/docs/billing/b2b-saas) - To charge companies or organizations + + --- + + - [Build a simple checkout page](/docs/custom-flows/checkout-new-payment-method) + - To charge users with a new payment method + + --- From d28d1bd27273be785b5f2886b0cfc10fc524e523 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 10 Jul 2025 17:57:15 +0300 Subject: [PATCH 10/36] Update docs/hooks/use-checkout.mdx Co-authored-by: Nick Wylynko --- docs/hooks/use-checkout.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 608ba37a20..3e497d5274 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -28,7 +28,7 @@ Would you like me to suggest any other places where this information might be re `useCheckout()` can be used in two ways: -1. In conjunction with the , which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. +1. In conjunction with the ``, which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. 1. As a standalone hook by passing configuration options directly to it. This is ideal for self-contained components that manage their own checkout flow. ## Parameters From e436face45e633bdcdb4b41a00bb17358f3b498a Mon Sep 17 00:00:00 2001 From: panteliselef Date: Mon, 14 Jul 2025 14:04:38 +0300 Subject: [PATCH 11/36] add usePlans --- docs/hooks/use-plans.mdx | 290 +++++++++++++++++++++++++++++++++++++++ docs/manifest.json | 5 + 2 files changed, 295 insertions(+) create mode 100644 docs/hooks/use-plans.mdx diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx new file mode 100644 index 0000000000..f25203779b --- /dev/null +++ b/docs/hooks/use-plans.mdx @@ -0,0 +1,290 @@ +--- +title: '`usePlans()`' +description: Access plans in your React application with Clerk's usePlans() hook. +--- + +The `usePlans()` hook provides access to the subscription plans available in your application. It returns a paginated list of plans and includes methods for managing them. + +## Parameters + +`usePlans()` accepts a single object with the following properties: + + + - `for?` + - `'user' | 'organization'` + + Specifies whether to fetch plans for users or organizations. Defaults to `'user'`. + + --- + + - `pageSize?` + - `number` + + The number of plans to fetch per page. Defaults to `10`. + + --- + + - `initialPage?` + - `number` + + The page number to start fetching from. Defaults to `1`. + + --- + + - `infinite?` + - `boolean` + + When `true`, enables infinite pagination mode where new pages are appended to existing data. When `false`, each page replaces the previous data. Defaults to `false`. + + --- + + - `keepPreviousData?` + - `boolean` + + When `true`, the previous data will be kept while loading the next page. This helps prevent layout shifts. Defaults to `false`. + + +## Returns + +The hook returns an object with the following properties: + + + - `data` + - `Plan[] | null` + + An array of plan objects, or `null` if the data hasn't been loaded yet. + + --- + + - `isLoading` + - `boolean` + + `true` while the initial data is being fetched. + + --- + + - `isFetching` + - `boolean` + + `true` while any request is in flight, including background updates. + + --- + + - `hasNextPage` + - `boolean` + + `true` if there are more pages available to load. + + --- + + - `hasPreviousPage` + - `boolean` + + `true` if there are previous pages available to load. + + --- + + - `fetchNext` + - `() => Promise` + + Function to fetch the next page of plans. + + --- + + - `fetchPrevious` + - `() => Promise` + + Function to fetch the previous page of plans. + + --- + + - `pageCount` + - `number` + + The total number of available pages. + + --- + + - `count` + - `number` + + The total number of plans available. + + +### `Plan` + +Each plan object contains the following properties: + + + - `id` + - `string` + + The unique identifier for the plan (e.g., `cplan_xxxx`). + + --- + + - `name` + - `string` + + The display name of the plan. + + --- + + - `description` + - `string` + + A detailed description of what the plan offers. + + --- + + - `amount` + - `number` + + The cost of the plan in cents. + + --- + + - `currency` + - `string` + + The three-letter ISO currency code (e.g., 'USD', 'EUR'). + + --- + + - `interval` + - `'monthly' | 'yearly'` + + The billing interval for the plan. + + --- + + - `features` + - `PlanFeature[]` + + An array of features included in the plan. + + --- + + - `isPublic` + - `boolean` + + Whether the plan is publicly available and visible in components like ``. + + +### `PlanFeature` + +Each feature object contains the following properties: + + + - `id` + - `string` + + The unique identifier for the feature. + + --- + + - `name` + - `string` + + The display name of the feature. + + --- + + - `description` + - `string` + + A detailed description of what the feature provides. + + +## Examples + +### Basic Usage + +The following example shows how to fetch and display available plans: + +```tsx +import { usePlans } from '@clerk/nextjs' + +function PlansList() { + const { data, isLoading } = usePlans({ + for: 'user', + pageSize: 10, + }) + + if (isLoading) { + return
Loading plans...
+ } + + return ( +
    + {data?.map((plan) => ( +
  • +

    {plan.name}

    +

    {plan.description}

    +

    + {(plan.amount / 100).toFixed(2)} {plan.currency} / {plan.interval} +

    +

    Features:

    +
      + {plan.features.map((feature) => ( +
    • {feature.name}
    • + ))} +
    +
  • + ))} +
+ ) +} +``` + +### With Checkout Flow + +Here's an example of using `usePlans` in a checkout flow to let users select a plan: + +```tsx +import { usePlans, useCheckout } from '@clerk/nextjs' + +function PlanSelection() { + const { data, isLoading } = usePlans({ for: 'user' }) + const [selectedPlan, setSelectedPlan] = useState(null) + const { checkout } = useCheckout({ + planId: selectedPlan?.id, + planPeriod: selectedPlan?.interval, + }) + + const handlePlanSelect = async (plan) => { + setSelectedPlan(plan) + try { + await checkout.start() + // Continue with checkout flow... + } catch (error) { + console.error('Failed to start checkout:', error) + } + } + + if (isLoading) { + return
Loading plans...
+ } + + return ( +
+

Choose a Plan

+
+ {data?.map((plan) => ( + + ))} +
+
+ ) +} +``` \ No newline at end of file diff --git a/docs/manifest.json b/docs/manifest.json index ee03598009..d34e411feb 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1091,6 +1091,11 @@ "title": "`usePaymentMethods()`", "wrap": false, "href": "/docs/hooks/use-payment-methods" + }, + { + "title": "`usePlans()`", + "wrap": false, + "href": "/docs/hooks/use-plans" } ] ] From e54e93658100af75ca853a2d5c7fa142a520f384 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 17 Jul 2025 16:35:23 +0300 Subject: [PATCH 12/36] formatting --- docs/hooks/use-checkout.mdx | 8 ++++---- docs/hooks/use-plans.mdx | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 3e497d5274..1e20711123 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -7,10 +7,10 @@ The `useCheckout()` hook is the primary tool for managing checkout flows. It can > [!IMPORTANT] > For the best user experience and to prevent potential errors, always wrap components using `useCheckout()` with both `` and `` components. This ensures that the user is properly authenticated and Clerk is fully initialized before accessing checkout functionality. -> +> > ```tsx -> import { ClerkLoaded, SignedIn } from '@clerk/nextjs'; -> +> import { ClerkLoaded, SignedIn } from '@clerk/nextjs' +> > function CheckoutPage() { > return ( > @@ -18,7 +18,7 @@ The `useCheckout()` hook is the primary tool for managing checkout flows. It can > > > -> ); +> ) > } > ``` diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index f25203779b..a11c1e1d0c 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -287,4 +287,4 @@ function PlanSelection() { ) } -``` \ No newline at end of file +``` From aeced2768136376f7e031eb5dd060865920d6192 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Thu, 17 Jul 2025 18:12:06 +0300 Subject: [PATCH 13/36] add useSubscription --- docs/hooks/use-subscription.mdx | 279 ++++++++++++++++++++++++++++++++ docs/manifest.json | 5 + 2 files changed, 284 insertions(+) create mode 100644 docs/hooks/use-subscription.mdx diff --git a/docs/hooks/use-subscription.mdx b/docs/hooks/use-subscription.mdx new file mode 100644 index 0000000000..8dbec94879 --- /dev/null +++ b/docs/hooks/use-subscription.mdx @@ -0,0 +1,279 @@ +--- +title: '`useSubscription()`' +description: Access subscription information in your React application with Clerk's useSubscription() hook. +--- + +The `useSubscription()` hook provides access to subscription information for users or organizations in your application. It returns the current subscription data and includes methods for managing it. + +> [!WARNING] +> The `useSubscription()` hook should only be used for accessing and displaying subscription information. For authorization purposes (i.e., controlling access to features or content), use the [`has()`](/docs/guides/authorization-checks#use-has-for-authorization-checks) helper or the [``](/docs/components/protect) component instead. + +## Parameters + +`useSubscription()` accepts a single optional object with the following properties: + + + - `for?` + - `'organization' | 'user'` + + Specifies whether to fetch subscription for an organization or user. Defaults to `'user'`. + + --- + + - `keepPreviousData?` + - `boolean` + + When `true`, the previous data will be kept in the cache until new data is fetched. This helps prevent layout shifts. Defaults to `false`. + + +## Returns + +The hook returns an object with the following properties: + + + - `data` + - `Subscription | null` + + The subscription object, or `null` if the data hasn't been loaded yet. + + --- + + - `isLoading` + - `boolean` + + `true` while the initial data is being fetched. + + --- + + - `isFetching` + - `boolean` + + `true` while any request is in flight, including background updates. + + --- + + - `error` + - `Error | null` + + Any error that occurred during the data fetch, or `null` if no error occurred. + + --- + + - `revalidate` + - `() => Promise` + + Function to manually trigger a refresh of the subscription data. + + +### `Subscription` + +Each subscription object contains the following properties: + + + - `id` + - `string` + + The unique identifier for the subscription. + + --- + + - `status` + - `CommerceSubscriptionStatus` + + The current status of the subscription. + + --- + + - `activeAt` + - `Date` + + The date when the subscription became active. + + --- + + - `createdAt` + - `Date` + + The date when the subscription was created. + + --- + + - `updatedAt` + - `Date | null` + + The date when the subscription was last updated, or null if never updated. + + --- + + - `pastDueAt` + - `Date | null` + + The date when the subscription became past due, or null if not past due. + + --- + + - `nextPayment` + - `{ amount: CommerceMoney; time: Date; } | null` + + Information about the next payment, including the amount and scheduled time. Null if no upcoming payment. + + --- + + - `subscriptionItems` + - `CommerceSubscriptionItemResource[]` + + An array of items included in this subscription. + + +## Examples + +### Basic Usage + +The following example shows how to fetch and display subscription information: + +```tsx +import { useSubscription } from '@clerk/nextjs' + +function SubscriptionInfo() { + const { data, isLoading, error } = useSubscription() + + if (isLoading) { + return
Loading subscription...
+ } + + if (error) { + return
Error loading subscription: {error.message}
+ } + + if (!data) { + return
No subscription found
+ } + + return ( +
+

Your Subscription

+ {/* Display subscription details */} +
+ ) +} +``` + +### Organization Subscription + +Here's an example of fetching an organization's subscription: + +```tsx +import { useSubscription } from '@clerk/nextjs' + +function OrganizationSubscription() { + const { data, isLoading, revalidate } = useSubscription({ + for: 'organization', + keepPreviousData: true, + }) + + const handleSubscriptionUpdate = async () => { + // After making changes to the subscription + await revalidate() + } + + if (isLoading) { + return
Loading organization subscription...
+ } + + return ( +
+

Organization Subscription

+ {/* Display organization subscription details */} + +
+ ) +} +``` + +### With Error Handling + +This example shows how to handle subscription data with proper error states: + +```tsx +import { useSubscription } from '@clerk/nextjs' + +function SubscriptionStatus() { + const { data, isLoading, error, isFetching } = useSubscription() + + if (error) { + return ( +
+

Failed to load subscription

+

{error.message}

+ +
+ ) + } + + return ( +
+ {isLoading ? ( +
Loading...
+ ) : ( + <> +
{isFetching && Refreshing...}
+ {data ? ( +
{/* Display subscription details */}
+ ) : ( +
No active subscription
+ )} + + )} +
+ ) +} +``` + +```tsx +import { useSubscription } from '@clerk/nextjs' + +function SubscriptionDetails() { + const { data: subscription, isLoading } = useSubscription() + + if (isLoading) { + return
Loading subscription...
+ } + + if (!subscription) { + return
No subscription
+ } + + return ( +
+

Subscription Details

+
+ Status: {subscription.status} +
+ +
+

Active since: {subscription.activeAt.toLocaleDateString()}

+ {subscription.pastDueAt && ( +

Past due since: {subscription.pastDueAt.toLocaleDateString()}

+ )} +
+ + {subscription.nextPayment && ( +
+

Next Payment

+

Amount: {subscription.nextPayment.amount}

+

Due: {subscription.nextPayment.time.toLocaleDateString()}

+
+ )} + +
+

Subscription Items

+
    + {subscription.subscriptionItems.map((item) => ( +
  • {/* Display subscription item details */}
  • + ))} +
+
+
+ ) +} +``` diff --git a/docs/manifest.json b/docs/manifest.json index 0d3b44bbe5..8310888d16 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -1096,6 +1096,11 @@ "title": "`usePlans()`", "wrap": false, "href": "/docs/hooks/use-plans" + }, + { + "title": "`useSubscription()`", + "wrap": false, + "href": "/docs/hooks/use-subscription" } ] ] From 22af4b43217af96df84369ec5108aa30eaa3da0e Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 22 Jul 2025 14:57:53 +0300 Subject: [PATCH 14/36] add experimental callout --- docs/_partials/billing/api-experimental.mdx | 3 +++ docs/hooks/use-checkout.mdx | 2 ++ docs/hooks/use-payment-element.mdx | 2 ++ docs/hooks/use-payment-methods.mdx | 3 +++ docs/hooks/use-plans.mdx | 2 ++ docs/hooks/use-subscription.mdx | 2 ++ 6 files changed, 14 insertions(+) create mode 100644 docs/_partials/billing/api-experimental.mdx diff --git a/docs/_partials/billing/api-experimental.mdx b/docs/_partials/billing/api-experimental.mdx new file mode 100644 index 0000000000..e8881f744f --- /dev/null +++ b/docs/_partials/billing/api-experimental.mdx @@ -0,0 +1,3 @@ +> [!WARNING] +> +> This API is experimental and subject to change while Clerk Billing is under Beta. To mitigate potential disruptions, we recommend [pinning](https://docs.renovatebot.com/dependency-pinning/#what-is-dependency-pinning) your SDK and `clerk-js` package versions. diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 1e20711123..f0c8271563 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -3,6 +3,8 @@ title: useCheckout() description: Clerk's useCheckout() hook provides state and methods to manage a subscription checkout flow. --- + + The `useCheckout()` hook is the primary tool for managing checkout flows. It can be used to create, manage, and confirm a checkout session for a user or an organization's subscription plan. The hook provides the state of the current checkout process, such as its status and any errors, along with methods to initiate and complete the checkout. > [!IMPORTANT] diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx index 759173e4b2..0f8dcb3c77 100644 --- a/docs/hooks/use-payment-element.mdx +++ b/docs/hooks/use-payment-element.mdx @@ -3,6 +3,8 @@ title: usePaymentElement() description: Clerk's usePaymentElement() hook provides methods and state for interacting with a payment form. --- + + The `usePaymentElement()` hook is used to control the payment form rendered by the `` component. It provides the necessary state and methods to submit payment details to a payment provider like Stripe. This hook must be used within a component that is a descendant of the `` component. It is typically used in a checkout flow that prompts a user to add a new payment method, or for adding a new payment method outside of a checkout. diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index da98a459a0..31c2cb9dc8 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -3,6 +3,9 @@ title: '`usePaymentMethods()`' description: Access and manage payment methods in your React application with Clerk's usePaymentMethods() hook. --- + + + The `usePaymentMethods()` hook provides access to the payment methods associated with a user or organization. It returns a paginated list of payment methods and includes methods for managing them. ## Parameters diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index a11c1e1d0c..6c43c9638d 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -5,6 +5,8 @@ description: Access plans in your React application with Clerk's usePlans() hook The `usePlans()` hook provides access to the subscription plans available in your application. It returns a paginated list of plans and includes methods for managing them. + + ## Parameters `usePlans()` accepts a single object with the following properties: diff --git a/docs/hooks/use-subscription.mdx b/docs/hooks/use-subscription.mdx index 8dbec94879..e65d47e20e 100644 --- a/docs/hooks/use-subscription.mdx +++ b/docs/hooks/use-subscription.mdx @@ -3,6 +3,8 @@ title: '`useSubscription()`' description: Access subscription information in your React application with Clerk's useSubscription() hook. --- + + The `useSubscription()` hook provides access to subscription information for users or organizations in your application. It returns the current subscription data and includes methods for managing it. > [!WARNING] From bf80eab42e48b628282db6abf5b00797f5dd2aa2 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 22 Jul 2025 15:01:53 +0300 Subject: [PATCH 15/36] change callouts of custom flows --- docs/custom-flows/add-new-payment-methods.mdx | 2 +- docs/custom-flows/checkout-existing-payment-method.mdx | 2 +- docs/custom-flows/checkout-new-payment-method.mdx | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/custom-flows/add-new-payment-methods.mdx b/docs/custom-flows/add-new-payment-methods.mdx index 5b9efbeedb..f1a11bbdfa 100644 --- a/docs/custom-flows/add-new-payment-methods.mdx +++ b/docs/custom-flows/add-new-payment-methods.mdx @@ -3,7 +3,7 @@ title: Add a new payment method description: Learn how to use Clerk's components to allow users to add a new payment method to their account. --- - + This guide will walk you through how to build a flow for adding a new payment method. This is a common feature in a user's billing or account settings page, allowing them to pre-emptively add a payment method for future use. diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index 1a2a044a9f..df5cab7bb9 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -3,7 +3,7 @@ title: Build a custom checkout flow with an existing payment method description: Learn how to use the Clerk API to build a custom checkout flow using an existing payment method. --- - + This guide will walk you through how to build a custom checkout flow using an existing payment method. diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index 4635d732ee..1710d1b0dd 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -3,7 +3,7 @@ title: Build a custom checkout flow for a new payment method description: Learn how to use the Clerk API to build a custom checkout flow for a new payment method. --- - + This guide will walk you through how to build a custom checkout flow with a new payment method. From 1d2770149007c963b6f6fc0f280476ab63403bd0 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 22 Jul 2025 15:07:22 +0300 Subject: [PATCH 16/36] fix --- docs/_partials/billing/api-experimental-guide.mdx | 3 +++ docs/hooks/use-checkout.mdx | 12 ++++++++++++ docs/hooks/use-payment-element.mdx | 12 ++++++++++++ docs/hooks/use-payment-methods.mdx | 1 - 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 docs/_partials/billing/api-experimental-guide.mdx diff --git a/docs/_partials/billing/api-experimental-guide.mdx b/docs/_partials/billing/api-experimental-guide.mdx new file mode 100644 index 0000000000..b2c06f1cca --- /dev/null +++ b/docs/_partials/billing/api-experimental-guide.mdx @@ -0,0 +1,3 @@ +> [!WARNING] +> +> This guide is using experimental APIs and subject to change while Clerk Billing is under Beta. To mitigate potential disruptions, we recommend [pinning](https://docs.renovatebot.com/dependency-pinning/#what-is-dependency-pinning) your SDK and `clerk-js` package versions. diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index f0c8271563..2c02f56af1 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -324,3 +324,15 @@ The `useCheckout()` hook can be used with a context provider for managing state ``` + +## Related guides + + + - [Checkout flow with a new payment method](/docs/custom-flows/checkout-new-payment-method) + - Prompt users to add a new payment method during checkout + + --- + + - [Checkout flow for returning users](/docs/custom-flows/checkout-existing-payment-method) + - Prompt users to select an existing payment method during checkout + diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx index 0f8dcb3c77..b14a2016df 100644 --- a/docs/hooks/use-payment-element.mdx +++ b/docs/hooks/use-payment-element.mdx @@ -171,3 +171,15 @@ The following example demonstrates the basic structure for adding a new payment ``` + +## Related guides + + + - [Use PaymentElement in a checkout flow](/docs/custom-flows/checkout-new-payment-method) + - Prompt users to add a new payment method during checkout + + --- + + - [Use PaymentElement outside of a checkout flow](/docs/custom-flows/add-new-payment-methods) + - Add a new payment method outside of a checkout flow + diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index 31c2cb9dc8..c4c7b4af32 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -3,7 +3,6 @@ title: '`usePaymentMethods()`' description: Access and manage payment methods in your React application with Clerk's usePaymentMethods() hook. --- - The `usePaymentMethods()` hook provides access to the payment methods associated with a user or organization. It returns a paginated list of payment methods and includes methods for managing them. From f2f0bdb8e66c302219d6f7bc2de406117af45530 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 22 Jul 2025 15:28:56 +0300 Subject: [PATCH 17/36] remove invalid example --- docs/hooks/use-plans.mdx | 52 ---------------------------------------- 1 file changed, 52 deletions(-) diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index 6c43c9638d..1c3070e60c 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -238,55 +238,3 @@ function PlansList() { ) } ``` - -### With Checkout Flow - -Here's an example of using `usePlans` in a checkout flow to let users select a plan: - -```tsx -import { usePlans, useCheckout } from '@clerk/nextjs' - -function PlanSelection() { - const { data, isLoading } = usePlans({ for: 'user' }) - const [selectedPlan, setSelectedPlan] = useState(null) - const { checkout } = useCheckout({ - planId: selectedPlan?.id, - planPeriod: selectedPlan?.interval, - }) - - const handlePlanSelect = async (plan) => { - setSelectedPlan(plan) - try { - await checkout.start() - // Continue with checkout flow... - } catch (error) { - console.error('Failed to start checkout:', error) - } - } - - if (isLoading) { - return
Loading plans...
- } - - return ( -
-

Choose a Plan

-
- {data?.map((plan) => ( - - ))} -
-
- ) -} -``` From 47e22946034fa8249ecf4ed4c0e511f148bd9258 Mon Sep 17 00:00:00 2001 From: Sarah Soutoul Date: Thu, 24 Jul 2025 19:30:19 +0200 Subject: [PATCH 18/36] docs review --- docs/hooks/use-checkout.mdx | 40 +++++++++++------------------- docs/hooks/use-payment-element.mdx | 8 +++--- docs/hooks/use-payment-methods.mdx | 26 +++++++++---------- docs/hooks/use-plans.mdx | 20 +++++++-------- docs/hooks/use-subscription.mdx | 26 +++++++++---------- 5 files changed, 51 insertions(+), 69 deletions(-) diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 2c02f56af1..366758a9ac 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -1,11 +1,16 @@ --- -title: useCheckout() +title: '`useCheckout()`' description: Clerk's useCheckout() hook provides state and methods to manage a subscription checkout flow. --- -The `useCheckout()` hook is the primary tool for managing checkout flows. It can be used to create, manage, and confirm a checkout session for a user or an organization's subscription plan. The hook provides the state of the current checkout process, such as its status and any errors, along with methods to initiate and complete the checkout. +The `useCheckout()` hook is used to create, manage, and confirm a checkout session for a user or an organization's subscription plan. The hook provides the state of the current checkout process, such as its status and any errors, along with methods to initiate and complete the checkout. + +There are two ways to use `useCheckout()`: + +1. In conjunction with `` to create a shared checkout context. All child components inside the provider can then use `useCheckout()` to access or update the same checkout state. +1. Using `useCheckout()` on its own by passing configuration options directly to it. This is ideal for self-contained components that handle their own checkout flow without needing a shared context. > [!IMPORTANT] > For the best user experience and to prevent potential errors, always wrap components using `useCheckout()` with both `` and `` components. This ensures that the user is properly authenticated and Clerk is fully initialized before accessing checkout functionality. @@ -24,24 +29,13 @@ The `useCheckout()` hook is the primary tool for managing checkout flows. It can > } > ``` -This addition will help developers avoid common issues and follow best practices when implementing checkout flows with Clerk. - -Would you like me to suggest any other places where this information might be relevant to include? - -`useCheckout()` can be used in two ways: - -1. In conjunction with the ``, which provides the checkout context to its children. This is useful when multiple components in a tree need to access the same checkout state. -1. As a standalone hook by passing configuration options directly to it. This is ideal for self-contained components that manage their own checkout flow. - ## Parameters -The `useCheckout()` hook accepts an optional options object. These options are **required** if the hook is used without a `` wrapping your component tree. - - `options?` - [`UseCheckoutOptions`](#use-checkout-options) - An object containing the configuration for the checkout flow. + An object containing the configuration for the checkout flow. This is **required** if the hook is used without a `` wrapping the component tree. ### `UseCheckoutOptions` @@ -50,7 +44,7 @@ The `useCheckout()` hook accepts an optional options object. These options are * - `for?` - `'organization'` - Specifies that the checkout is for an organization. If omitted, the checkout defaults to the current user. + Specifies if the checkout is for an organization. If omitted, the checkout defaults to the current user. --- @@ -69,18 +63,16 @@ The `useCheckout()` hook accepts an optional options object. These options are * ## Returns -The hook returns an object containing a `checkout` object with the current state and methods to control the flow. - - `checkout` - `object` - An object containing the checkout resource properties, state helpers, and methods. + Specify the checkout resource properties, state helpers, and methods. The `checkout` object contains the following: -### Resource Properties +### Resource properties These properties describe the checkout resource itself. They are `null` until the checkout process is started by calling the `start()` method. @@ -130,7 +122,7 @@ These properties describe the checkout resource itself. They are `null` until th - `totals` - `object | null` - An object containing the total costs, taxes, and other pricing details. + The total costs, taxes, and other pricing details. --- @@ -140,7 +132,7 @@ These properties describe the checkout resource itself. They are `null` until th Indicates if the plan change will take effect immediately. -### State Helpers +### State helpers These properties provide information about the current state of the hook's operations. @@ -169,7 +161,7 @@ These properties provide information about the current state of the hook's opera - `error` - `ClerkAPIResponseError | null` - An error object if any part of the checkout process fails. + Returns an error object if any part of the checkout process fails. --- @@ -217,8 +209,6 @@ The `useCheckout()` hook can be used with a context provider for managing state ", "Standalone Hook"]}> - ### With `` - Using the `` is the recommended approach when checkout state needs to be shared across multiple components. The provider is configured once, and any child component can access the checkout context by calling `useCheckout()`. The following example shows a `` that sets up the provider and a `` component that consumes the context to manage the checkout UI. @@ -282,8 +272,6 @@ The `useCheckout()` hook can be used with a context provider for managing state - ### Standalone Hook - For simple, self-contained components, you can use `useCheckout()` by passing the configuration options directly to the hook. This avoids the need to wrap the component in a provider. The following example shows an `` component that manages its own checkout flow. diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx index b14a2016df..1a2558cfb4 100644 --- a/docs/hooks/use-payment-element.mdx +++ b/docs/hooks/use-payment-element.mdx @@ -1,5 +1,5 @@ --- -title: usePaymentElement() +title: '`usePaymentElement()`' description: Clerk's usePaymentElement() hook provides methods and state for interacting with a payment form. --- @@ -9,7 +9,7 @@ The `usePaymentElement()` hook is used to control the payment form rendered by t This hook must be used within a component that is a descendant of the `` component. It is typically used in a checkout flow that prompts a user to add a new payment method, or for adding a new payment method outside of a checkout. -## Payment Element Components +## Payment element components The `usePaymentElement()` hook works in conjunction with the `` and `` components. @@ -62,8 +62,6 @@ The `usePaymentElement()` hook does not accept any parameters. It derives its st ## Returns -The hook returns an object containing state helpers and methods to interact with the payment form. - - `submit` - `() => Promise<{ data: { gateway: 'stripe'; paymentToken: string } | null; error: PaymentElementError | null}>` @@ -101,7 +99,7 @@ The hook returns an object containing state helpers and methods to interact with ## Examples -The following example demonstrates the basic structure for adding a new payment method. A parent component, ``, sets up the provider and renders the form. A child component, ``, uses the `usePaymentElement()` hook to handle the form submission. +The following example shows the basic structure for adding a new payment method. A parent component, ``, sets up the provider and renders the form. A child component, ``, uses the `usePaymentElement()` hook to handle the form submission. diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index c4c7b4af32..db1ffc1d8d 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -48,11 +48,9 @@ The `usePaymentMethods()` hook provides access to the payment methods associated ## Returns -The hook returns an object with the following properties: - - `data` - - `PaymentMethod[] | null` + - [`PaymentMethod[]`](#payment-method) | null An array of payment method objects, or `null` if the data hasn't been loaded yet. @@ -61,28 +59,28 @@ The hook returns an object with the following properties: - `isLoading` - `boolean` - `true` while the initial data is being fetched. + A boolean that indicates whether the initial data is still being fetched. --- - `isFetching` - `boolean` - `true` while any request is in flight, including background updates. + A boolean that indicates whether any request is still in flight, including background updates. --- - `hasNextPage` - `boolean` - `true` if there are more pages available to load. + A boolean that indicates whether there are more pages available to load. --- - `hasPreviousPage` - `boolean` - `true` if there are previous pages available to load. + A boolean that indicates whether there are previous pages available to load. --- @@ -156,14 +154,14 @@ Each payment method object contains the following properties: - `isDefault` - `boolean` - Whether this is the default payment method. + Specifies whether this is the default payment method. ## Examples -### Basic Usage +### Basic usage -The following example shows how to fetch and display a user's payment methods: +The following example demonstrates how to fetch and display a user's payment methods. ```tsx import { usePaymentMethods } from '@clerk/nextjs' @@ -191,9 +189,9 @@ function PaymentMethodsList() { } ``` -### Infinite Pagination +### Infinite pagination -This example demonstrates how to implement infinite scrolling with payment methods: +The following example demonstrates how to implement infinite scrolling with payment methods. ```tsx import { usePaymentMethods } from '@clerk/nextjs' @@ -227,9 +225,9 @@ function InfinitePaymentMethods() { } ``` -### With Checkout Flow +### With checkout flow -Here's an example of using `usePaymentMethods` in a checkout flow to select an existing payment method: +The following example demonstrates how to use `usePaymentMethods` in a checkout flow to select an existing payment method. ```tsx import { usePaymentMethods, useCheckout } from '@clerk/nextjs' diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index 1c3070e60c..d0071e034a 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -3,10 +3,10 @@ title: '`usePlans()`' description: Access plans in your React application with Clerk's usePlans() hook. --- -The `usePlans()` hook provides access to the subscription plans available in your application. It returns a paginated list of plans and includes methods for managing them. - +The `usePlans()` hook provides access to the subscription plans available in your application. It returns a paginated list of plans and includes methods for managing them. + ## Parameters `usePlans()` accepts a single object with the following properties: @@ -52,7 +52,7 @@ The hook returns an object with the following properties: - `data` - - `Plan[] | null` + - [`Plan[]`](#plan) | null An array of plan objects, or `null` if the data hasn't been loaded yet. @@ -61,28 +61,28 @@ The hook returns an object with the following properties: - `isLoading` - `boolean` - `true` while the initial data is being fetched. + A boolean that indicates whether the initial data is still being fetched. --- - `isFetching` - `boolean` - `true` while any request is in flight, including background updates. + A boolean that indicates whether any request is still in flight, including background updates. --- - `hasNextPage` - `boolean` - `true` if there are more pages available to load. + A boolean that indicates whether there are more pages available to load. --- - `hasPreviousPage` - `boolean` - `true` if there are previous pages available to load. + A boolean that indicates whether there are previous pages available to load. --- @@ -161,7 +161,7 @@ Each plan object contains the following properties: --- - `features` - - `PlanFeature[]` + - [`PlanFeature[]`](#plan-feature) An array of features included in the plan. @@ -200,9 +200,9 @@ Each feature object contains the following properties: ## Examples -### Basic Usage +### Basic usage -The following example shows how to fetch and display available plans: +The following example shows how to fetch and display available plans. ```tsx import { usePlans } from '@clerk/nextjs' diff --git a/docs/hooks/use-subscription.mdx b/docs/hooks/use-subscription.mdx index e65d47e20e..1033ca40fc 100644 --- a/docs/hooks/use-subscription.mdx +++ b/docs/hooks/use-subscription.mdx @@ -30,11 +30,9 @@ The `useSubscription()` hook provides access to subscription information for use ## Returns -The hook returns an object with the following properties: - - `data` - - `Subscription | null` + - [`Subscription`](#subscription) | null The subscription object, or `null` if the data hasn't been loaded yet. @@ -43,14 +41,14 @@ The hook returns an object with the following properties: - `isLoading` - `boolean` - `true` while the initial data is being fetched. + A boolean that indicates whether the initial data is still being fetched. --- - `isFetching` - `boolean` - `true` while any request is in flight, including background updates. + A boolean that indicates whether any request is still in flight, including background updates. --- @@ -103,21 +101,21 @@ Each subscription object contains the following properties: - `updatedAt` - `Date | null` - The date when the subscription was last updated, or null if never updated. + The date when the subscription was last updated, or `null` if never updated. --- - `pastDueAt` - `Date | null` - The date when the subscription became past due, or null if not past due. + The date when the subscription became past due, or `null` if not past due. --- - `nextPayment` - `{ amount: CommerceMoney; time: Date; } | null` - Information about the next payment, including the amount and scheduled time. Null if no upcoming payment. + Information about the next payment, including the amount and scheduled time. Returns `null` if no upcoming payment. --- @@ -129,9 +127,9 @@ Each subscription object contains the following properties: ## Examples -### Basic Usage +### Basic usage -The following example shows how to fetch and display subscription information: +The following example shows how to fetch and display subscription information. ```tsx import { useSubscription } from '@clerk/nextjs' @@ -160,9 +158,9 @@ function SubscriptionInfo() { } ``` -### Organization Subscription +### Organization subscription -Here's an example of fetching an organization's subscription: +The following example shows how to fetch an organization's subscription. ```tsx import { useSubscription } from '@clerk/nextjs' @@ -192,9 +190,9 @@ function OrganizationSubscription() { } ``` -### With Error Handling +### With error handling -This example shows how to handle subscription data with proper error states: +The following example shows how to handle subscription data with proper error states. ```tsx import { useSubscription } from '@clerk/nextjs' From ac5110905e92853cbb8712d69bc947ec4e099826 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 25 Jul 2025 21:59:48 +0300 Subject: [PATCH 19/36] fix paths --- docs/custom-flows/add-new-payment-methods.mdx | 7 ++++--- .../checkout-existing-payment-method.mdx | 9 ++------- .../custom-flows/checkout-new-payment-method.mdx | 7 +++---- docs/hooks/use-checkout.mdx | 16 ++++++++-------- docs/hooks/use-payment-element.mdx | 16 ++++++++-------- docs/hooks/use-payment-methods.mdx | 6 +++--- docs/hooks/use-plans.mdx | 2 +- docs/hooks/use-subscription.mdx | 8 ++++---- 8 files changed, 33 insertions(+), 38 deletions(-) diff --git a/docs/custom-flows/add-new-payment-methods.mdx b/docs/custom-flows/add-new-payment-methods.mdx index f1a11bbdfa..9efa0cfcd2 100644 --- a/docs/custom-flows/add-new-payment-methods.mdx +++ b/docs/custom-flows/add-new-payment-methods.mdx @@ -33,7 +33,7 @@ This guide will walk you through how to build a flow for adding a new payment me This component is responsible for setting up the provider context. It specifies that the payment actions within its children are `for` the `user`. ```tsx {{ filename: 'src/components/UserBillingPage.tsx' }} - import { PaymentElementProvider } from '@clerk/nextjs' + import { PaymentElementProvider } from '@clerk/nextjs/experimental' import { AddPaymentMethodForm } from './AddPaymentMethodForm' export function UserBillingPage() { @@ -55,7 +55,8 @@ This guide will walk you through how to build a flow for adding a new payment me This component contains the form and the logic to handle the submission. It uses `usePaymentElement` to get the `submit` function and `useUser` to get the `user` object. When the form is submitted, it first creates a payment token and then attaches it to the user. ```tsx {{ filename: 'src/components/AddPaymentMethodForm.tsx' }} - import { usePaymentElement, useUser, PaymentElementForm } from '@clerk/nextjs' + import { useUser } from '@clerk/nextjs' + import { usePaymentElement, PaymentElement } from '@clerk/nextjs/experimental' import { useState } from 'react' export function AddPaymentMethodForm() { @@ -98,7 +99,7 @@ This guide will walk you through how to build a flow for adding a new payment me return (

Add a new payment method

- + diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index df5cab7bb9..ea791da787 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -38,13 +38,8 @@ This guide will walk you through how to build a custom checkout flow using an ex ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 9], 14, 15, 17, 18, 23, [26, 28], [55, 58], [71, 77], [102, 104]] }} 'use client' import * as React from 'react' - import { - __experimental_CheckoutProvider as CheckoutProvider, - __experimental_useCheckout as useCheckout, - __experimental_usePaymentMethods as usePaymentMethods, - SignedIn, - ClerkLoaded, - } from '@clerk/nextjs' + import { SignedIn, ClerkLoaded } from '@clerk/nextjs' + import { CheckoutProvider, useCheckout, usePaymentMethods } from '@clerk/nextjs/experimental' import { useMemo, useState } from 'react' export default function CheckoutPage() { diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index 1710d1b0dd..a4cc5e7015 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -27,7 +27,7 @@ This guide will walk you through how to build a custom checkout flow with a new The following example: 1. Uses the [`useCheckout()`](/docs/hooks/use-checkout) hook to get to initiate and manage the checkout session. - 1. Uses the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to control the payment element, which is rendered by ``. + 1. Uses the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to control the payment element, which is rendered by ``. 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways. 1. Copy from the Clerk Dashboard. 1. Use the [Clerk Backend API](TBD). @@ -38,15 +38,14 @@ This guide will walk you through how to build a custom checkout flow with a new ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 11], 16, 18, [23, 24], 26, 34, 36, 42, 56, [66, 75], 85] }} 'use client' import * as React from 'react' + import { SignedIn, ClerkLoaded } from '@clerk/nextjs' import { CheckoutProvider, useCheckout, PaymentElementProvider, PaymentElementForm, usePaymentElement, - SignedIn, - ClerkLoaded, - } from '@clerk/nextjs' + } from '@clerk/nextjs/experimental' import { useRouter } from 'next/navigation' export default function CheckoutPage() { diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 366758a9ac..e80c19b1dd 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -138,7 +138,7 @@ These properties provide information about the current state of the hook's opera - `status` - - `'idle' | 'starting' | 'confirming' | 'complete' | 'error'` + - `'awaiting_initialization' | 'awaiting_confirmation' | 'completed'` The current status of the checkout flow. @@ -177,20 +177,20 @@ These methods are used to control the checkout flow. - `start()` - - `() => Promise` + - `() => Promise<{ data: CommerceCheckoutResource; error: null; } | { data: null; error: ClerkAPIResponseError; }>` Initializes the checkout process by creating a checkout resource on the server. --- - `confirm()` - - `(params: ConfirmCheckoutParams) => Promise` + - `(params: ConfirmCheckoutParams) => Promise<{ data: CommerceCheckoutResource; error: null; } | { data: null; error: ClerkAPIResponseError; }>` Confirms the checkout, typically after the user has entered payment details. --- - - `complete()` + - `finalize()` - `(params?: { redirectUrl: string }) => void` Finalizes the checkout process. Can optionally accept a `redirectUrl` to navigate the user to upon completion. @@ -216,7 +216,7 @@ The `useCheckout()` hook can be used with a context provider for managing state ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} - import { CheckoutProvider } from '@clerk/clerk-react' // Fictional import path + import { CheckoutProvider } from '@clerk/clerk-react/experimental' import { CheckoutFlow } from './CheckoutFlow' export function SubscriptionPage() { @@ -237,7 +237,7 @@ The `useCheckout()` hook can be used with a context provider for managing state ```tsx {{ filename: 'src/components/CheckoutFlow.tsx', collapsible: true }} - import { useCheckout } from '@clerk/clerk-react' // Fictional import path + import { useCheckout } from '@clerk/clerk-react/experimental' export function CheckoutFlow() { // `useCheckout` reads context from the nearest `` @@ -249,7 +249,7 @@ The `useCheckout()` hook can be used with a context provider for managing state // This will create the checkout session on the backend await start() // Next steps would involve using a payment element (e.g., Stripe) - // and then calling `checkout.confirm()` and `checkout.complete()`. + // and then calling `checkout.confirm()` and `checkout.finalize()`. } catch (e) { console.error('Error starting checkout:', e) } @@ -277,7 +277,7 @@ The `useCheckout()` hook can be used with a context provider for managing state The following example shows an `` component that manages its own checkout flow. ```tsx {{ filename: 'src/components/UpgradeButton.tsx' }} - import { useCheckout } from '@clerk/clerk-react' // Fictional import path + import { useCheckout } from '@clerk/clerk-react/experimental' export function UpgradeButton({ planId, planPeriod }) { // Pass options directly to the hook when not using a provider. diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx index 1a2558cfb4..1fec2c47d2 100644 --- a/docs/hooks/use-payment-element.mdx +++ b/docs/hooks/use-payment-element.mdx @@ -5,13 +5,13 @@ description: Clerk's usePaymentElement() hook provides methods and state for int -The `usePaymentElement()` hook is used to control the payment form rendered by the `` component. It provides the necessary state and methods to submit payment details to a payment provider like Stripe. +The `usePaymentElement()` hook is used to control the payment form rendered by the `` component. It provides the necessary state and methods to submit payment details to a payment provider like Stripe. This hook must be used within a component that is a descendant of the `` component. It is typically used in a checkout flow that prompts a user to add a new payment method, or for adding a new payment method outside of a checkout. ## Payment element components -The `usePaymentElement()` hook works in conjunction with the `` and `` components. +The `usePaymentElement()` hook works in conjunction with the `` and `` components. ### `` @@ -45,7 +45,7 @@ This provider component sets up the context for the payment element. It fetches An optional description to display to the user within the payment element UI. -### `` +### `` This component renders the actual payment form from the provider (e.g., the Stripe Payment Element). It should be rendered as a child of ``. @@ -104,7 +104,7 @@ The following example shows the basic structure for adding a new payment method. ```tsx {{ filename: 'src/components/AddPaymentMethodView.tsx' }} - import { PaymentElementProvider, PaymentElementForm } from '@clerk/nextjs' + import { PaymentElementProvider, PaymentElement } from '@clerk/nextjs/experimental' import { PaymentForm } from './PaymentForm' import { PaymentFormSkeleton } from './PaymentFormSkeleton' @@ -116,10 +116,10 @@ The following example shows the basic structure for adding a new payment method.

Your payment details will be saved securely for future purchases.

{/* The form component renders the payment UI */} - }> + }> {/* The child component handles form interaction */} - +
) } @@ -128,7 +128,7 @@ The following example shows the basic structure for adding a new payment method. ```tsx {{ filename: 'src/components/PaymentForm.tsx' }} - import { usePaymentElement } from '@clerk/nextjs' + import { usePaymentElement } from '@clerk/nextjs/experimental' import { useState } from 'react' export function PaymentForm() { @@ -159,7 +159,7 @@ The following example shows the basic structure for adding a new payment method. return ( - {/* The actual payment fields are rendered by */} + {/* The actual payment fields are rendered by */} diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index db1ffc1d8d..4469452e1f 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -164,7 +164,7 @@ Each payment method object contains the following properties: The following example demonstrates how to fetch and display a user's payment methods. ```tsx -import { usePaymentMethods } from '@clerk/nextjs' +import { usePaymentMethods } from '@clerk/nextjs/experimental' function PaymentMethodsList() { const { data, isLoading } = usePaymentMethods({ @@ -194,7 +194,7 @@ function PaymentMethodsList() { The following example demonstrates how to implement infinite scrolling with payment methods. ```tsx -import { usePaymentMethods } from '@clerk/nextjs' +import { usePaymentMethods } from '@clerk/nextjs/experimental' function InfinitePaymentMethods() { const { data, isLoading, hasNextPage, fetchNext } = usePaymentMethods({ @@ -230,7 +230,7 @@ function InfinitePaymentMethods() { The following example demonstrates how to use `usePaymentMethods` in a checkout flow to select an existing payment method. ```tsx -import { usePaymentMethods, useCheckout } from '@clerk/nextjs' +import { usePaymentMethods, useCheckout } from '@clerk/nextjs/experimental' function CheckoutPaymentSelection() { const { data, isLoading } = usePaymentMethods({ for: 'user' }) diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index d0071e034a..641b475b06 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -205,7 +205,7 @@ Each feature object contains the following properties: The following example shows how to fetch and display available plans. ```tsx -import { usePlans } from '@clerk/nextjs' +import { usePlans } from '@clerk/nextjs/experimental' function PlansList() { const { data, isLoading } = usePlans({ diff --git a/docs/hooks/use-subscription.mdx b/docs/hooks/use-subscription.mdx index 1033ca40fc..f316f15e75 100644 --- a/docs/hooks/use-subscription.mdx +++ b/docs/hooks/use-subscription.mdx @@ -132,7 +132,7 @@ Each subscription object contains the following properties: The following example shows how to fetch and display subscription information. ```tsx -import { useSubscription } from '@clerk/nextjs' +import { useSubscription } from '@clerk/nextjs/experimental' function SubscriptionInfo() { const { data, isLoading, error } = useSubscription() @@ -163,7 +163,7 @@ function SubscriptionInfo() { The following example shows how to fetch an organization's subscription. ```tsx -import { useSubscription } from '@clerk/nextjs' +import { useSubscription } from '@clerk/nextjs/experimental' function OrganizationSubscription() { const { data, isLoading, revalidate } = useSubscription({ @@ -195,7 +195,7 @@ function OrganizationSubscription() { The following example shows how to handle subscription data with proper error states. ```tsx -import { useSubscription } from '@clerk/nextjs' +import { useSubscription } from '@clerk/nextjs/experimental' function SubscriptionStatus() { const { data, isLoading, error, isFetching } = useSubscription() @@ -230,7 +230,7 @@ function SubscriptionStatus() { ``` ```tsx -import { useSubscription } from '@clerk/nextjs' +import { useSubscription } from '@clerk/nextjs/experimental' function SubscriptionDetails() { const { data: subscription, isLoading } = useSubscription() From 0777d6399d3a4b383943cfc0e5cc32d125bd592e Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 25 Jul 2025 22:10:59 +0300 Subject: [PATCH 20/36] address comment about return object --- docs/hooks/use-checkout.mdx | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index e80c19b1dd..f11ceac298 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -61,20 +61,9 @@ There are two ways to use `useCheckout()`: The billing period for the plan.
-## Returns +## Returns `{ checkout }` - - - `checkout` - - `object` - - Specify the checkout resource properties, state helpers, and methods. - - -The `checkout` object contains the following: - -### Resource properties - -These properties describe the checkout resource itself. They are `null` until the checkout process is started by calling the `start()` method. +The `checkout` object contains the following properties. They are `null` until the checkout process is started by calling the `start()` method. - `id` From 2ed529194f96f3e8bbe111c71984260ab4596bf0 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Sat, 26 Jul 2025 11:39:24 +0300 Subject: [PATCH 21/36] improve useCheckout snippets --- .../checkout-existing-payment-method.mdx | 2 +- .../checkout-new-payment-method.mdx | 2 +- docs/hooks/use-checkout.mdx | 88 +++++++++++++++---- docs/hooks/use-payment-methods.mdx | 2 +- 4 files changed, 73 insertions(+), 21 deletions(-) diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index ea791da787..a13ffadd73 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -109,7 +109,7 @@ This guide will walk you through how to build a custom checkout flow using an ex paymentSourceId: (selectedMethod || defaultMethod)?.id, }) // Complete checkout and redirect - await complete({ redirectUrl: '/dashboard' }) + await finalize({ redirectUrl: '/dashboard' }) } catch (error) { console.error('Payment failed:', error) } finally { diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index a4cc5e7015..f39b2f0d0b 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -115,7 +115,7 @@ This guide will walk you through how to build a custom checkout flow with a new // Confirm checkout with payment method await confirm(data) // Complete checkout and redirect - await complete({ redirectUrl: '/dashboard' }) + await finalize({ redirectUrl: '/dashboard' }) } catch (error) { console.error('Payment failed:', error) } finally { diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index f11ceac298..fc31d73a91 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -56,7 +56,7 @@ There are two ways to use `useCheckout()`: --- - `planPeriod` - - `'monthly' | 'yearly'` + - `'month' | 'annual'` The billing period for the plan. @@ -95,7 +95,7 @@ The `checkout` object contains the following properties. They are `null` until t --- - `planPeriod` - - `'monthly' | 'yearly' | null` + - `'month' | 'annual' | null` The billing period for the plan. @@ -212,7 +212,7 @@ The `useCheckout()` hook can be used with a context provider for managing state // The provider sets the context for the checkout flow. // Any child component can now call `useCheckout()` to access this context. return ( - +

Upgrade Your Plan

You are about to subscribe to our monthly plan.

@@ -229,29 +229,81 @@ The `useCheckout()` hook can be used with a context provider for managing state import { useCheckout } from '@clerk/clerk-react/experimental' export function CheckoutFlow() { - // `useCheckout` reads context from the nearest `` const { checkout } = useCheckout() - const { start, status, isStarting, error } = checkout + const { status } = checkout + + if (status === 'awaiting_initialization') { + return + } + + return ( +
+ + +
+ ) + } + + function CheckoutInitialization() { + const { checkout } = useCheckout() + const { start, status, fetchStatus } = checkout + + return ( + + ) + } + + function PaymentSection() { + const { checkout } = useCheckout() + + const { isConfirming, confirm, complete, error } = checkout + + const [isProcessing, setIsProcessing] = useState(false) + const [selectedMethod, setSelectedMethod] = useState<(typeof data)[number] | null>(null) + + const submitSelectedMethod = async () => { + if (isProcessing || !selectedMethod) return + setIsProcessing(true) - const handleStartCheckout = async () => { try { - // This will create the checkout session on the backend - await start() - // Next steps would involve using a payment element (e.g., Stripe) - // and then calling `checkout.confirm()` and `checkout.finalize()`. - } catch (e) { - console.error('Error starting checkout:', e) + // Confirm checkout with payment method + await confirm({ + paymentSourceId: selectedMethod.id, + }) + // Calling `.complete` enables you to sync the client side state with the server side state of your users. + // It revalidates all authorization checks computed within server components. + await complete({ redirectUrl: '/dashboard' }) + } catch (error) { + console.error('Payment failed:', error) + } finally { + setIsProcessing(false) } } return ( -
-

Current status: {status}

- - {error &&

Error: {error.errors[0].message}

} - {status === 'starting' &&

Redirecting to payment...

} + + ) + } + + function CheckoutSummary() { + const { checkout } = useCheckout() + const { plan, totals } = checkout + + return ( +
+

Order Summary

+ {plan?.name} + {totals?.totalDueNow.currencySymbol}{totals?.totalDueNow.amountFormatted}
) } diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index 4469452e1f..4942d10625 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -242,7 +242,7 @@ function CheckoutPaymentSelection() { // Confirm checkout with selected payment method await confirm({ paymentSourceId: paymentMethodId }) // Complete checkout and redirect - await complete({ redirectUrl: '/dashboard' }) + await finalize({ redirectUrl: '/dashboard' }) } catch (error) { console.error('Payment failed:', error) } From 9e0c68840f8f977e0800246a3fdc9825cc3622f5 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Sat, 26 Jul 2025 13:22:39 +0300 Subject: [PATCH 22/36] format --- docs/hooks/use-checkout.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index fc31d73a91..e5d73c6930 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -303,7 +303,10 @@ The `useCheckout()` hook can be used with a context provider for managing state

Order Summary

{plan?.name} - {totals?.totalDueNow.currencySymbol}{totals?.totalDueNow.amountFormatted} + + {totals?.totalDueNow.currencySymbol} + {totals?.totalDueNow.amountFormatted} +
) } From d24223756919133bead28d74799fe9c14942ffe6 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 29 Jul 2025 15:39:26 +0300 Subject: [PATCH 23/36] improve ref types --- .../checkout-existing-payment-method.mdx | 12 +- .../checkout-new-payment-method.mdx | 12 +- docs/hooks/use-payment-element.mdx | 4 +- docs/hooks/use-payment-methods.mdx | 24 ++-- docs/hooks/use-plans.mdx | 108 +++++++++++++-- docs/hooks/use-subscription.mdx | 126 +++++++++++++++++- 6 files changed, 248 insertions(+), 38 deletions(-) diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index a13ffadd73..0e6ce840fc 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -31,7 +31,7 @@ This guide will walk you through how to build a custom checkout flow using an ex 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways: 1. Copy from the Clerk Dashboard. 1. Use the [Clerk Backend API](TBD). - 1. Use the new `usePlans()` hook to get the plan details. + 1. Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. This example is written for Next.js App Router but can be adapted for any React-based framework. @@ -153,11 +153,17 @@ This guide will walk you through how to build a custom checkout flow using an ex const { checkout } = useCheckout() const { plan, totals } = checkout + if (!plan) { + return null + } + return (

Order Summary

- {plan?.name} - \({totals?.totalDueNow.amountFormatted}\) + {plan.name} + + {totals.totalDueNow.currencySymbol} {totals.totalDueNow.amountFormatted} +
) } diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index f39b2f0d0b..f5ecd09211 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -31,7 +31,7 @@ This guide will walk you through how to build a custom checkout flow with a new 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways. 1. Copy from the Clerk Dashboard. 1. Use the [Clerk Backend API](TBD). - 1. Use the new `usePlans()` hook to get the plan details. + 1. Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. This example is written for Next.js App Router but can be adapted for any React-based framework. @@ -140,11 +140,17 @@ This guide will walk you through how to build a custom checkout flow with a new const { checkout } = useCheckout() const { plan, totals } = checkout + if (!plan) { + return null + } + return (

Order Summary

- {plan?.name} - \({totals?.totalDueNow.amountFormatted}\) + {plan.name} + + {totals.totalDueNow.currencySymbol} {totals.totalDueNow.amountFormatted} +
) } diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx index 1fec2c47d2..09a1194e38 100644 --- a/docs/hooks/use-payment-element.mdx +++ b/docs/hooks/use-payment-element.mdx @@ -19,14 +19,14 @@ This provider component sets up the context for the payment element. It fetches - `checkout?` - - `CommerceCheckoutResource` + - [`CommerceCheckoutResource`](/docs/hooks/use-checkout#returns-checkout) An optional checkout resource object. When provided, the payment element is scoped to the specific checkout session. --- - `for?` - - `'user' | 'org'` + - `'user' | 'organization'` Specifies whether the payment method is being added for a user or an organization. Defaults to `'user'`. diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index 4942d10625..d22821d188 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -123,13 +123,6 @@ Each payment method object contains the following properties: --- - - `type` - - `'card'` - - The type of payment method. Currently, only card payments are supported. - - --- - - `cardType` - `string` @@ -144,10 +137,17 @@ Each payment method object contains the following properties: --- - - `expirationDate` - - `string` + - `status` + - `'active' | 'expired' | 'disconnected'` + + The status of the payment method. + + --- + + - `isRemovable` + - `boolean` - The expiration date of the card in 'MM/YY' format. + Whether the payment method can be removed. --- @@ -213,8 +213,8 @@ function InfinitePaymentMethods() { {data?.map((method) => (
  • {method.cardType} ending in {method.last4} -
    - Expires: {method.expirationDate} + {method.status === 'expired' ? ' (Expired)' : null} + {method.status === 'disconnected' ? ' (Disconnected)' : null}
  • ))} diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index 641b475b06..4533f147e4 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -52,7 +52,7 @@ The hook returns an object with the following properties: - `data` - - [`Plan[]`](#plan) | null + - [`CommercePlanResource[]`](#commerce-plan-resource) | null An array of plan objects, or `null` if the data hasn't been loaded yet. @@ -113,7 +113,7 @@ The hook returns an object with the following properties: The total number of plans available. -### `Plan` +### `CommercePlanResource` Each plan object contains the following properties: @@ -142,7 +142,49 @@ Each plan object contains the following properties: - `amount` - `number` - The cost of the plan in cents. + The monthly cost of the plan in cents. + + --- + + - `amountFormatted` + - `string` + + The monthly formatted cost of the plan. + + --- + + - `annualAmount` + - `number` + + The annual cost of the plan in cents. + + --- + + - `annualAmountFormatted` + - `string` + + The formatted annual cost of the plan. + + --- + + - `annualMonthlyAmount` + - `number` + + The monthly cost when billed annually, in cents. + + --- + + - `annualMonthlyAmountFormatted` + - `string` + + The formatted monthly cost when billed annually. + + --- + + - `currencySymbol` + - `string` + + The symbol for the currency (e.g., '$', '€'). --- @@ -153,27 +195,55 @@ Each plan object contains the following properties: --- - - `interval` - - `'monthly' | 'yearly'` + - `isDefault` + - `boolean` - The billing interval for the plan. + Whether this is the default plan. --- - - `features` - - [`PlanFeature[]`](#plan-feature) + - `isRecurring` + - `boolean` - An array of features included in the plan. + Whether the plan is billed on a recurring basis. --- - - `isPublic` + - `hasBaseFee` - `boolean` - Whether the plan is publicly available and visible in components like ``. + Whether the plan includes a base fee. + + --- + + - `forPayerType` + - `'org' | 'user'` + + The type of payer this plan is for. + + --- + + - `publiclyVisible` + - `boolean` + + Whether the plan is publicly visible. + + --- + + - `slug` + - `string` + + The URL-friendly identifier for the plan. + + --- + + - `features` + - [`CommerceFeatureResource[]`](#commerce-feature-resource) + + An array of features included in the plan.
    -### `PlanFeature` +### `CommerceFeatureResource` Each feature object contains the following properties: @@ -196,6 +266,13 @@ Each feature object contains the following properties: - `string` A detailed description of what the feature provides. + + --- + + - `slug` + - `string` + + The URL-friendly identifier for the feature. ## Examples @@ -223,8 +300,13 @@ function PlansList() {
  • {plan.name}

    {plan.description}

    +

    Is free plan: {!plan.hasBaseFee ? 'Yes' : 'No'}

    +

    + Price per month: {plan.currency} {plan.amountFormatted} +

    - {(plan.amount / 100).toFixed(2)} {plan.currency} / {plan.interval} + Price per year: {plan.currency} {plan.annualAmountFormatted} equivalent to{' '} + {plan.currency} {plan.annualMonthlyAmountFormatted} per month

    Features:

      diff --git a/docs/hooks/use-subscription.mdx b/docs/hooks/use-subscription.mdx index f316f15e75..3e335241bf 100644 --- a/docs/hooks/use-subscription.mdx +++ b/docs/hooks/use-subscription.mdx @@ -32,7 +32,7 @@ The `useSubscription()` hook provides access to subscription information for use - `data` - - [`Subscription`](#subscription) | null + - [`CommerceSubscriptionResource`](#commerce-subscription-resource) | null The subscription object, or `null` if the data hasn't been loaded yet. @@ -65,7 +65,7 @@ The `useSubscription()` hook provides access to subscription information for use Function to manually trigger a refresh of the subscription data. -### `Subscription` +### `CommerceSubscriptionResource` Each subscription object contains the following properties: @@ -78,7 +78,7 @@ Each subscription object contains the following properties: --- - `status` - - `CommerceSubscriptionStatus` + - `'active' | 'past_due'` The current status of the subscription. @@ -113,7 +113,7 @@ Each subscription object contains the following properties: --- - `nextPayment` - - `{ amount: CommerceMoney; time: Date; } | null` + - `{ amount: CommerceMoney; date: Date; } | null` Information about the next payment, including the amount and scheduled time. Returns `null` if no upcoming payment. @@ -125,6 +125,122 @@ Each subscription object contains the following properties: An array of items included in this subscription. +### `CommerceSubscriptionItemResource` + +Each subscription item object contains the following properties: + + + - `id` + - `string` + + The unique identifier for the subscription item. + + --- + + - `paymentSourceId` + - `string` + + The identifier of the payment source used for this subscription. + + --- + + - `plan` + - [`CommercePlanResource`](/docs/hooks/use-plans#commerce-plan-resource) + + The plan associated with this subscription item. + + --- + + - `planPeriod` + - `'month' | 'annual'` + + The billing period of the subscription. + + --- + + - `status` + - `'active' | 'ended' | 'upcoming' | 'past_due'` + + The current status of the subscription. + + --- + + - `createdAt` + - `Date` + + The date when the subscription was created. + + --- + + - `pastDueAt` + - `Date | null` + + The date when the subscription became past due, if applicable. + + --- + + - `periodStartDate` + - `Date` + + The start date of the current billing period. + + --- + + - `periodEndDate` + - `Date | null` + + The end date of the current billing period. + + --- + + - `canceledAtDate` + - `Date | null` + + The date when the subscription was canceled, if applicable. + + --- + + - `periodStart` + - `number` + + The Unix timestamp for the start of the current billing period. + + --- + + - `periodEnd` + - `number` + + The Unix timestamp for the end of the current billing period. + + --- + + - `canceledAt` + - `number | null` + + The Unix timestamp when the subscription was canceled, if applicable. + + --- + + - `amount` + - `CommerceMoney | undefined` + + The amount charged for this subscription item. + + --- + + - `credit` + - `{ amount: CommerceMoney } | undefined` + + Credit information for this subscription item, if any. + + --- + + - `cancel` + - `(params: CancelSubscriptionParams) => Promise` + + A function to cancel this subscription item. + + ## Examples ### Basic usage @@ -261,7 +377,7 @@ function SubscriptionDetails() {

      Next Payment

      Amount: {subscription.nextPayment.amount}

      -

      Due: {subscription.nextPayment.time.toLocaleDateString()}

      +

      Due: {subscription.nextPayment.date.toLocaleDateString()}

      )} From 0bdaf6608fd97aada5a9bb26aee2982e2661a553 Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:14:32 -0400 Subject: [PATCH 24/36] docs review pt 1 --- .../billing/use-checkout-options.mdx | 20 ++ docs/billing/b2b-saas.mdx | 4 +- docs/billing/b2c-saas.mdx | 4 +- .../{ => billing}/checkout-button.mdx | 0 .../{ => billing}/plan-details-button.mdx | 0 .../{ => billing}/pricing-table.mdx | 0 .../subscription-details-button.mdx | 0 docs/custom-flows/add-new-payment-methods.mdx | 12 +- .../checkout-existing-payment-method.mdx | 2 +- .../checkout-new-payment-method.mdx | 2 +- docs/hooks/use-checkout.mdx | 153 +++++------ docs/hooks/use-payment-element.mdx | 96 +++---- docs/hooks/use-payment-methods.mdx | 62 +---- docs/hooks/use-plans.mdx | 219 ++++------------ docs/hooks/use-subscription.mdx | 246 +++--------------- docs/manifest.json | 44 +++- .../javascript/types/clerk-api-error.mdx | 120 +++++++-- .../types/clerk-api-response-error.mdx | 50 ++++ .../types/commerce-checkout-resource.mdx | 128 +++++++++ .../types/commerce-checkout-totals.mdx | 50 ++++ .../types/commerce-feature-resource.mdx | 43 +++ .../javascript/types/commerce-money.mdx | 38 +++ .../commerce-payment-source-resource.mdx | 82 ++++++ .../types/commerce-plan-resource.mdx | 141 ++++++++++ .../commerce-subscription-item-resource.mdx | 122 +++++++++ .../types/commerce-subscription-resource.mdx | 64 +++++ redirects/static/docs.json | 20 ++ 27 files changed, 1125 insertions(+), 597 deletions(-) create mode 100644 docs/_partials/billing/use-checkout-options.mdx rename docs/components/{ => billing}/checkout-button.mdx (100%) rename docs/components/{ => billing}/plan-details-button.mdx (100%) rename docs/components/{ => billing}/pricing-table.mdx (100%) rename docs/components/{ => billing}/subscription-details-button.mdx (100%) create mode 100644 docs/references/javascript/types/clerk-api-response-error.mdx create mode 100644 docs/references/javascript/types/commerce-checkout-resource.mdx create mode 100644 docs/references/javascript/types/commerce-checkout-totals.mdx create mode 100644 docs/references/javascript/types/commerce-feature-resource.mdx create mode 100644 docs/references/javascript/types/commerce-money.mdx create mode 100644 docs/references/javascript/types/commerce-payment-source-resource.mdx create mode 100644 docs/references/javascript/types/commerce-plan-resource.mdx create mode 100644 docs/references/javascript/types/commerce-subscription-item-resource.mdx create mode 100644 docs/references/javascript/types/commerce-subscription-resource.mdx diff --git a/docs/_partials/billing/use-checkout-options.mdx b/docs/_partials/billing/use-checkout-options.mdx new file mode 100644 index 0000000000..9989b54fac --- /dev/null +++ b/docs/_partials/billing/use-checkout-options.mdx @@ -0,0 +1,20 @@ + + - `for?` + - `'organization'` + + Specifies if the checkout is for an organization. If omitted, the checkout defaults to the current user. + + --- + + - `planId` + - `string` + + The ID of the subscription plan to check out (e.g., `cplan_123`). + + --- + + - `planPeriod` + - `'month' | 'annual'` + + The billing period for the plan. + diff --git a/docs/billing/b2b-saas.mdx b/docs/billing/b2b-saas.mdx index 93403483ce..f14ad0bdaf 100644 --- a/docs/billing/b2b-saas.mdx +++ b/docs/billing/b2b-saas.mdx @@ -1,7 +1,7 @@ --- title: Clerk billing for B2B SaaS description: Clerk billing is a feature that allows you to create and manage plans and features for your application. -sdk: nextjs, react, expo, react-router, astro, tanstack-react-start, remix, nuxt, vue, js-frontend, expressjs, fastify, js-backend +sdk: nextjs, react, expo, react-router, astro, tanstack-react-start, remix, nuxt, vue, js-frontend, expressjs, fastify, js-backend --- @@ -42,7 +42,7 @@ You can add a feature to a plan when you are creating a plan. To add it after a ## Create a pricing page -You can create a pricing page by using the [``](/docs/components/pricing-table) component. This component displays a table of plans and features that customers can subscribe to. **It's recommended to create a dedicated page**, as shown in the following example. +You can create a pricing page by using the [``](/docs/components/billing/pricing-table) component. This component displays a table of plans and features that customers can subscribe to. **It's recommended to create a dedicated page**, as shown in the following example. diff --git a/docs/billing/b2c-saas.mdx b/docs/billing/b2c-saas.mdx index 72ca3acac2..86b56905c4 100644 --- a/docs/billing/b2c-saas.mdx +++ b/docs/billing/b2c-saas.mdx @@ -1,7 +1,7 @@ --- title: Clerk billing for B2C SaaS description: Clerk billing is a feature that allows you to create and manage plans and features for your application. -sdk: nextjs, react, expo, react-router, astro, tanstack-react-start, remix, nuxt, vue, js-frontend, expressjs, fastify, js-backend +sdk: nextjs, react, expo, react-router, astro, tanstack-react-start, remix, nuxt, vue, js-frontend, expressjs, fastify, js-backend --- @@ -42,7 +42,7 @@ You can add a feature to a plan when you are creating a plan. To add it after a ## Create a pricing page -You can create a pricing page by using the [``](/docs/components/pricing-table) component. This component displays a table of plans and features that users can subscribe to. **It's recommended to create a dedicated page**, as shown in the following example. +You can create a pricing page by using the [``](/docs/components/billing/pricing-table) component. This component displays a table of plans and features that users can subscribe to. **It's recommended to create a dedicated page**, as shown in the following example. diff --git a/docs/components/checkout-button.mdx b/docs/components/billing/checkout-button.mdx similarity index 100% rename from docs/components/checkout-button.mdx rename to docs/components/billing/checkout-button.mdx diff --git a/docs/components/plan-details-button.mdx b/docs/components/billing/plan-details-button.mdx similarity index 100% rename from docs/components/plan-details-button.mdx rename to docs/components/billing/plan-details-button.mdx diff --git a/docs/components/pricing-table.mdx b/docs/components/billing/pricing-table.mdx similarity index 100% rename from docs/components/pricing-table.mdx rename to docs/components/billing/pricing-table.mdx diff --git a/docs/components/subscription-details-button.mdx b/docs/components/billing/subscription-details-button.mdx similarity index 100% rename from docs/components/subscription-details-button.mdx rename to docs/components/billing/subscription-details-button.mdx diff --git a/docs/custom-flows/add-new-payment-methods.mdx b/docs/custom-flows/add-new-payment-methods.mdx index 9efa0cfcd2..973552925e 100644 --- a/docs/custom-flows/add-new-payment-methods.mdx +++ b/docs/custom-flows/add-new-payment-methods.mdx @@ -10,7 +10,7 @@ This guide will walk you through how to build a flow for adding a new payment me ### Enable billing features - To use billing features, you first need to ensure they are enabled for your application. Please follow the [Billing documentation](/docs/billing/overview) to enable them and set up your plans. + To use billing features, you first need to ensure they are enabled for your application. Follow the [Billing documentation](/docs/billing/overview) to enable them and set up your plans. ### Add payment method flow @@ -28,15 +28,15 @@ This guide will walk you through how to build a flow for adding a new payment me - **``**: This component sets up the ``. - **``**: This component renders the payment form and handles the submission logic using the `usePaymentElement` and `useUser` hooks. - + ", ""]}> This component is responsible for setting up the provider context. It specifies that the payment actions within its children are `for` the `user`. - ```tsx {{ filename: 'src/components/UserBillingPage.tsx' }} + ```tsx {{ filename: 'app/user/billing/page.tsx' }} import { PaymentElementProvider } from '@clerk/nextjs/experimental' import { AddPaymentMethodForm } from './AddPaymentMethodForm' - export function UserBillingPage() { + export function Page() { return (

      Billing Settings

      @@ -52,9 +52,9 @@ This guide will walk you through how to build a flow for adding a new payment me - This component contains the form and the logic to handle the submission. It uses `usePaymentElement` to get the `submit` function and `useUser` to get the `user` object. When the form is submitted, it first creates a payment token and then attaches it to the user. + This component contains the form and the logic to handle the submission. It uses `usePaymentElement()` to get the `submit` function and `useUser()` to get the `user` object. When the form is submitted, it first creates a payment token and then attaches it to the user. - ```tsx {{ filename: 'src/components/AddPaymentMethodForm.tsx' }} + ```tsx {{ filename: 'app/user/billing/AddPaymentMethodForm.tsx' }} import { useUser } from '@clerk/nextjs' import { usePaymentElement, PaymentElement } from '@clerk/nextjs/experimental' import { useState } from 'react' diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index 0e6ce840fc..5a265e074f 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -10,7 +10,7 @@ This guide will walk you through how to build a custom checkout flow using an ex ## Enable billing features - To use billing features, you first need to ensure they are enabled for your application. Please follow the [Billing documentation](/docs/billing/overview) to enable them and setup your plans. + To use billing features, you first need to ensure they are enabled for your application. Follow the [Billing documentation](/docs/billing/overview) to enable them and setup your plans. ## Checkout flow diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index f5ecd09211..39fa543f6f 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -10,7 +10,7 @@ This guide will walk you through how to build a custom checkout flow with a new ## Enable billing features - To use billing features, you first need to ensure they are enabled for your application. Please follow the [Billing documentation](/docs/billing/overview) to enable them and setup your plans. + To use billing features, you first need to ensure they are enabled for your application. Follow the [Billing documentation](/docs/billing/overview) to enable them and setup your plans. ## Checkout flow diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index e5d73c6930..014df9e87e 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -5,95 +5,68 @@ description: Clerk's useCheckout() hook provides state and methods to manage a s -The `useCheckout()` hook is used to create, manage, and confirm a checkout session for a user or an organization's subscription plan. The hook provides the state of the current checkout process, such as its status and any errors, along with methods to initiate and complete the checkout. +The `useCheckout()` hook is used to create, manage, and confirm a checkout session for a user or an organization's subscription plan. It provides the state of the current checkout process, such as its status and any errors, along with methods to initiate and complete the checkout. There are two ways to use `useCheckout()`: -1. In conjunction with `` to create a shared checkout context. All child components inside the provider can then use `useCheckout()` to access or update the same checkout state. -1. Using `useCheckout()` on its own by passing configuration options directly to it. This is ideal for self-contained components that handle their own checkout flow without needing a shared context. - -> [!IMPORTANT] -> For the best user experience and to prevent potential errors, always wrap components using `useCheckout()` with both `` and `` components. This ensures that the user is properly authenticated and Clerk is fully initialized before accessing checkout functionality. -> -> ```tsx -> import { ClerkLoaded, SignedIn } from '@clerk/nextjs' -> -> function CheckoutPage() { -> return ( -> -> -> -> -> -> ) -> } -> ``` +1. In conjunction with [``](#checkout-provider) to create a shared checkout context. All child components inside the provider can then use `useCheckout()` to access or update the same checkout state. +1. On its own by passing configuration options directly to it. This is ideal for self-contained components that handle their own checkout flow without needing a shared context. ## Parameters +`useCheckout()` accepts a single object with the following properties: + - `options?` - [`UseCheckoutOptions`](#use-checkout-options) - An object containing the configuration for the checkout flow. This is **required** if the hook is used without a `` wrapping the component tree. + **Required** if the hook is used without a `` wrapping the component tree. An object containing the configuration for the checkout flow. ### `UseCheckoutOptions` - - - `for?` - - `'organization'` + - Specifies if the checkout is for an organization. If omitted, the checkout defaults to the current user. +## Returns - --- +`useCheckout()` returns a `{ checkout }` object. The `checkout` object contains the following properties. They are `null` until the checkout process is started by calling the `start()` method. - - `planId` - - `string` + + - `id` + - `string | null` - The ID of the subscription plan to check out (e.g., `cplan_xxxx`). + The unique identifier for the checkout session. --- - - `planPeriod` - - `'month' | 'annual'` - - The billing period for the plan. - + - `externalClientSecret` + - `string | null` -## Returns `{ checkout }` + The client secret from an external payment provider (such as Stripe) used to complete the payment on the client-side. -The `checkout` object contains the following properties. They are `null` until the checkout process is started by calling the `start()` method. + --- - - - `id` + - `externalGatewayId` - `string | null` - The unique identifier for the checkout resource. + The identifier for the external payment gateway used for the checkout session. --- - `paymentSource` - - `object | null` + - [CommercePaymentSourceResource](/docs/references/javascript/types/commerce-payment-source-resource) | null The payment source being used for the checkout. --- - `plan` - - `object | null` + - [CommercePlanResource](/docs/references/javascript/types/commerce-plan-resource) | null The subscription plan details for the checkout. --- - - `externalClientSecret` - - `string | null` - - The client secret from an external payment provider, like Stripe, used to complete the payment on the client-side. - - --- - - `planPeriod` - `'month' | 'annual' | null` @@ -102,53 +75,49 @@ The `checkout` object contains the following properties. They are `null` until t --- - `planPeriodStart` - - `Date | null` + - `number | undefined` - The start date of the plan period. + The start date of the plan period, represented as a Unix timestamp. --- - - `totals` - - `object | null` + - `status` + - `'awaiting_initialization' | 'awaiting_confirmation' | 'completed'` - The total costs, taxes, and other pricing details. + The current status of the checkout session. --- - - `isImmediatePlanChange` - - `boolean | null` - - Indicates if the plan change will take effect immediately. - + - `totals` + - [`CommerceCheckoutTotals`](/docs/references/javascript/types/commerce-checkout-totals) -### State helpers + The total costs, taxes, and other pricing details. -These properties provide information about the current state of the hook's operations. + --- - - - `status` - - `'awaiting_initialization' | 'awaiting_confirmation' | 'completed'` + - `isImmediatePlanChange` + - `boolean` - The current status of the checkout flow. + A boolean that indicates if the plan change will take effect immediately. --- - `isStarting` - `boolean` - Returns `true` when the `start()` method is in progress. + A boolean that indicates if the `start()` method is in progress. --- - `isConfirming` - `boolean` - Returns `true` when the `confirm()` method is in progress. + A boolean that indicates if the `confirm()` method is in progress. --- - `error` - - `ClerkAPIResponseError | null` + - [ClerkAPIResponseError](/docs/references/javascript/types/clerk-api-response-error) | null Returns an error object if any part of the checkout process fails. @@ -157,52 +126,70 @@ These properties provide information about the current state of the hook's opera - `fetchStatus` - `'idle' | 'fetching' | 'error'` - The data fetching status for the checkout resource. - - -### Methods + The data fetching status. -These methods are used to control the checkout flow. + --- - - `start()` - `() => Promise<{ data: CommerceCheckoutResource; error: null; } | { data: null; error: ClerkAPIResponseError; }>` - Initializes the checkout process by creating a checkout resource on the server. + A function that initializes the checkout process by creating a checkout resource on the server. --- - `confirm()` - `(params: ConfirmCheckoutParams) => Promise<{ data: CommerceCheckoutResource; error: null; } | { data: null; error: ClerkAPIResponseError; }>` - Confirms the checkout, typically after the user has entered payment details. + A function that confirms and finalizes the checkout process, usually after the user has provided and validated payment information. --- - `finalize()` - `(params?: { redirectUrl: string }) => void` - Finalizes the checkout process. Can optionally accept a `redirectUrl` to navigate the user to upon completion. + A function that finalizes the checkout process. Can optionally accept a `redirectUrl` to navigate the user to upon completion. --- - `clear()` - `() => void` - Clears the current checkout state from the cache. + A function that clears the current checkout state from the cache. -## Examples +## `` + +The `` component is a wrapper that provides a checkout context to its children, allowing checkout state to be shared across multiple components. Child components can access the checkout context by calling `useCheckout()`. + +### Properties + + + +## Usage + +For the best user experience and to prevent potential errors, always wrap components using `useCheckout()` with both `` and `` components. This ensures that the user is properly authenticated and Clerk is fully initialized before accessing checkout functionality. + +```tsx +function CheckoutPage() { + return ( + + + + + + ) +} +``` + +### Examples The `useCheckout()` hook can be used with a context provider for managing state across multiple components or as a standalone hook for more isolated use cases. ", "Standalone Hook"]}> - Using the `` is the recommended approach when checkout state needs to be shared across multiple components. The provider is configured once, and any child component can access the checkout context by calling `useCheckout()`. - - The following example shows a `` that sets up the provider and a `` component that consumes the context to manage the checkout UI. + The following example shows the basic structure for a checkout flow. A parent component, ``, sets up the `` and renders the checkout flow. A child component, ``, uses the `useCheckout()` hook to access the checkout state. - + ", ""]}> ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} import { CheckoutProvider } from '@clerk/clerk-react/experimental' @@ -212,7 +199,7 @@ The `useCheckout()` hook can be used with a context provider for managing state // The provider sets the context for the checkout flow. // Any child component can now call `useCheckout()` to access this context. return ( - +

      Upgrade Your Plan

      You are about to subscribe to our monthly plan.

      diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx index 09a1194e38..fdbe0e42e5 100644 --- a/docs/hooks/use-payment-element.mdx +++ b/docs/hooks/use-payment-element.mdx @@ -5,103 +5,109 @@ description: Clerk's usePaymentElement() hook provides methods and state for int -The `usePaymentElement()` hook is used to control the payment form rendered by the `` component. It provides the necessary state and methods to submit payment details to a payment provider like Stripe. +The `usePaymentElement()` hook is used to control the payment form rendered by the [``](#payment-element) component. It provides the necessary state and methods to submit payment details to a payment provider like Stripe. This hook must be used within a component that is a descendant of the `` component. It is typically used in a checkout flow that prompts a user to add a new payment method, or for adding a new payment method outside of a checkout. -## Payment element components +## Parameters -The `usePaymentElement()` hook works in conjunction with the `` and `` components. +`usePaymentElement()` doesn't accept any parameters. It derives its state and configuration from the nearest [``](#payment-element-provider). -### `` +## Returns -This provider component sets up the context for the payment element. It fetches all the necessary data from the payment provider (e.g., Stripe) and makes it available to its children. +`usePaymentElement()` returns an object with the following properties: - - `checkout?` - - [`CommerceCheckoutResource`](/docs/hooks/use-checkout#returns-checkout) + - `submit()` + - `() => Promise<{ data: { gateway: 'stripe'; paymentToken: string } | null; error: PaymentElementError | null}>` - An optional checkout resource object. When provided, the payment element is scoped to the specific checkout session. + A function that submits the payment form data to the payment provider. It returns a promise that resolves with either a `data` object containing a payment token on success, or an `error` object on failure. --- - - `for?` - - `'user' | 'organization'` + - `reset()` + - `() => Promise` - Specifies whether the payment method is being added for a user or an organization. Defaults to `'user'`. + A function that resets the payment form to its initial, empty state. --- - - `stripeAppearance?` - - `object` + - `isFormReady` + - `boolean` - An optional object to customize the appearance of the Stripe Payment Element. This allows you to match the form's styling to your application's theme. + A boolean that indicates if the payment form UI has been rendered and is ready for user input. This is useful for disabling a submit button until the form is interactive. --- - - `paymentDescription?` - - `string` - - An optional description to display to the user within the payment element UI. - + - `isProviderReady` + - `boolean` -### `` + A boolean that indicates if the underlying payment provider (e.g. Stripe) has been fully initialized. -This component renders the actual payment form from the provider (e.g., the Stripe Payment Element). It should be rendered as a child of ``. + --- - - - `fallback?` - - `ReactNode` + - `provider` + - `{ name: 'stripe' } | undefined` - Optional fallback content, such as a loading skeleton, to display while the payment form is being initialized. + An object containing information about the initialized payment provider. It is `undefined` until `isProviderReady` is `true`. -## Parameters +## Payment element components -The `usePaymentElement()` hook does not accept any parameters. It derives its state and configuration from the nearest ``. +The `usePaymentElement()` hook works in conjunction with the `` and `` components. -## Returns +### `` + +The `` component sets up the context for the payment element. It fetches all the necessary data from the payment provider (e.g., Stripe) and makes it available to its children. + +#### Properties - - `submit` - - `() => Promise<{ data: { gateway: 'stripe'; paymentToken: string } | null; error: PaymentElementError | null}>` + - `checkout?` + - [`CommerceCheckoutResource`](/docs/references/javascript/types/commerce-checkout-resource) - A function that submits the payment form data to the payment provider. It returns a promise that resolves with either a `data` object containing a payment token on success, or an `error` object on failure. + An optional checkout resource object. When provided, the payment element is scoped to the specific checkout session. --- - - `reset` - - `() => Promise` + - `for?` + - `'user' | 'organization'` - A function that resets the payment form to its initial, empty state. + Specifies whether the payment method is being added for a user or an organization. Defaults to `'user'`. --- - - `isFormReady` - - `boolean` + - `stripeAppearance?` + - `object` - Returns `true` when the payment form UI has been rendered and is ready for user input. This is useful for disabling a submit button until the form is interactive. + An optional object to customize the appearance of the Stripe Payment Element. This allows you to match the form's styling to your application's theme. --- - - `isProviderReady` - - `boolean` + - `paymentDescription?` + - `string` - Returns `true` when the underlying payment provider (e.g., Stripe.js) has been fully initialized. + An optional description to display to the user within the payment element UI. + - --- +### `` - - `provider` - - `{ name: 'stripe' } | undefined` +This component renders the actual payment form from the provider (e.g., the Stripe Payment Element). It should be rendered as a child of ``. - An object containing information about the initialized payment provider. It is `undefined` until `isProviderReady` is `true`. +#### Properties + + + - `fallback?` + - `ReactNode` + + Optional fallback content, such as a loading skeleton, to display while the payment form is being initialized. ## Examples The following example shows the basic structure for adding a new payment method. A parent component, ``, sets up the provider and renders the form. A child component, ``, uses the `usePaymentElement()` hook to handle the form submission. - +", ""]}> ```tsx {{ filename: 'src/components/AddPaymentMethodView.tsx' }} import { PaymentElementProvider, PaymentElement } from '@clerk/nextjs/experimental' diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index d22821d188..a1d0ee030f 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -48,11 +48,13 @@ The `usePaymentMethods()` hook provides access to the payment methods associated ## Returns +`usePaymentMethods()` returns an object with the following properties: + - `data` - - [`PaymentMethod[]`](#payment-method) | null + - [CommercePaymentSourceResource](/docs/references/javascript/types/commerce-payment-source-resource)\[] | null - An array of payment method objects, or `null` if the data hasn't been loaded yet. + An array of [payment methods](/docs/references/javascript/types/commerce-payment-source-resource), or `null` if the data hasn't been loaded yet. --- @@ -87,14 +89,14 @@ The `usePaymentMethods()` hook provides access to the payment methods associated - `fetchNext` - `() => Promise` - Function to fetch the next page of payment methods. + A function to fetch the next page of payment methods. --- - `fetchPrevious` - `() => Promise` - Function to fetch the previous page of payment methods. + A function to fetch the previous page of payment methods. --- @@ -111,52 +113,6 @@ The `usePaymentMethods()` hook provides access to the payment methods associated The total number of payment methods available. -### `PaymentMethod` - -Each payment method object contains the following properties: - - - - `id` - - `string` - - The unique identifier for the payment method. - - --- - - - `cardType` - - `string` - - The type of card (e.g., 'visa', 'mastercard'). - - --- - - - `last4` - - `string` - - The last 4 digits of the card number. - - --- - - - `status` - - `'active' | 'expired' | 'disconnected'` - - The status of the payment method. - - --- - - - `isRemovable` - - `boolean` - - Whether the payment method can be removed. - - --- - - - `isDefault` - - `boolean` - - Specifies whether this is the default payment method. - - ## Examples ### Basic usage @@ -227,7 +183,7 @@ function InfinitePaymentMethods() { ### With checkout flow -The following example demonstrates how to use `usePaymentMethods` in a checkout flow to select an existing payment method. +The following example demonstrates how to use `usePaymentMethods()` in a checkout flow to select an existing payment method. ```tsx import { usePaymentMethods, useCheckout } from '@clerk/nextjs/experimental' @@ -235,14 +191,14 @@ import { usePaymentMethods, useCheckout } from '@clerk/nextjs/experimental' function CheckoutPaymentSelection() { const { data, isLoading } = usePaymentMethods({ for: 'user' }) const { checkout } = useCheckout() - const { confirm, complete } = checkout + const { confirm, finalize } = checkout const handlePaymentSubmit = async (paymentMethodId: string) => { try { // Confirm checkout with selected payment method await confirm({ paymentSourceId: paymentMethodId }) // Complete checkout and redirect - await finalize({ redirectUrl: '/dashboard' }) + finalize({ redirectUrl: '/dashboard' }) } catch (error) { console.error('Payment failed:', error) } diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index 4533f147e4..0e5860171c 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -48,13 +48,13 @@ The `usePlans()` hook provides access to the subscription plans available in you ## Returns -The hook returns an object with the following properties: +`usePlans()` returns an object with the following properties: - `data` - [`CommercePlanResource[]`](#commerce-plan-resource) | null - An array of plan objects, or `null` if the data hasn't been loaded yet. + An array of [plans](/docs/references/javascript/types/commerce-plan-resource), or `null` if the data hasn't been loaded yet. --- @@ -89,14 +89,14 @@ The hook returns an object with the following properties: - `fetchNext` - `() => Promise` - Function to fetch the next page of plans. + A function to fetch the next page of plans. --- - `fetchPrevious` - `() => Promise` - Function to fetch the previous page of plans. + A function to fetch the previous page of plans. --- @@ -113,168 +113,6 @@ The hook returns an object with the following properties: The total number of plans available. -### `CommercePlanResource` - -Each plan object contains the following properties: - - - - `id` - - `string` - - The unique identifier for the plan (e.g., `cplan_xxxx`). - - --- - - - `name` - - `string` - - The display name of the plan. - - --- - - - `description` - - `string` - - A detailed description of what the plan offers. - - --- - - - `amount` - - `number` - - The monthly cost of the plan in cents. - - --- - - - `amountFormatted` - - `string` - - The monthly formatted cost of the plan. - - --- - - - `annualAmount` - - `number` - - The annual cost of the plan in cents. - - --- - - - `annualAmountFormatted` - - `string` - - The formatted annual cost of the plan. - - --- - - - `annualMonthlyAmount` - - `number` - - The monthly cost when billed annually, in cents. - - --- - - - `annualMonthlyAmountFormatted` - - `string` - - The formatted monthly cost when billed annually. - - --- - - - `currencySymbol` - - `string` - - The symbol for the currency (e.g., '$', '€'). - - --- - - - `currency` - - `string` - - The three-letter ISO currency code (e.g., 'USD', 'EUR'). - - --- - - - `isDefault` - - `boolean` - - Whether this is the default plan. - - --- - - - `isRecurring` - - `boolean` - - Whether the plan is billed on a recurring basis. - - --- - - - `hasBaseFee` - - `boolean` - - Whether the plan includes a base fee. - - --- - - - `forPayerType` - - `'org' | 'user'` - - The type of payer this plan is for. - - --- - - - `publiclyVisible` - - `boolean` - - Whether the plan is publicly visible. - - --- - - - `slug` - - `string` - - The URL-friendly identifier for the plan. - - --- - - - `features` - - [`CommerceFeatureResource[]`](#commerce-feature-resource) - - An array of features included in the plan. - - -### `CommerceFeatureResource` - -Each feature object contains the following properties: - - - - `id` - - `string` - - The unique identifier for the feature. - - --- - - - `name` - - `string` - - The display name of the feature. - - --- - - - `description` - - `string` - - A detailed description of what the feature provides. - - --- - - - `slug` - - `string` - - The URL-friendly identifier for the feature. - - ## Examples ### Basic usage @@ -320,3 +158,52 @@ function PlansList() { ) } ``` + +### Infinite pagination + +The following example demonstrates how to implement infinite scrolling with plans. + +```tsx +import { usePlans } from '@clerk/nextjs/experimental' + +function InfinitePlansList() { + const { data, isLoading, hasNextPage, fetchNext } = usePlans({ + for: 'user', + infinite: true, + pageSize: 20, + }) + + if (isLoading) { + return
      Loading plans...
      + } + + return ( +
      +
        + {data?.map((plan) => ( +
      • +

        {plan.name}

        +

        {plan.description}

        +

        Is free plan: {!plan.hasBaseFee ? 'Yes' : 'No'}

        +

        + Price per month: {plan.currency} {plan.amountFormatted} +

        +

        + Price per year: {plan.currency} {plan.annualAmountFormatted} equivalent to{' '} + {plan.currency} {plan.annualMonthlyAmountFormatted} per month +

        +

        Features:

        +
          + {plan.features.map((feature) => ( +
        • {feature.name}
        • + ))} +
        +
      • + ))} +
      + + {hasNextPage && } +
      + ) +} +``` diff --git a/docs/hooks/use-subscription.mdx b/docs/hooks/use-subscription.mdx index 3e335241bf..56cfdbd493 100644 --- a/docs/hooks/use-subscription.mdx +++ b/docs/hooks/use-subscription.mdx @@ -30,9 +30,11 @@ The `useSubscription()` hook provides access to subscription information for use ## Returns +`useSubscription()` returns an object with the following properties: + - `data` - - [`CommerceSubscriptionResource`](#commerce-subscription-resource) | null + - [`CommerceSubscriptionResource`](/docs/references/javascript/types/commerce-subscription-resource) | null The subscription object, or `null` if the data hasn't been loaded yet. @@ -65,182 +67,6 @@ The `useSubscription()` hook provides access to subscription information for use Function to manually trigger a refresh of the subscription data. -### `CommerceSubscriptionResource` - -Each subscription object contains the following properties: - - - - `id` - - `string` - - The unique identifier for the subscription. - - --- - - - `status` - - `'active' | 'past_due'` - - The current status of the subscription. - - --- - - - `activeAt` - - `Date` - - The date when the subscription became active. - - --- - - - `createdAt` - - `Date` - - The date when the subscription was created. - - --- - - - `updatedAt` - - `Date | null` - - The date when the subscription was last updated, or `null` if never updated. - - --- - - - `pastDueAt` - - `Date | null` - - The date when the subscription became past due, or `null` if not past due. - - --- - - - `nextPayment` - - `{ amount: CommerceMoney; date: Date; } | null` - - Information about the next payment, including the amount and scheduled time. Returns `null` if no upcoming payment. - - --- - - - `subscriptionItems` - - `CommerceSubscriptionItemResource[]` - - An array of items included in this subscription. - - -### `CommerceSubscriptionItemResource` - -Each subscription item object contains the following properties: - - - - `id` - - `string` - - The unique identifier for the subscription item. - - --- - - - `paymentSourceId` - - `string` - - The identifier of the payment source used for this subscription. - - --- - - - `plan` - - [`CommercePlanResource`](/docs/hooks/use-plans#commerce-plan-resource) - - The plan associated with this subscription item. - - --- - - - `planPeriod` - - `'month' | 'annual'` - - The billing period of the subscription. - - --- - - - `status` - - `'active' | 'ended' | 'upcoming' | 'past_due'` - - The current status of the subscription. - - --- - - - `createdAt` - - `Date` - - The date when the subscription was created. - - --- - - - `pastDueAt` - - `Date | null` - - The date when the subscription became past due, if applicable. - - --- - - - `periodStartDate` - - `Date` - - The start date of the current billing period. - - --- - - - `periodEndDate` - - `Date | null` - - The end date of the current billing period. - - --- - - - `canceledAtDate` - - `Date | null` - - The date when the subscription was canceled, if applicable. - - --- - - - `periodStart` - - `number` - - The Unix timestamp for the start of the current billing period. - - --- - - - `periodEnd` - - `number` - - The Unix timestamp for the end of the current billing period. - - --- - - - `canceledAt` - - `number | null` - - The Unix timestamp when the subscription was canceled, if applicable. - - --- - - - `amount` - - `CommerceMoney | undefined` - - The amount charged for this subscription item. - - --- - - - `credit` - - `{ amount: CommerceMoney } | undefined` - - Credit information for this subscription item, if any. - - --- - - - `cancel` - - `(params: CancelSubscriptionParams) => Promise` - - A function to cancel this subscription item. - - ## Examples ### Basic usage @@ -310,42 +136,7 @@ function OrganizationSubscription() { The following example shows how to handle subscription data with proper error states. -```tsx -import { useSubscription } from '@clerk/nextjs/experimental' - -function SubscriptionStatus() { - const { data, isLoading, error, isFetching } = useSubscription() - - if (error) { - return ( -
      -

      Failed to load subscription

      -

      {error.message}

      - -
      - ) - } - - return ( -
      - {isLoading ? ( -
      Loading...
      - ) : ( - <> -
      {isFetching && Refreshing...}
      - {data ? ( -
      {/* Display subscription details */}
      - ) : ( -
      No active subscription
      - )} - - )} -
      - ) -} -``` - -```tsx +```tsx {{ filename: 'app/pricing/subscription-details/page.tsx' }} import { useSubscription } from '@clerk/nextjs/experimental' function SubscriptionDetails() { @@ -376,7 +167,7 @@ function SubscriptionDetails() { {subscription.nextPayment && (

      Next Payment

      -

      Amount: {subscription.nextPayment.amount}

      +

      Amount: {subscription.nextPayment.amount.amountFormatted}

      Due: {subscription.nextPayment.date.toLocaleDateString()}

      )} @@ -392,4 +183,31 @@ function SubscriptionDetails() {
      ) } + +export default function Page() { + const { data, isLoading, error, isFetching, revalidate } = useSubscription() + + if (error) { + return ( +
      +

      Failed to load subscription

      +

      {error.message}

      + +
      + ) + } + + return ( +
      + {isLoading ? ( +
      Loading...
      + ) : ( + <> +
      {isFetching && Refreshing...}
      + {data ? :
      No active subscription
      } + + )} +
      + ) +} ``` diff --git a/docs/manifest.json b/docs/manifest.json index f4b7e36fbd..a4af12d88a 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -872,25 +872,25 @@ { "title": "``", "wrap": false, - "href": "/docs/components/pricing-table" + "href": "/docs/components/billing/pricing-table" }, { "title": "``", "tag": "(Beta)", "wrap": false, - "href": "/docs/components/checkout-button" + "href": "/docs/components/billing/checkout-button" }, { "title": "``", "tag": "(Beta)", "wrap": false, - "href": "/docs/components/plan-details-button" + "href": "/docs/components/billing/plan-details-button" }, { "title": "``", "tag": "(Beta)", "wrap": false, - "href": "/docs/components/subscription-details-button" + "href": "/docs/components/billing/subscription-details-button" } ] ] @@ -2219,10 +2219,46 @@ "title": "`ClerkAPIError`", "href": "/docs/references/javascript/types/clerk-api-error" }, + { + "title": "`ClerkAPIResponseError`", + "href": "/docs/references/javascript/types/clerk-api-response-error" + }, { "title": "`ClerkPaginatedResponse`", "href": "/docs/references/javascript/types/clerk-paginated-response" }, + { + "title": "`CommerceCheckoutResource`", + "href": "/docs/references/javascript/types/commerce-checkout-resource" + }, + { + "title": "`CommerceCheckoutTotals`", + "href": "/docs/references/javascript/types/commerce-checkout-totals" + }, + { + "title": "`CommerceFeatureResource`", + "href": "/docs/references/javascript/types/commerce-feature-resource" + }, + { + "title": "`CommerceMoney`", + "href": "/docs/references/javascript/types/commerce-money" + }, + { + "title": "`CommercePaymentSourceResource`", + "href": "/docs/references/javascript/types/commerce-payment-source-resource" + }, + { + "title": "`CommercePlanResource`", + "href": "/docs/references/javascript/types/commerce-plan-resource" + }, + { + "title": "`CommerceSubscriptionItemResource`", + "href": "/docs/references/javascript/types/commerce-subscription-item-resource" + }, + { + "title": "`CommerceSubscriptionResource`", + "href": "/docs/references/javascript/types/commerce-subscription-resource" + }, { "title": "`CustomMenuItem`", "href": "/docs/references/javascript/types/custom-menu-item" diff --git a/docs/references/javascript/types/clerk-api-error.mdx b/docs/references/javascript/types/clerk-api-error.mdx index 1e43984dd5..e855c21f11 100644 --- a/docs/references/javascript/types/clerk-api-error.mdx +++ b/docs/references/javascript/types/clerk-api-error.mdx @@ -20,33 +20,113 @@ An interface that represents an error returned by the Clerk API. --- - - `longMessage` + - `longMessage?` - `string` A more detailed message that describes the error. --- - - `meta` + - `meta?` - `object` Additional information about the error. -
      -The `meta` property consists of the following structure: - -```ts {{ prettier: false }} -meta?: { - paramName?: string - sessionId?: string - emailAddresses?: string[] - identifiers?: string[] - zxcvbn?: { - suggestions: { - code: string - message: string - }[] - } - permissions?: string[] -} -``` + --- + + - `meta.paramName?` + - `string` + + The name of the parameter that caused the error. + + --- + + - `meta.sessionId?` + - `string` + + The ID of the session that caused the error. + + --- + + - `meta.emailAddresses?` + - `string[]` + + The email addresses that caused the error. + + --- + + - `meta.identifiers?` + - `string[]` + + The identifiers that caused the error. + + --- + + - `meta.zxcvbn?` + - `object` + + The [zxcvbn](https://github.com/dropbox/zxcvbn) score of the password that caused the error. + + --- + + - `meta.zxcvbn.suggestions?` + - `{ code: string; message: string; }[]` + + Suggestions to improve the password. + + --- + + - `meta.permissions?` + - `string[]` + + The permissions that caused the error. + + --- + + - `meta.plan?` + - `object` + + The plan that caused the error. + + --- + + - `meta.plan.id?` + - `string` + + The ID of the plan that caused the error. + + --- + + - `meta.plan.name?` + - `string` + + The name of the plan. + + --- + + - `meta.plan.amount_formatted?` + - `string` + + The formatted amount of the plan. + + --- + + - `meta.plan.annual_monthly_amount_formatted?` + - `string` + + The formatted annual or monthly amount of the plan. + + --- + + - `meta.plan.currency_symbol?` + - `string` + + The currency symbol of the plan. + + --- + + - `meta.isPlanUpgradePossible?` + - `boolean` + + Whether the plan upgrade is possible. + diff --git a/docs/references/javascript/types/clerk-api-response-error.mdx b/docs/references/javascript/types/clerk-api-response-error.mdx new file mode 100644 index 0000000000..dff85ae6d4 --- /dev/null +++ b/docs/references/javascript/types/clerk-api-response-error.mdx @@ -0,0 +1,50 @@ +--- +title: '`ClerkAPIResponseError`' +description: An interface that represents an error returned by the Clerk API. +--- + +An interface that represents an error returned by the Clerk API. + +## Properties + + + - `clerkError` + - `true` + + Always true, marks this as a Clerk API error. + + --- + + - `status` + - `number` + + The HTTP status code returned by the API. + + --- + + - `message` + - `string` + + The main error message. + + --- + + - `clerkTraceId?` + - `string` + + Optional. A trace ID from Clerk for debugging or support. + + --- + + - `retryAfter?` + - `number` + + Optional. If set, tells you how many seconds to wait before retrying (from `Retry-After` header). + + --- + + - `errors` + - [ClerkAPIError](/docs/references/javascript/types/clerk-api-error)\[] + + An array of error objects with more details about what went wrong. + diff --git a/docs/references/javascript/types/commerce-checkout-resource.mdx b/docs/references/javascript/types/commerce-checkout-resource.mdx new file mode 100644 index 0000000000..98b91e043d --- /dev/null +++ b/docs/references/javascript/types/commerce-checkout-resource.mdx @@ -0,0 +1,128 @@ +--- +title: '`CommerceCheckoutResource`' +description: 'The CommerceCheckoutResource type represents information about a checkout session.' +--- + +The `CommerceCheckoutResource` type represents information about a checkout session. + +## Properties + + + - `id` + - `string` + + The unique identifier for the checkout session. + + --- + + - `externalClientSecret` + - `string` + + A client secret from an external payment provider (such as Stripe) used to complete the payment on the client-side. + + --- + + - `externalGatewayId` + - `string` + + The identifier for the external payment gateway used for this checkout session. + + --- + + - `paymentSource` + - `CommercePaymentSourceResource | undefined` + + The payment source being used for the checkout, such as a credit card or bank account. + + --- + + - `plan` + - `CommercePlanResource` + + The subscription plan details for the checkout. + + --- + + - `planPeriod` + - `'month' | 'annual'` + + The billing period for the plan. + + --- + + - `planPeriodStart` + - `number | undefined` + + The start date of the plan period, represented as a Unix timestamp. + + --- + + - `status` + - `'awaiting_initialization' | 'awaiting_confirmation' | 'completed'` + + The current status of the checkout session. + + --- + + - `totals` + - [`CommerceCheckoutTotals`](/docs/references/javascript/types/commerce-checkout-totals) + + The total costs, taxes, and other pricing details. + + --- + + - `isImmediatePlanChange` + - `boolean` + + A boolean that indicates if the plan change will take effect immediately after checkout. + + --- + + - [`confirm()`](#confirm) + - `(params: ConfirmCheckoutParams) => Promise` + + A method to confirm and finalize the checkout process, usually after payment information has been provided and validated. [Learn more.](#confirm) + + +### `confirm()` + +The `confirm()` function is used to confirm and finalize the checkout process, usually after payment information has been provided and validated. + +#### Parameters + +**Only one of `paymentSourceId`, `paymentToken`, or `useTestCard` should be provided.** + + + - `orgId?` + - `string | undefined` + + The organization ID to perform the checkout for. + + --- + + - `paymentSourceId?` + - `string | undefined` + + The ID of a saved payment source to use for this checkout. + + --- + + - `paymentToken?` + - `string | undefined` + + A token representing payment details, usually from a payment form. Requires `gateway` to be provided. + + --- + + - `useTestCard?` + - `boolean | undefined` + + If true, uses a test card for the checkout. Requires `gateway` to be provided. + + --- + + - `gateway?` + - `PaymentGateway | undefined` + + **Required** if `paymentToken` or `useTestCard` is provided. The payment gateway to use (like `'stripe'`, `'paypal'`, etc). + diff --git a/docs/references/javascript/types/commerce-checkout-totals.mdx b/docs/references/javascript/types/commerce-checkout-totals.mdx new file mode 100644 index 0000000000..bc0cb88072 --- /dev/null +++ b/docs/references/javascript/types/commerce-checkout-totals.mdx @@ -0,0 +1,50 @@ +--- +title: '`CommerceCheckoutTotals`' +description: 'The CommerceCheckoutTotals type represents the total costs, taxes, and other pricing details for a checkout session.' +--- + +The `CommerceCheckoutTotals` type represents the total costs, taxes, and other pricing details for a checkout session. + +## Properties + + + - `subtotal` + - [`CommerceMoney`](/docs/references/javascript/types/commerce-money) + + The price of the items or plan before taxes, credits, or discounts are applied. + + --- + + - `grandTotal` + - [`CommerceMoney`](/docs/references/javascript/types/commerce-money) + + The total amount for the checkout, including taxes and after credits/discounts are applied. This is the final amount due. + + --- + + - `taxTotal` + - [`CommerceMoney`](/docs/references/javascript/types/commerce-money) + + The amount of tax included in the checkout. + + --- + + - `totalDueNow` + - [`CommerceMoney`](/docs/references/javascript/types/commerce-money) + + The amount that needs to be immediately paid to complete the checkout. + + --- + + - `credit` + - [`CommerceMoney`](/docs/references/javascript/types/commerce-money) + + Any credits (like account balance or promo credits) that are being applied to the checkout. + + --- + + - `pastDue` + - [`CommerceMoney`](/docs/references/javascript/types/commerce-money) + + Any outstanding amount from previous unpaid invoices that is being collected as part of the checkout. + diff --git a/docs/references/javascript/types/commerce-feature-resource.mdx b/docs/references/javascript/types/commerce-feature-resource.mdx new file mode 100644 index 0000000000..faa9e3e89d --- /dev/null +++ b/docs/references/javascript/types/commerce-feature-resource.mdx @@ -0,0 +1,43 @@ +--- +title: '`CommerceFeatureResource`' +description: 'The CommerceFeatureResource type represents a feature of a subscription plan.' +--- + +The `CommerceFeatureResource` type represents a feature of a subscription plan. + +## Properties + + + - `id` + - `string` + + The unique identifier for the feature. + + --- + + - `name` + - `string` + + The display name of the feature. + + --- + + - `description` + - `string` + + A short description of what the feature provides. + + --- + + - `slug` + - `string` + + A unique, URL-friendly identifier for the feature. + + --- + + - `avatarUrl` + - `string` + + The URL of the feature's avatar image. + diff --git a/docs/references/javascript/types/commerce-money.mdx b/docs/references/javascript/types/commerce-money.mdx new file mode 100644 index 0000000000..4d1b0e5974 --- /dev/null +++ b/docs/references/javascript/types/commerce-money.mdx @@ -0,0 +1,38 @@ +--- +title: '`CommerceMoney`' +description: 'The CommerceMoney type represents a monetary value with currency information.' +--- + +The `CommerceMoney` type represents a monetary value with currency information. + +## Properties + +{/* TODO: AI filled these descriptions. We need to test what format each of these values are in and update the descriptions accordingly */} + + + - `amount` + - `number` + + The raw amount as a number, usually in the smallest unit of the currency (like cents for USD). + + --- + + - `amountFormatted` + - `string` + + The amount as a formatted string, including currency symbol and separators (like `$10.00`). + + --- + + - `currency` + - `string` + + The ISO currency code for this amount (like `USD`, `EUR`, etc). + + --- + + - `currencySymbol` + - `string` + + The symbol for the currency (like `$`, `€`, `£`). + diff --git a/docs/references/javascript/types/commerce-payment-source-resource.mdx b/docs/references/javascript/types/commerce-payment-source-resource.mdx new file mode 100644 index 0000000000..2046a9fb12 --- /dev/null +++ b/docs/references/javascript/types/commerce-payment-source-resource.mdx @@ -0,0 +1,82 @@ +--- +title: '`CommercePaymentSourceResource`' +description: 'The CommercePaymentSourceResource type represents a payment source for a checkout session.' +--- + +The `CommercePaymentSourceResource` type represents a payment source for a checkout session. + +## Properties + + + - `id` + - `string` + + The unique identifier for the payment method. + + --- + + - `last4` + - `string` + + The last four digits of the payment method. + + --- + + - `paymentMethod` + - `string` + + The type of payment method. For example, `'card'` or `'bank_account'`. + + --- + + - `cardType` + - `string` + + The brand or type of card. For example, `'visa'` or `'mastercard'`. + + --- + + - `isDefault` + - `boolean` + + A boolean that indicates if this payment method is set as the default for the account. + + --- + + - `isRemovable` + - `boolean` + + A boolean that indicates if the payment method can be removed by the user. + + --- + + - `status` + - `'active' | 'expired' | 'disconnected'` + + The current status of the payment method. + + --- + + - `walletType` + - `string | undefined` + + The type of digital wallet, if applicable. For example, `'apple_pay'`, or `'google_pay'`. + + --- + + - `remove()` + - `(params?: RemovePaymentSourceParams) => Promise` + + A function that removes this payment source from the account. Accepts the following parameters: + + - `orgId?` (`string`): The ID of the organization to remove the payment source from. + + --- + + - `makeDefault()` + - `(params?: MakeDefaultPaymentSourceParams) => Promise` + + A function that sets this payment source as the default for the account. Accepts the following parameters: + + - `orgId?` (`string`): The ID of the organization to set as the default. + diff --git a/docs/references/javascript/types/commerce-plan-resource.mdx b/docs/references/javascript/types/commerce-plan-resource.mdx new file mode 100644 index 0000000000..7b666ea0dd --- /dev/null +++ b/docs/references/javascript/types/commerce-plan-resource.mdx @@ -0,0 +1,141 @@ +--- +title: '`CommercePlanResource`' +description: 'The CommercePlanResource type represents a subscription plan with its details.' +--- + +The `CommercePlanResource` type represents a subscription plan with its details. + +## Properties + + + - `id` + - `string` + + The unique identifier for the plan. + + --- + + - `name` + - `string` + + The display name of the plan. + + --- + + - `amount` + - `number` + + The price of the plan for a single billing period (usually monthly). For example, `1000` for `$10.00`. + + --- + + - `amountFormatted` + - `string` + + The formatted price for a single billing period, including currency symbol. For example, `$10.00`. + + --- + + - `annualAmount` + - `number` + + The total price for a full year of the plan, in the smallest unit of the currency. For example, `10000` for `$100.00`. + + --- + + - `annualAmountFormatted` + - `string` + + The formatted price for a full year of the plan, including currency symbol. For example, `$100.00`. + + --- + + - `annualMonthlyAmount` + - `number` + + The effective monthly price when billed annually, in the smallest unit of the currency. For example, `833` for `$8.33`. + + --- + + - `annualMonthlyAmountFormatted` + - `string` + + The formatted effective monthly price when billed annually, including currency symbol. For example, `$8.33`. + + --- + + - `currencySymbol` + - `string` + + The symbol for the plan's currency. For example, `$` or `€`. + + --- + + - `currency` + - `string` + + The ISO currency code for the plan. For example, `USD` or `EUR`. + + --- + + - `description` + - `string` + + A short description of what the plan offers. + + --- + + - `isDefault` + - `boolean` + + A boolean that indicates if this plan is the default plan. + + --- + + - `isRecurring` + - `boolean` + + A boolean that indicates if the plan is billed on a recurring basis. + + --- + + - `hasBaseFee` + - `boolean` + + A boolean that indicates if the plan has a base fee. + + --- + + - `forPayerType` + - `'org' | 'user'` + + The type of payer this plan is for. + + --- + + - `publiclyVisible` + - `boolean` + + A boolean that indicates if the plan is visible to the public. + + --- + + - `slug` + - `string` + + A unique, URL-friendly identifier for the plan. + + --- + + - `avatarUrl` + - `string` + + The URL of the plan's avatar image. + + --- + + - `features` + - [CommerceFeatureResource](/docs/references/javascript/types/commerce-feature-resource)\[] + + The list of features included in this plan. + diff --git a/docs/references/javascript/types/commerce-subscription-item-resource.mdx b/docs/references/javascript/types/commerce-subscription-item-resource.mdx new file mode 100644 index 0000000000..3156ffc181 --- /dev/null +++ b/docs/references/javascript/types/commerce-subscription-item-resource.mdx @@ -0,0 +1,122 @@ +--- +title: '`CommerceSubscriptionItemResource`' +description: 'The CommerceSubscriptionItemResource type represents an item in a subscription.' +--- + +The `CommerceSubscriptionItemResource` type represents an item in a subscription. + +## Properties + + + - `id` + - `string` + + The unique identifier for the subscription item. + + --- + + - `paymentSourceId` + - `string` + + The identifier of the payment source used for the subscription item. + + --- + + - `plan` + - [`CommercePlanResource`](/docs/references/javascript/types/commerce-plan-resource) + + The plan associated with the subscription item. + + --- + + - `planPeriod` + - `'month' | 'annual'` + + The billing period of the subscription item. + + --- + + - `status` + - `'active' | 'ended' | 'upcoming' | 'past_due'` + + The current status of the subscription item. + + --- + + - `createdAt` + - `Date` + + The date when the subscription item was created. + + --- + + - `pastDueAt` + - `Date | null` + + The date when the subscription item became past due, or `null` if it's not past due. + + --- + + - `periodStartDate` + - `Date` + + The start date of the current billing period. + + --- + + - `periodEndDate` + - `Date | null` + + The end date of the current billing period, or `null` if not set. + + --- + + - `canceledAtDate` + - `Date | null` + + The date when the subscription item was canceled, or `null` if it's not canceled. + + --- + + - `periodStart` + - `number` + + **Deprecated. Use `periodStartDate` instead.** The Unix timestamp for the start of the current billing period. + + --- + + - `periodEnd` + - `number` + + **Deprecated. Use `periodEndDate` instead.** The Unix timestamp for the end of the current billing period. + + --- + + - `canceledAt` + - `number | null` + + **Deprecated. Use `canceledAtDate` instead.** The Unix timestamp for when the item was canceled, or `null`. + + --- + + - `amount` + - [CommerceMoney](/docs/references/javascript/types/commerce-money) | undefined + + The amount charged for the subscription item. + + --- + + - `credit` + - `{ amount: CommerceMoney } | undefined` + + Credit info for the subscription item, if any. + + --- + + - `cancel` + - `(params: CancelSubscriptionParams) => Promise` + + A function to cancel the subscription item. Accepts the following parameters: + + - `orgId?` (`string`): The ID of the organization to cancel the subscription item for. + diff --git a/docs/references/javascript/types/commerce-subscription-resource.mdx b/docs/references/javascript/types/commerce-subscription-resource.mdx new file mode 100644 index 0000000000..c79f1e0de4 --- /dev/null +++ b/docs/references/javascript/types/commerce-subscription-resource.mdx @@ -0,0 +1,64 @@ +--- +title: '`CommerceSubscriptionResource`' +description: 'The CommerceSubscriptionResource type represents a subscription to a plan.' +--- + +The `CommerceSubscriptionResource` type represents a subscription to a plan. + +## Properties + + + - `id` + - `string` + + The unique identifier for the subscription. + + --- + + - `activeAt` + - `Date` + + The date when the subscription became active. + + --- + + - `createdAt` + - `Date` + + The date when the subscription was created. + + --- + + - `nextPayment` + - `{ amount: CommerceMoney; date: Date } | null` + + Information about the next payment, including the amount and the date it's due. Returns `null` if there is no upcoming payment. + + --- + + - `pastDueAt` + - `Date | null` + + The date when the subscription became past due, or `null` if it's not past due. + + --- + + - `status` + - `'active' | 'past_due'` + + The current status of the subscription. + + --- + + - `subscriptionItems` + - [CommerceSubscriptionItemResource](/docs/references/javascript/types/commerce-subscription-item-resource)\[] + + The list of items (plans/features) included in this subscription. + + --- + + - `updatedAt` + - `Date | null` + + The date when the subscription was last updated, or `null` if it hasn't been updated. + diff --git a/redirects/static/docs.json b/redirects/static/docs.json index 5b66b36f61..a872b1ca16 100644 --- a/redirects/static/docs.json +++ b/redirects/static/docs.json @@ -2468,5 +2468,25 @@ "source": "/docs/references/community-sdk/overview", "destination": "/docs/references/overview#build-with-community-maintained-sdks", "permanent": true + }, + { + "source": "/docs/components/checkout-button", + "destination": "/docs/components/billing/checkout-button", + "permanent": true + }, + { + "source": "/docs/components/plan-details-button", + "destination": "/docs/components/billing/plan-details-button", + "permanent": true + }, + { + "source": "/docs/components/pricing-table", + "destination": "/docs/components/billing/pricing-table", + "permanent": true + }, + { + "source": "/docs/components/subscription-details-button", + "destination": "/docs/components/billing/subscription-details-button", + "permanent": true } ] From 29dbaba2dd729c1ac71691556f74470b9e1c3f9b Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Tue, 29 Jul 2025 14:31:27 -0400 Subject: [PATCH 25/36] fix broken hash --- docs/hooks/use-plans.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index 0e5860171c..9ebd54fa67 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -52,7 +52,7 @@ The `usePlans()` hook provides access to the subscription plans available in you - `data` - - [`CommercePlanResource[]`](#commerce-plan-resource) | null + - [`CommercePlanResource[]`](/docs/references/javascript/types/commerce-plan-resource) | null An array of [plans](/docs/references/javascript/types/commerce-plan-resource), or `null` if the data hasn't been loaded yet. From c800db0f6427e5593acb3d62b8003555c1357bde Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Tue, 29 Jul 2025 18:28:08 -0400 Subject: [PATCH 26/36] small updates --- docs/_partials/billing/use-checkout-options.mdx | 2 +- docs/hooks/use-checkout.mdx | 10 ++++++++-- .../javascript/types/commerce-checkout-resource.mdx | 12 +++++++++--- docs/references/javascript/types/commerce-money.mdx | 10 ++++------ .../javascript/types/commerce-plan-resource.mdx | 12 ++++++------ 5 files changed, 28 insertions(+), 18 deletions(-) diff --git a/docs/_partials/billing/use-checkout-options.mdx b/docs/_partials/billing/use-checkout-options.mdx index 9989b54fac..234f42cf0a 100644 --- a/docs/_partials/billing/use-checkout-options.mdx +++ b/docs/_partials/billing/use-checkout-options.mdx @@ -9,7 +9,7 @@ - `planId` - `string` - The ID of the subscription plan to check out (e.g., `cplan_123`). + The ID of the subscription plan to check out (e.g. `cplan_123`). --- diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 014df9e87e..2e443c8cce 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -20,7 +20,9 @@ There are two ways to use `useCheckout()`: - `options?` - [`UseCheckoutOptions`](#use-checkout-options) - **Required** if the hook is used without a `` wrapping the component tree. An object containing the configuration for the checkout flow. + An object containing the configuration for the checkout flow. + + **Required** if the hook is used without a `` wrapping the component tree. ### `UseCheckoutOptions` @@ -84,7 +86,11 @@ There are two ways to use `useCheckout()`: - `status` - `'awaiting_initialization' | 'awaiting_confirmation' | 'completed'` - The current status of the checkout session. + The current status of the checkout session. The following statuses are possible: + + - `awaiting_initialization`: The checkout hasn't started but the hook is mounted. Call `start()` to continue. + - `awaiting_confirmation`: The checkout has been initialized and is awaiting confirmation. Call `confirm()` to continue. + - `completed`: The checkout has been successfully confirmed. Call `finalize()` to complete the checkout. --- diff --git a/docs/references/javascript/types/commerce-checkout-resource.mdx b/docs/references/javascript/types/commerce-checkout-resource.mdx index 98b91e043d..7c93358aef 100644 --- a/docs/references/javascript/types/commerce-checkout-resource.mdx +++ b/docs/references/javascript/types/commerce-checkout-resource.mdx @@ -110,19 +110,25 @@ The `confirm()` function is used to confirm and finalize the checkout process, u - `paymentToken?` - `string | undefined` - A token representing payment details, usually from a payment form. Requires `gateway` to be provided. + A token representing payment details, usually from a payment form. + + **Requires** `gateway` to be provided. --- - `useTestCard?` - `boolean | undefined` - If true, uses a test card for the checkout. Requires `gateway` to be provided. + If true, uses a test card for the checkout. + + **Requires** `gateway` to be provided. --- - `gateway?` - `PaymentGateway | undefined` - **Required** if `paymentToken` or `useTestCard` is provided. The payment gateway to use (like `'stripe'`, `'paypal'`, etc). + The payment gateway to use. For example, `'stripe'` or `'paypal'`. + + **Required** if `paymentToken` or `useTestCard` is provided. diff --git a/docs/references/javascript/types/commerce-money.mdx b/docs/references/javascript/types/commerce-money.mdx index 4d1b0e5974..757e86541f 100644 --- a/docs/references/javascript/types/commerce-money.mdx +++ b/docs/references/javascript/types/commerce-money.mdx @@ -7,32 +7,30 @@ The `CommerceMoney` type represents a monetary value with currency information. ## Properties -{/* TODO: AI filled these descriptions. We need to test what format each of these values are in and update the descriptions accordingly */} - - `amount` - `number` - The raw amount as a number, usually in the smallest unit of the currency (like cents for USD). + The raw amount as a number, usually in the smallest unit of the currency (like cents for USD). For example, `1000` for $10.00. --- - `amountFormatted` - `string` - The amount as a formatted string, including currency symbol and separators (like `$10.00`). + The amount as a formatted string. For example, `10` for $10.00. --- - `currency` - `string` - The ISO currency code for this amount (like `USD`, `EUR`, etc). + The ISO currency code for this amount. For example, `USD` or `EUR`. --- - `currencySymbol` - `string` - The symbol for the currency (like `$`, `€`, `£`). + The symbol for the currency. For example, `$`, `€`, or `£`. diff --git a/docs/references/javascript/types/commerce-plan-resource.mdx b/docs/references/javascript/types/commerce-plan-resource.mdx index 7b666ea0dd..04dac7bb76 100644 --- a/docs/references/javascript/types/commerce-plan-resource.mdx +++ b/docs/references/javascript/types/commerce-plan-resource.mdx @@ -25,42 +25,42 @@ The `CommercePlanResource` type represents a subscription plan with its details. - `amount` - `number` - The price of the plan for a single billing period (usually monthly). For example, `1000` for `$10.00`. + The price of the plan for a single billing period (usually monthly). For example, `1000` for $10.00. --- - `amountFormatted` - `string` - The formatted price for a single billing period, including currency symbol. For example, `$10.00`. + The formatted price for a single billing period. For example, `10` for $10.00. --- - `annualAmount` - `number` - The total price for a full year of the plan, in the smallest unit of the currency. For example, `10000` for `$100.00`. + The total price for a full year of the plan, in the smallest unit of the currency. For example, `10000` for $100.00. --- - `annualAmountFormatted` - `string` - The formatted price for a full year of the plan, including currency symbol. For example, `$100.00`. + The formatted price for a full year of the plan. For example, `100` for $100.00. --- - `annualMonthlyAmount` - `number` - The effective monthly price when billed annually, in the smallest unit of the currency. For example, `833` for `$8.33`. + The effective monthly price when billed annually, in the smallest unit of the currency. For example, `833` for $8.33. --- - `annualMonthlyAmountFormatted` - `string` - The formatted effective monthly price when billed annually, including currency symbol. For example, `$8.33`. + The formatted effective monthly price when billed annually. For example, `8.33` for $8.33. --- From 318496364dca382d346dd66748d733a7de2552be Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 30 Jul 2025 13:00:49 +0300 Subject: [PATCH 27/36] address review comments --- docs/custom-flows/add-new-payment-methods.mdx | 5 ++-- .../checkout-existing-payment-method.mdx | 9 +++---- .../checkout-new-payment-method.mdx | 4 +-- docs/hooks/use-checkout.mdx | 27 ++++++++++++------- docs/hooks/use-payment-element.mdx | 10 +++---- 5 files changed, 31 insertions(+), 24 deletions(-) diff --git a/docs/custom-flows/add-new-payment-methods.mdx b/docs/custom-flows/add-new-payment-methods.mdx index 973552925e..1aed2a92b7 100644 --- a/docs/custom-flows/add-new-payment-methods.mdx +++ b/docs/custom-flows/add-new-payment-methods.mdx @@ -17,7 +17,7 @@ This guide will walk you through how to build a flow for adding a new payment me To add a new payment method for a user, you must: 1. Set up the [``](/docs/hooks/use-payment-element) to create a context for the user's payment actions. - 1. Render the [``](/docs/hooks/use-payment-element) to display the secure payment fields from your provider. + 1. Render the [``](/docs/hooks/use-payment-element) to display the secure payment fields from your provider. 1. Use the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to submit the form and create a payment token. 1. Use the [`useUser()`](/docs/hooks/use-user) hook to attach the newly created payment method to the user. @@ -36,7 +36,7 @@ This guide will walk you through how to build a flow for adding a new payment me import { PaymentElementProvider } from '@clerk/nextjs/experimental' import { AddPaymentMethodForm } from './AddPaymentMethodForm' - export function Page() { + export default function Page() { return (

      Billing Settings

      @@ -55,6 +55,7 @@ This guide will walk you through how to build a flow for adding a new payment me This component contains the form and the logic to handle the submission. It uses `usePaymentElement()` to get the `submit` function and `useUser()` to get the `user` object. When the form is submitted, it first creates a payment token and then attaches it to the user. ```tsx {{ filename: 'app/user/billing/AddPaymentMethodForm.tsx' }} + 'use client' import { useUser } from '@clerk/nextjs' import { usePaymentElement, PaymentElement } from '@clerk/nextjs/experimental' import { useState } from 'react' diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index 5a265e074f..e9eb30f82c 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -95,19 +95,18 @@ This guide will walk you through how to build a custom checkout flow using an ex const { isConfirming, confirm, complete, error } = checkout const [isProcessing, setIsProcessing] = useState(false) - const [selectedMethod, setSelectedMethod] = useState<(typeof data)[number] | null>(null) + const [paymentMethodId, setPaymentMethodId] = useState(null) const defaultMethod = useMemo(() => data?.find((method) => method.isDefault), [data]) const submitSelectedMethod = async () => { - if (isProcessing) return + const paymentSourceId = paymentMethodId || defaultMethod?.id; + if (isProcessing || !paymentSourceId) return setIsProcessing(true) try { // Confirm checkout with payment method - await confirm({ - paymentSourceId: (selectedMethod || defaultMethod)?.id, - }) + await confirm({ paymentSourceId }) // Complete checkout and redirect await finalize({ redirectUrl: '/dashboard' }) } catch (error) { diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index 39fa543f6f..f209e6617b 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -43,7 +43,7 @@ This guide will walk you through how to build a custom checkout flow with a new CheckoutProvider, useCheckout, PaymentElementProvider, - PaymentElementForm, + PaymentElement, usePaymentElement, } from '@clerk/nextjs/experimental' import { useRouter } from 'next/navigation' @@ -125,7 +125,7 @@ This guide will walk you through how to build a custom checkout flow with a new return ( - } /> + } /> {error &&
      {error.message}
      } diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 2e443c8cce..9d90168369 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -199,6 +199,7 @@ The `useCheckout()` hook can be used with a context provider for managing state ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} import { CheckoutProvider } from '@clerk/clerk-react/experimental' + import { ClerkLoaded } from '@clerk/clerk-react' import { CheckoutFlow } from './CheckoutFlow' export function SubscriptionPage() { @@ -209,7 +210,9 @@ The `useCheckout()` hook can be used with a context provider for managing state

      Upgrade Your Plan

      You are about to subscribe to our monthly plan.

      - + + +
      ) @@ -251,23 +254,23 @@ The `useCheckout()` hook can be used with a context provider for managing state function PaymentSection() { const { checkout } = useCheckout() - const { isConfirming, confirm, complete, error } = checkout + const { isConfirming, confirm, finalize, error } = checkout const [isProcessing, setIsProcessing] = useState(false) - const [selectedMethod, setSelectedMethod] = useState<(typeof data)[number] | null>(null) + const [paymentMethodId, setPaymentMethodId] = useState(null) const submitSelectedMethod = async () => { - if (isProcessing || !selectedMethod) return + if (isProcessing || !paymentMethodId) return setIsProcessing(true) try { // Confirm checkout with payment method await confirm({ - paymentSourceId: selectedMethod.id, + paymentSourceId: paymentMethodId, }) - // Calling `.complete` enables you to sync the client side state with the server side state of your users. + // Calling `.finalize` enables you to sync the client side state with the server side state of your users. // It revalidates all authorization checks computed within server components. - await complete({ redirectUrl: '/dashboard' }) + await finalize({ redirectUrl: '/dashboard' }) } catch (error) { console.error('Payment failed:', error) } finally { @@ -277,7 +280,7 @@ The `useCheckout()` hook can be used with a context provider for managing state return ( <> - + {error &&
      {error.message}
      } @@ -316,7 +319,13 @@ The `useCheckout()` hook can be used with a context provider for managing state ```tsx {{ filename: 'src/components/UpgradeButton.tsx' }} import { useCheckout } from '@clerk/clerk-react/experimental' - export function UpgradeButton({ planId, planPeriod }) { + export function UpgradeButton({ + planId, + planPeriod, + }: { + planId: string + planPeriod: 'month' | 'annual' + }) { // Pass options directly to the hook when not using a provider. const { checkout } = useCheckout({ planId, diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx index fdbe0e42e5..9dbf8d88dc 100644 --- a/docs/hooks/use-payment-element.mdx +++ b/docs/hooks/use-payment-element.mdx @@ -121,11 +121,7 @@ The following example shows the basic structure for adding a new payment method.

      Add a new payment method

      Your payment details will be saved securely for future purchases.

      - {/* The form component renders the payment UI */} - }> - {/* The child component handles form interaction */} - - + ) } @@ -149,7 +145,6 @@ The following example shows the basic structure for adding a new payment method. } setIsSubmitting(true) - setError(null) const { data, error } = await submit() @@ -165,6 +160,9 @@ The following example shows the basic structure for adding a new payment method. return ( + {/* The form component renders the payment UI */} + } /> + {/* The actual payment fields are rendered by */} + {error &&

      {error}

      } + + ) + } + ``` + diff --git a/docs/_partials/billing/use-checkout-options.mdx b/docs/_partials/billing/use-checkout-options.mdx index 234f42cf0a..2aceb88f83 100644 --- a/docs/_partials/billing/use-checkout-options.mdx +++ b/docs/_partials/billing/use-checkout-options.mdx @@ -9,7 +9,7 @@ - `planId` - `string` - The ID of the subscription plan to check out (e.g. `cplan_123`). + The ID of the subscription plan to check out (e.g. `cplan_xxx`). --- diff --git a/docs/custom-flows/add-new-payment-method.mdx b/docs/custom-flows/add-new-payment-method.mdx new file mode 100644 index 0000000000..18997ad537 --- /dev/null +++ b/docs/custom-flows/add-new-payment-method.mdx @@ -0,0 +1,31 @@ +--- +title: Build a custom flow for adding a new payment method +description: Learn how to use the Clerk API to build a custom flow for adding a new payment method to a user's account. +--- + + + +This guide will walk you through how to build a custom user interface that allows users to **add a new payment method to their account**. This is a common feature in a user's billing or account settings page, allowing them to pre-emptively add a payment method for future use. + +For the custom flow that allows users to add a new payment method **during checkout**, see the [dedicated guide](/docs/custom-flows/checkout-new-payment-method). + + + ### Enable billing features + + To use billing features, you first need to ensure they are enabled for your application. Follow the [Billing documentation](/docs/billing/overview) to enable them and set up your plans. + + ### Add payment method flow + + To add a new payment method for a user, you must: + + 1. Set up the [``](/docs/hooks/use-payment-element) to create a context for the user's payment actions. + 1. Render the [``](/docs/hooks/use-payment-element) to display the secure payment fields from your provider. + 1. Use the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to submit the form and create a payment token. + 1. Use the [`useUser()`](/docs/hooks/use-user) hook to attach the newly created payment method to the user. + + + + + + + diff --git a/docs/custom-flows/add-new-payment-methods.mdx b/docs/custom-flows/add-new-payment-methods.mdx deleted file mode 100644 index 1aed2a92b7..0000000000 --- a/docs/custom-flows/add-new-payment-methods.mdx +++ /dev/null @@ -1,116 +0,0 @@ ---- -title: Add a new payment method -description: Learn how to use Clerk's components to allow users to add a new payment method to their account. ---- - - - -This guide will walk you through how to build a flow for adding a new payment method. This is a common feature in a user's billing or account settings page, allowing them to pre-emptively add a payment method for future use. - - - ### Enable billing features - - To use billing features, you first need to ensure they are enabled for your application. Follow the [Billing documentation](/docs/billing/overview) to enable them and set up your plans. - - ### Add payment method flow - - To add a new payment method for a user, you must: - - 1. Set up the [``](/docs/hooks/use-payment-element) to create a context for the user's payment actions. - 1. Render the [``](/docs/hooks/use-payment-element) to display the secure payment fields from your provider. - 1. Use the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to submit the form and create a payment token. - 1. Use the [`useUser()`](/docs/hooks/use-user) hook to attach the newly created payment method to the user. - - - - The following example demonstrates how to create a billing page where a user can add a new payment method. It is split into two components: - - - **``**: This component sets up the ``. - - **``**: This component renders the payment form and handles the submission logic using the `usePaymentElement` and `useUser` hooks. - - ", ""]}> - - This component is responsible for setting up the provider context. It specifies that the payment actions within its children are `for` the `user`. - - ```tsx {{ filename: 'app/user/billing/page.tsx' }} - import { PaymentElementProvider } from '@clerk/nextjs/experimental' - import { AddPaymentMethodForm } from './AddPaymentMethodForm' - - export default function Page() { - return ( -
      -

      Billing Settings

      -

      Manage your saved payment methods.

      - - - - -
      - ) - } - ``` -
      - - - This component contains the form and the logic to handle the submission. It uses `usePaymentElement()` to get the `submit` function and `useUser()` to get the `user` object. When the form is submitted, it first creates a payment token and then attaches it to the user. - - ```tsx {{ filename: 'app/user/billing/AddPaymentMethodForm.tsx' }} - 'use client' - import { useUser } from '@clerk/nextjs' - import { usePaymentElement, PaymentElement } from '@clerk/nextjs/experimental' - import { useState } from 'react' - - export function AddPaymentMethodForm() { - const { user } = useUser() - const { submit, isFormReady } = usePaymentElement() - const [isSubmitting, setIsSubmitting] = useState(false) - const [error, setError] = useState(null) - - const handleAddPaymentMethod = async (e: React.FormEvent) => { - e.preventDefault() - if (!isFormReady || !user) { - return - } - - setError(null) - setIsSubmitting(true) - - try { - // 1. Submit the form to the payment provider to get a payment token - const { data, error } = await submit() - - // Usually a validation error from stripe that you can ignore. - if (error) { - setIsSubmitting(false) - return - } - - // 2. Use the token to add the payment source to the user - await user.addPaymentSource(result.data) - - // 3. Handle success (e.g., show a confirmation, clear the form) - alert('Payment method added successfully!') - } catch (err: any) { - setError(err.message || 'An unexpected error occurred.') - } finally { - setIsSubmitting(false) - } - } - - return ( -
      -

      Add a new payment method

      - - - {error &&

      {error}

      } - - ) - } - ``` -
      -
      -
      -
      -
      diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index e9eb30f82c..94cdbdd001 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -1,11 +1,11 @@ --- title: Build a custom checkout flow with an existing payment method -description: Learn how to use the Clerk API to build a custom checkout flow using an existing payment method. +description: Learn how to use the Clerk API to build a custom checkout flow that allows users to checkout with an existing payment method. --- -This guide will walk you through how to build a custom checkout flow using an existing payment method. +This guide will walk you through how to build a custom user interface for a checkout flow that allows users to checkout **with an existing payment method**. For the custom flow that allows users to **add a new payment method** during checkout, see the [dedicated guide](/docs/custom-flows/checkout-new-payment-method). ## Enable billing features @@ -29,13 +29,13 @@ This guide will walk you through how to build a custom checkout flow using an ex 1. Uses the [`useCheckout()`](/docs/hooks/use-checkout) hook to initiate and manage the checkout session. 1. Uses the [`usePaymentMethods()`](/docs/hooks/use-payment-methods) hook to fetch the user's existing payment methods. 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways: - 1. Copy from the Clerk Dashboard. - 1. Use the [Clerk Backend API](TBD). - 1. Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. + - [Copy from the Clerk Dashboard](https://dashboard.clerk.com/last-active?path=billing/plans?tab=user). + - Use the [Clerk Backend API](TODO). + - Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. This example is written for Next.js App Router but can be adapted for any React-based framework. - ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 9], 14, 15, 17, 18, 23, [26, 28], [55, 58], [71, 77], [102, 104]] }} + ```tsx {{ filename: 'app/checkout/page.tsx' }} 'use client' import * as React from 'react' import { SignedIn, ClerkLoaded } from '@clerk/nextjs' @@ -44,7 +44,7 @@ This guide will walk you through how to build a custom checkout flow using an ex export default function CheckoutPage() { return ( - + @@ -92,7 +92,7 @@ This guide will walk you through how to build a custom checkout flow using an ex pageSize: 20, }) - const { isConfirming, confirm, complete, error } = checkout + const { isConfirming, confirm, finalize, error } = checkout const [isProcessing, setIsProcessing] = useState(false) const [paymentMethodId, setPaymentMethodId] = useState(null) @@ -100,7 +100,7 @@ This guide will walk you through how to build a custom checkout flow using an ex const defaultMethod = useMemo(() => data?.find((method) => method.isDefault), [data]) const submitSelectedMethod = async () => { - const paymentSourceId = paymentMethodId || defaultMethod?.id; + const paymentSourceId = paymentMethodId || defaultMethod?.id if (isProcessing || !paymentSourceId) return setIsProcessing(true) @@ -108,7 +108,7 @@ This guide will walk you through how to build a custom checkout flow using an ex // Confirm checkout with payment method await confirm({ paymentSourceId }) // Complete checkout and redirect - await finalize({ redirectUrl: '/dashboard' }) + finalize({ redirectUrl: '/dashboard' }) } catch (error) { console.error('Payment failed:', error) } finally { @@ -128,7 +128,7 @@ This guide will walk you through how to build a custom checkout flow using an ex const methodId = e.target.value const method = data?.find((method) => method.id === methodId) if (method) { - setSelectedMethod(method) + setPaymentMethodId(method.id) } }} > diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index f209e6617b..50cb405d56 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -1,11 +1,15 @@ --- -title: Build a custom checkout flow for a new payment method -description: Learn how to use the Clerk API to build a custom checkout flow for a new payment method. +title: Build a custom checkout flow with a new payment method +description: Learn how to use the Clerk API to build a custom checkout flow that allows users to add a new payment method during checkout. --- -This guide will walk you through how to build a custom checkout flow with a new payment method. +This guide will walk you through how to build a custom user interface for a checkout flow that allows users to **add a new payment method during checkout**. + +For the custom flow that allows users to checkout **with an existing payment** method, see the [dedicated guide](/docs/custom-flows/checkout-existing-payment-method). + +For the custom flow that allows users to add a new payment method to their account, **outside of a checkout flow**, see the [dedicated guide](/docs/custom-flows/add-payment-method-outside-checkout). ## Enable billing features @@ -29,13 +33,13 @@ This guide will walk you through how to build a custom checkout flow with a new 1. Uses the [`useCheckout()`](/docs/hooks/use-checkout) hook to get to initiate and manage the checkout session. 1. Uses the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to control the payment element, which is rendered by ``. 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways. - 1. Copy from the Clerk Dashboard. - 1. Use the [Clerk Backend API](TBD). - 1. Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. + - [Copy from the Clerk Dashboard](https://dashboard.clerk.com/last-active?path=billing/plans?tab=user). + - Use the [Clerk Backend API](TODO). + - Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. This example is written for Next.js App Router but can be adapted for any React-based framework. - ```tsx {{ filename: 'app/components/CheckoutPage.tsx', mark: [[3, 11], 16, 18, [23, 24], 26, 34, 36, 42, 56, [66, 75], 85] }} + ```tsx {{ filename: 'app/checkout/page.tsx' }} 'use client' import * as React from 'react' import { SignedIn, ClerkLoaded } from '@clerk/nextjs' @@ -46,11 +50,10 @@ This guide will walk you through how to build a custom checkout flow with a new PaymentElement, usePaymentElement, } from '@clerk/nextjs/experimental' - import { useRouter } from 'next/navigation' export default function CheckoutPage() { return ( - + @@ -80,7 +83,8 @@ This guide will walk you through how to build a custom checkout flow with a new } function CheckoutInitialization() { - const { start, status, fetchStatus } = useCheckout() + const { checkout } = useCheckout() + const { start, status, fetchStatus } = checkout if (status === 'awaiting_initialization') { return @@ -95,12 +99,12 @@ This guide will walk you through how to build a custom checkout flow with a new function PaymentSection() { const { checkout } = useCheckout() - const { isConfirming, confirm, complete, error } = checkout + const { isConfirming, confirm, finalize, error } = checkout const { isFormReady, submit } = usePaymentElement() const [isProcessing, setIsProcessing] = React.useState(false) - const handleSubmit = async (e) => { + const handleSubmit = async (e: React.FormEvent) => { e.preventDefault() if (!isFormReady || isProcessing) return setIsProcessing(true) diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 9d90168369..3966a40f46 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -198,18 +198,18 @@ The `useCheckout()` hook can be used with a context provider for managing state ", ""]}> ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }} - import { CheckoutProvider } from '@clerk/clerk-react/experimental' - import { ClerkLoaded } from '@clerk/clerk-react' + import { CheckoutProvider } from '@clerk/nextjs/experimental' + import { ClerkLoaded } from '@clerk/nextjs' import { CheckoutFlow } from './CheckoutFlow' export function SubscriptionPage() { - // The provider sets the context for the checkout flow. + // `` sets the context for the checkout flow. // Any child component can now call `useCheckout()` to access this context. return ( - +

      Upgrade Your Plan

      -

      You are about to subscribe to our monthly plan.

      +

      You are about to subscribe to our monthly plan

      @@ -222,7 +222,9 @@ The `useCheckout()` hook can be used with a context provider for managing state ```tsx {{ filename: 'src/components/CheckoutFlow.tsx', collapsible: true }} - import { useCheckout } from '@clerk/clerk-react/experimental' + 'use client' + + import { useCheckout } from '@clerk/nextjs/experimental' export function CheckoutFlow() { const { checkout } = useCheckout() @@ -242,7 +244,7 @@ The `useCheckout()` hook can be used with a context provider for managing state function CheckoutInitialization() { const { checkout } = useCheckout() - const { start, status, fetchStatus } = checkout + const { start, fetchStatus } = checkout return ( - - ) - } - ``` - - + ## Related guides - [Use PaymentElement in a checkout flow](/docs/custom-flows/checkout-new-payment-method) - - Prompt users to add a new payment method during checkout + - Add a new payment method during checkout --- - - [Use PaymentElement outside of a checkout flow](/docs/custom-flows/add-new-payment-methods) + - [Use PaymentElement outside of a checkout flow](/docs/custom-flows/add-payment-method-outside-checkout) - Add a new payment method outside of a checkout flow diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index a1d0ee030f..7d8b9f7c8a 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -132,6 +132,11 @@ function PaymentMethodsList() { return
      Loading payment methods...
      } + if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/custom-flows/add-payment-method-outside-checkout + return
      No payment methods found. Please add a payment method to your account.
      + } + return (
        {data?.map((method) => ( @@ -163,6 +168,11 @@ function InfinitePaymentMethods() { return
        Loading...
        } + if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/custom-flows/add-payment-method-outside-checkout + return
        No payment methods found. Please add a payment method to your account.
        + } + return (
          @@ -183,7 +193,7 @@ function InfinitePaymentMethods() { ### With checkout flow -The following example demonstrates how to use `usePaymentMethods()` in a checkout flow to select an existing payment method. +The following example demonstrates how to use `usePaymentMethods()` in a checkout flow to select an existing payment method. For more information on how to build a checkout flow with an existing payment method, see [Build a custom checkout flow](/docs/custom-flows/checkout-new-payment-method). ```tsx import { usePaymentMethods, useCheckout } from '@clerk/nextjs/experimental' @@ -208,6 +218,11 @@ function CheckoutPaymentSelection() { return
          Loading payment methods...
          } + if (!data || data.length === 0) { + // Code for how to add a new payment method: https://clerk.com/docs/custom-flows/checkout-new-payment-method + return
          No payment methods found. Please add a payment method to your account.
          + } + return (

          Select a payment method

          @@ -220,3 +235,15 @@ function CheckoutPaymentSelection() { ) } ``` + +## Related guides + + + - [Add a new payment method during checkout](/docs/custom-flows/checkout-new-payment-method) + - Build a custom checkout flow that allows users to add a new payment method during checkout + + --- + + - [Add a new payment method outside of a checkout flow](/docs/custom-flows/add-payment-method-outside-checkout) + - Build a custom user interface that allows users to add a new payment method to their account + diff --git a/docs/hooks/use-plans.mdx b/docs/hooks/use-plans.mdx index 9ebd54fa67..c6d17b8bb1 100644 --- a/docs/hooks/use-plans.mdx +++ b/docs/hooks/use-plans.mdx @@ -120,10 +120,11 @@ The `usePlans()` hook provides access to the subscription plans available in you The following example shows how to fetch and display available plans. ```tsx +'use client' import { usePlans } from '@clerk/nextjs/experimental' function PlansList() { - const { data, isLoading } = usePlans({ + const { data, isLoading, hasNextPage, fetchNext, hasPreviousPage, fetchPrevious } = usePlans({ for: 'user', pageSize: 10, }) @@ -154,6 +155,9 @@ function PlansList() {
        ))} + + {hasNextPage && } + {hasPreviousPage && }
      ) } @@ -164,13 +168,14 @@ function PlansList() { The following example demonstrates how to implement infinite scrolling with plans. ```tsx +'use client' import { usePlans } from '@clerk/nextjs/experimental' function InfinitePlansList() { const { data, isLoading, hasNextPage, fetchNext } = usePlans({ for: 'user', infinite: true, - pageSize: 20, + pageSize: 2, }) if (isLoading) { diff --git a/docs/hooks/use-subscription.mdx b/docs/hooks/use-subscription.mdx index 56cfdbd493..31aaa9d86c 100644 --- a/docs/hooks/use-subscription.mdx +++ b/docs/hooks/use-subscription.mdx @@ -74,6 +74,7 @@ The `useSubscription()` hook provides access to subscription information for use The following example shows how to fetch and display subscription information. ```tsx +'use client' import { useSubscription } from '@clerk/nextjs/experimental' function SubscriptionInfo() { @@ -105,6 +106,7 @@ function SubscriptionInfo() { The following example shows how to fetch an organization's subscription. ```tsx +'use client' import { useSubscription } from '@clerk/nextjs/experimental' function OrganizationSubscription() { @@ -137,6 +139,7 @@ function OrganizationSubscription() { The following example shows how to handle subscription data with proper error states. ```tsx {{ filename: 'app/pricing/subscription-details/page.tsx' }} +'use client' import { useSubscription } from '@clerk/nextjs/experimental' function SubscriptionDetails() { diff --git a/docs/manifest.json b/docs/manifest.json index 6d8efd54aa..9c480a047c 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -3781,7 +3781,7 @@ }, { "title": "Add a new payment method", - "href": "/docs/custom-flows/add-new-payment-methods" + "href": "/docs/custom-flows/add-new-payment-method" } ] ] From 36edb29a69b2db6e36ca1732889c0c755b9cad6e Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Wed, 30 Jul 2025 11:26:05 -0400 Subject: [PATCH 29/36] add custom flow callout to custom flow guides --- docs/custom-flows/add-new-payment-method.mdx | 2 ++ docs/custom-flows/checkout-existing-payment-method.mdx | 2 ++ docs/custom-flows/checkout-new-payment-method.mdx | 2 ++ 3 files changed, 6 insertions(+) diff --git a/docs/custom-flows/add-new-payment-method.mdx b/docs/custom-flows/add-new-payment-method.mdx index 18997ad537..cb4cd4747d 100644 --- a/docs/custom-flows/add-new-payment-method.mdx +++ b/docs/custom-flows/add-new-payment-method.mdx @@ -3,6 +3,8 @@ title: Build a custom flow for adding a new payment method description: Learn how to use the Clerk API to build a custom flow for adding a new payment method to a user's account. --- + + This guide will walk you through how to build a custom user interface that allows users to **add a new payment method to their account**. This is a common feature in a user's billing or account settings page, allowing them to pre-emptively add a payment method for future use. diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index 94cdbdd001..27df610475 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -3,6 +3,8 @@ title: Build a custom checkout flow with an existing payment method description: Learn how to use the Clerk API to build a custom checkout flow that allows users to checkout with an existing payment method. --- + + This guide will walk you through how to build a custom user interface for a checkout flow that allows users to checkout **with an existing payment method**. For the custom flow that allows users to **add a new payment method** during checkout, see the [dedicated guide](/docs/custom-flows/checkout-new-payment-method). diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index 50cb405d56..f3c333f677 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -3,6 +3,8 @@ title: Build a custom checkout flow with a new payment method description: Learn how to use the Clerk API to build a custom checkout flow that allows users to add a new payment method during checkout. --- + + This guide will walk you through how to build a custom user interface for a checkout flow that allows users to **add a new payment method during checkout**. From 4a6e6651d192c26e2311349416b7e0d60dbb044c Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Wed, 30 Jul 2025 11:27:39 -0400 Subject: [PATCH 30/36] fix links --- docs/custom-flows/checkout-new-payment-method.mdx | 2 +- docs/hooks/use-payment-element.mdx | 2 +- docs/hooks/use-payment-methods.mdx | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index f3c333f677..957ddf7096 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -11,7 +11,7 @@ This guide will walk you through how to build a custom user interface for a chec For the custom flow that allows users to checkout **with an existing payment** method, see the [dedicated guide](/docs/custom-flows/checkout-existing-payment-method). -For the custom flow that allows users to add a new payment method to their account, **outside of a checkout flow**, see the [dedicated guide](/docs/custom-flows/add-payment-method-outside-checkout). +For the custom flow that allows users to add a new payment method to their account, **outside of a checkout flow**, see the [dedicated guide](/docs/custom-flows/add-new-payment-method). ## Enable billing features diff --git a/docs/hooks/use-payment-element.mdx b/docs/hooks/use-payment-element.mdx index 3a3f12d1a0..e968c8373a 100644 --- a/docs/hooks/use-payment-element.mdx +++ b/docs/hooks/use-payment-element.mdx @@ -115,6 +115,6 @@ This component renders the actual payment form from the provider (e.g., the Stri --- - - [Use PaymentElement outside of a checkout flow](/docs/custom-flows/add-payment-method-outside-checkout) + - [Use PaymentElement outside of a checkout flow](/docs/custom-flows/add-new-payment-method) - Add a new payment method outside of a checkout flow diff --git a/docs/hooks/use-payment-methods.mdx b/docs/hooks/use-payment-methods.mdx index 7d8b9f7c8a..9c29f13ecd 100644 --- a/docs/hooks/use-payment-methods.mdx +++ b/docs/hooks/use-payment-methods.mdx @@ -133,7 +133,7 @@ function PaymentMethodsList() { } if (!data || data.length === 0) { - // Code for how to add a new payment method: https://clerk.com/docs/custom-flows/add-payment-method-outside-checkout + // Code for how to add a new payment method: https://clerk.com/docs/custom-flows/add-new-payment-method return
      No payment methods found. Please add a payment method to your account.
      } @@ -169,7 +169,7 @@ function InfinitePaymentMethods() { } if (!data || data.length === 0) { - // Code for how to add a new payment method: https://clerk.com/docs/custom-flows/add-payment-method-outside-checkout + // Code for how to add a new payment method: https://clerk.com/docs/custom-flows/add-new-payment-method return
      No payment methods found. Please add a payment method to your account.
      } @@ -244,6 +244,6 @@ function CheckoutPaymentSelection() { --- - - [Add a new payment method outside of a checkout flow](/docs/custom-flows/add-payment-method-outside-checkout) + - [Add a new payment method outside of a checkout flow](/docs/custom-flows/add-new-payment-method) - Build a custom user interface that allows users to add a new payment method to their account From 2072c32a86090f32f3a2156816476118bf1180e7 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 30 Jul 2025 18:29:12 +0300 Subject: [PATCH 31/36] address infinite rendering --- docs/custom-flows/checkout-new-payment-method.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index 957ddf7096..45bb3b1ef9 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -88,8 +88,8 @@ For the custom flow that allows users to add a new payment method to their accou const { checkout } = useCheckout() const { start, status, fetchStatus } = checkout - if (status === 'awaiting_initialization') { - return + if (status !== 'awaiting_initialization') { + return null } return ( From c2c4a622d6ddfd455d32c16a1abb7bddfb203d76 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Wed, 30 Jul 2025 18:32:48 +0300 Subject: [PATCH 32/36] replace fallback --- docs/custom-flows/checkout-new-payment-method.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index 45bb3b1ef9..c2bcb6be27 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -131,7 +131,7 @@ For the custom flow that allows users to add a new payment method to their accou return (
      - } /> + Loading Payment UI

      } /> {error &&
      {error.message}
      } From d4d854c29c2fa9eb473f8f6c732cbbc0a8de4720 Mon Sep 17 00:00:00 2001 From: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> Date: Wed, 30 Jul 2025 11:33:08 -0400 Subject: [PATCH 33/36] update custom flow --- docs/custom-flows/checkout-new-payment-method.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index c2bcb6be27..b0f9c921b2 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -121,7 +121,7 @@ For the custom flow that allows users to add a new payment method to their accou // Confirm checkout with payment method await confirm(data) // Complete checkout and redirect - await finalize({ redirectUrl: '/dashboard' }) + finalize({ redirectUrl: '/dashboard' }) } catch (error) { console.error('Payment failed:', error) } finally { @@ -131,7 +131,7 @@ For the custom flow that allows users to add a new payment method to their accou return ( - Loading Payment UI

      } /> + Loading payment element...
      } /> {error &&
      {error.message}
      } From 92116f8932427c63d94cf6f05bf17251f77b07fc Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 1 Aug 2025 10:27:21 +0300 Subject: [PATCH 34/36] replace statuses --- docs/custom-flows/checkout-existing-payment-method.mdx | 4 ++-- docs/custom-flows/checkout-new-payment-method.mdx | 4 ++-- docs/hooks/use-checkout.mdx | 8 ++++---- .../javascript/types/commerce-checkout-resource.mdx | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index 27df610475..4db7a1aef7 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -60,7 +60,7 @@ This guide will walk you through how to build a custom user interface for a chec const { checkout } = useCheckout() const { status } = checkout - if (status === 'awaiting_initialization') { + if (status === 'needs_initialization') { return } @@ -76,7 +76,7 @@ This guide will walk you through how to build a custom user interface for a chec const { checkout } = useCheckout() const { start, status, fetchStatus } = checkout - if (status !== 'awaiting_initialization') { + if (status !== 'needs_initialization') { return null } diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index b0f9c921b2..efeba22425 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -69,7 +69,7 @@ For the custom flow that allows users to add a new payment method to their accou const { checkout } = useCheckout() const { status } = checkout - if (status === 'awaiting_initialization') { + if (status === 'needs_initialization') { return } @@ -88,7 +88,7 @@ For the custom flow that allows users to add a new payment method to their accou const { checkout } = useCheckout() const { start, status, fetchStatus } = checkout - if (status !== 'awaiting_initialization') { + if (status !== 'needs_initialization') { return null } diff --git a/docs/hooks/use-checkout.mdx b/docs/hooks/use-checkout.mdx index 3966a40f46..51c11d55e5 100644 --- a/docs/hooks/use-checkout.mdx +++ b/docs/hooks/use-checkout.mdx @@ -84,12 +84,12 @@ There are two ways to use `useCheckout()`: --- - `status` - - `'awaiting_initialization' | 'awaiting_confirmation' | 'completed'` + - `'needs_initialization' | 'needs_confirmation' | 'completed'` The current status of the checkout session. The following statuses are possible: - - `awaiting_initialization`: The checkout hasn't started but the hook is mounted. Call `start()` to continue. - - `awaiting_confirmation`: The checkout has been initialized and is awaiting confirmation. Call `confirm()` to continue. + - `needs_initialization`: The checkout hasn't started but the hook is mounted. Call `start()` to continue. + - `needs_confirmation`: The checkout has been initialized and is awaiting confirmation. Call `confirm()` to continue. - `completed`: The checkout has been successfully confirmed. Call `finalize()` to complete the checkout. --- @@ -230,7 +230,7 @@ The `useCheckout()` hook can be used with a context provider for managing state const { checkout } = useCheckout() const { status } = checkout - if (status === 'awaiting_initialization') { + if (status === 'needs_initialization') { return } diff --git a/docs/references/javascript/types/commerce-checkout-resource.mdx b/docs/references/javascript/types/commerce-checkout-resource.mdx index 7c93358aef..dde354dfa7 100644 --- a/docs/references/javascript/types/commerce-checkout-resource.mdx +++ b/docs/references/javascript/types/commerce-checkout-resource.mdx @@ -58,7 +58,7 @@ The `CommerceCheckoutResource` type represents information about a checkout sess --- - `status` - - `'awaiting_initialization' | 'awaiting_confirmation' | 'completed'` + - `'needs_initialization' | 'needs_confirmation' | 'completed'` The current status of the checkout session. From 2da7f14a71116372f8d63d0aeffa3368d6b43695 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 1 Aug 2025 10:32:09 +0300 Subject: [PATCH 35/36] update for prop usage --- docs/_partials/billing/use-checkout-options.mdx | 2 +- docs/components/billing/checkout-button.mdx | 10 +++++----- .../components/billing/subscription-details-button.mdx | 8 ++++---- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs/_partials/billing/use-checkout-options.mdx b/docs/_partials/billing/use-checkout-options.mdx index 2aceb88f83..3c1075f36b 100644 --- a/docs/_partials/billing/use-checkout-options.mdx +++ b/docs/_partials/billing/use-checkout-options.mdx @@ -1,6 +1,6 @@ - `for?` - - `'organization'` + - `'user' | 'organization'` Specifies if the checkout is for an organization. If omitted, the checkout defaults to the current user. diff --git a/docs/components/billing/checkout-button.mdx b/docs/components/billing/checkout-button.mdx index 5f508e52e7..8f90c51f9c 100644 --- a/docs/components/billing/checkout-button.mdx +++ b/docs/components/billing/checkout-button.mdx @@ -27,8 +27,8 @@ The `` component renders a button that opens the checkout draw --- - - `subscriberType?` - - `'user' | 'org'` + - `for?` + - `'user' | 'organization'` Determines whether the subscription is for the current user or organization. Defaults to `'user'`. @@ -78,14 +78,14 @@ The `` component renders a button that opens the checkout draw ``` -`` will throw an error if the `subscriberType` property is set to `'org'` and no [active organization](/docs/organizations/overview#active-organization) is set. +`` will throw an error if the `for` prop is set to `'organization'` and no [active organization](/docs/organizations/overview#active-organization) is set. ```tsx <> // ❌ This will throw an error if no organization is active - + // ✅ Correct usage - {auth.orgId ? : null} + {auth.orgId ? : null} ``` diff --git a/docs/components/billing/subscription-details-button.mdx b/docs/components/billing/subscription-details-button.mdx index c740f5ac30..1587aa831e 100644 --- a/docs/components/billing/subscription-details-button.mdx +++ b/docs/components/billing/subscription-details-button.mdx @@ -16,7 +16,7 @@ All props are optional. - `for?` - - `'user' | 'org'` + - `'user' | 'organization'` Determines whether to show subscription details for the current user or organization. Defaults to `'user'`. @@ -59,14 +59,14 @@ All props are optional. ``` -`` will throw an error if the `for` property is set to `'org'` and no [active organization](/docs/organizations/overview#active-organization) is set. +`` will throw an error if the `for` prop is set to `'organization'` and no [active organization](/docs/organizations/overview#active-organization) is set. ```tsx <> // ❌ This will throw an error if no organization is active - + // ✅ Correct usage - {auth.orgId ? : null} + {auth.orgId ? : null} ``` From 7e4bfcad9083e3d9ca615e170b403bbe04d28642 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Tue, 5 Aug 2025 19:26:58 +0300 Subject: [PATCH 36/36] resolve todos --- docs/custom-flows/checkout-existing-payment-method.mdx | 2 +- docs/custom-flows/checkout-new-payment-method.mdx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/custom-flows/checkout-existing-payment-method.mdx b/docs/custom-flows/checkout-existing-payment-method.mdx index 4db7a1aef7..f8ae9202cb 100644 --- a/docs/custom-flows/checkout-existing-payment-method.mdx +++ b/docs/custom-flows/checkout-existing-payment-method.mdx @@ -32,7 +32,7 @@ This guide will walk you through how to build a custom user interface for a chec 1. Uses the [`usePaymentMethods()`](/docs/hooks/use-payment-methods) hook to fetch the user's existing payment methods. 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways: - [Copy from the Clerk Dashboard](https://dashboard.clerk.com/last-active?path=billing/plans?tab=user). - - Use the [Clerk Backend API](TODO). + - Use the [Clerk Backend API](/docs/reference/backend-api/tag/commerce/get/commerce/plans#tag/commerce/get/commerce/plans). - Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. This example is written for Next.js App Router but can be adapted for any React-based framework. diff --git a/docs/custom-flows/checkout-new-payment-method.mdx b/docs/custom-flows/checkout-new-payment-method.mdx index efeba22425..a80388f298 100644 --- a/docs/custom-flows/checkout-new-payment-method.mdx +++ b/docs/custom-flows/checkout-new-payment-method.mdx @@ -36,7 +36,7 @@ For the custom flow that allows users to add a new payment method to their accou 1. Uses the [`usePaymentElement()`](/docs/hooks/use-payment-element) hook to control the payment element, which is rendered by ``. 1. Assumes that you have already have a valid `planId`, which you can acquire in many ways. - [Copy from the Clerk Dashboard](https://dashboard.clerk.com/last-active?path=billing/plans?tab=user). - - Use the [Clerk Backend API](TODO). + - Use the [Clerk Backend API](/docs/reference/backend-api/tag/commerce/get/commerce/plans#tag/commerce/get/commerce/plans). - Use the new [`usePlans()`](/docs/hooks/use-plans) hook to get the plan details. This example is written for Next.js App Router but can be adapted for any React-based framework.