# Build a custom flow for adding a new payment method

> This guide is for users who want to build a custom flow. To use a _prebuilt_ UI, use the [Account Portal pages](https://clerk.com/docs/guides/account-portal/overview.md?sdk=nextjs) or [prebuilt components](https://clerk.com/docs/nextjs/reference/components/overview.md).

> Billing is currently in Beta and its APIs are experimental and may undergo breaking changes. To mitigate potential disruptions, we recommend [pinning](https://clerk.com/docs/pinning.md?sdk=nextjs) your SDK and `clerk-js` package versions.

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](https://clerk.com/docs/nextjs/guides/development/custom-flows/billing/checkout-new-payment-method.md).

1. ## Enable Billing Features

   To use Billing Features, you first need to ensure they are enabled for your application. Follow the [Billing documentation](https://clerk.com/docs/guides/billing/overview.md?sdk=nextjs) to enable them and set up your Plans.
2. ## Build the custom flow

   To add a new payment method for a user, you must:

   1. Set up the [<PaymentElementProvider />](https://clerk.com/docs/nextjs/reference/hooks/use-payment-element.md) to create a context for the user's payment actions.
   2. Render the [<PaymentElement />](https://clerk.com/docs/nextjs/reference/hooks/use-payment-element.md) to display the secure payment fields from your provider.
   3. Use the [usePaymentElement()](https://clerk.com/docs/nextjs/reference/hooks/use-payment-element.md) hook to submit the form and create a payment token.
   4. Use the [useUser()](https://clerk.com/docs/nextjs/reference/hooks/use-user.md) 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:

   - **`<UserBillingPage />`**: Sets up the `<PaymentElementProvider />`, which specifies that the payment actions within its children are `for` the `user`.
   - **`<AddPaymentMethodForm />`**: Renders the payment form and handles the submission logic. 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.

     **<UserBillingPage />**

     filename: app/user/billing/page.tsx

     ```tsx
     import { ClerkLoaded } from '@clerk/nextjs'
     import { PaymentElementProvider } from '@clerk/nextjs/experimental'
     import { AddPaymentMethodForm } from './AddPaymentMethodForm'

     export default function Page() {
       return (
         <div>
           <h1>Billing Settings</h1>

           <ClerkLoaded>
             <PaymentElementProvider for="user">
               <AddPaymentMethodForm />
             </PaymentElementProvider>
           </ClerkLoaded>
         </div>
       )
     }
     ```

     **<AddPaymentMethodForm />**

     filename: app/user/billing/AddPaymentMethodForm.tsx

     ```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<string | null>(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(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 (
         <form onSubmit={handleAddPaymentMethod}>
           <h3>Add a new payment method</h3>
           <PaymentElement />
           <button type="submit" disabled={!isFormReady || isSubmitting}>
             {isSubmitting ? 'Saving...' : 'Save Card'}
           </button>
           {error && <p style={{ color: 'red' }}>{error}</p>}
         </form>
       )
     }
     ```

---

## Sitemap

[Overview of all docs pages](https://clerk.com/docs/llms.txt)
