Answers.Body: <p>I've solved this in the past by just showing the payment sources, and allowing the user to delete existing payment sources:</p>
  <pre><code>{% set paymentSources = craft.commerce.paymentSources.getAllPaymentSourcesByUserId(currentUser.id) %}
  
  {% if paymentSources %}
      &lt;table&gt;
          &lt;thead&gt;
              &lt;tr&gt;
                  &lt;th scope=&quot;col&quot;&gt;
                      Card details
                  &lt;/th&gt;
                  &lt;th scope=&quot;col&quot;&gt;
                      Actions
                  &lt;/th&gt;
              &lt;/tr&gt;
          &lt;/thead&gt;
          &lt;tbody&gt;
          {% for paymentSource in paymentSources %}
              &lt;tr&gt;
                  &lt;td&gt;{{ paymentSource.description }}&lt;/td&gt;
                  &lt;td&gt;
                      &lt;form method=&quot;post&quot;&gt;
                          {{ csrfInput() }}
                          {{ actionInput('commerce/payment-sources/delete') }}
                          {{ redirectInput(entry.uri) }}
                          &lt;input type=&quot;hidden&quot; name=&quot;id&quot; value=&quot;{{ paymentSource.id }}&quot;/&gt;
                          &lt;button type=&quot;submit&quot;&gt;Delete&lt;/button&gt;
                      &lt;/form&gt;
                  &lt;/td&gt;
              &lt;/tr&gt;
          {% endfor %}
          &lt;/tbody&gt;
      &lt;/table&gt;
  {% endif %}
  </code></pre>
  <p>You can then show a form to add a new payment source:</p>
  <pre><code>{% set customer = craft.commerce.customers.getCustomer() %}
  {# 
      Note: this next line fetches a single subscription - if you support multiple 
      subscriptions, you'll need to do it a little differently 
  #}
  {% set currentSubscription = customer.getSubscriptions()|first %}
  {% set plan = craft.commerce.plans.getPlanById(currentSubscription.planId) %}
  {% set gateway = plan.getGateway() %}
  
  &lt;form method=&quot;post&quot; accept-charset=&quot;UTF-8&quot; autocomplete=&quot;off&quot; novalidate&gt;
      {{ csrfInput() }}
      {{ actionInput('commerce/payment-sources/add') }}
      {{ redirectInput(entry.uri) }}
      &lt;input type=&quot;hidden&quot; name=&quot;gatewayId&quot; value=&quot;{{ gateway.id }}&quot;&gt;
  
      {{ gateway.getPaymentFormHtml({})|raw }}
  
      &lt;button type=&quot;submit&quot;&gt;Add card&lt;/button&gt;      
  &lt;/form&gt;
  </code></pre>
  <p>This is probably the simplest answer to your question, though you can get creative with how you present the payment sources and the add card form to the user.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-11-05T14:48:20.837Z
Answers.Text: Great answer, thank you Martin! Much appreciated.
Answers.UserDisplayName: James
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-11-04T15:38:13.637Z
Answers.LastActivityDate: 2020-11-05T17:21:21.640Z
Answers.LastEditDate: 2020-11-05T17:21:21.640Z
Answers.UserDisplayName: Martin Spain
Body: <p>The Craft Commerce config allows you to set <code>updatebillingdetailsurl</code>. <a href="https://craftcms.com/docs/commerce/3.x/configuration.html#updatebillingdetailsurl" rel="nofollow noreferrer">The docs</a> say,</p>
  <blockquote>
  <p>The URL for a user to resolve billing issues with their subscription.</p>
  </blockquote>
  <p>There’s an example of this in the example templates that come with Commerce and this uses <code>getBillingIssueResolveFormHtml()</code>.</p>
  <p>However, rather than <em>resolve</em> an issue, what I’m looking for is a way for customers with a subscription (via Stripe) to be able to update their billing information <em>before</em> there is a billing issue. Often customers realise their card has expired or want to change their card before the subscription renews, especially as we send emails to notify them about renewals. What’s the best way to create that form, or allow someone to do that?</p>
  
Tags: <plugin-craftcommerce><plugin-commerce-stripe>
Title: Update billing details for a subscription
ThreadText: # Update billing details for a subscription
  
  (Asked by: username_0 on 2020-11-04)
  
  The Craft Commerce config allows you to set `updatebillingdetailsurl`. [The docs](https://craftcms.com/docs/commerce/3.x/configuration.html#updatebillingdetailsurl) say,
  
  > The URL for a user to resolve billing issues with their subscription.
  
  There’s an example of this in the example templates that come with Commerce and this uses `getBillingIssueResolveFormHtml()`.
  
  However, rather than *resolve* an issue, what I’m looking for is a way for customers with a subscription (via Stripe) to be able to update their billing information *before* there is a billing issue. Often customers realise their card has expired or want to change their card before the subscription renews, especially as we send emails to notify them about renewals. What’s the best way to create that form, or allow someone to do that?
  
  **Tags:** plugin-craftcommerce, plugin-commerce-stripe
  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2020-11-04. Score: 5 | Accepted answer
  
  I've solved this in the past by just showing the payment sources, and allowing the user to delete existing payment sources:
  
  ```
  {% set paymentSources = craft.commerce.paymentSources.getAllPaymentSourcesByUserId(currentUser.id) %}
  
  {% if paymentSources %}
      <table>
          <thead>
              <tr>
                  <th scope="col">
                      Card details
                  </th>
                  <th scope="col">
                      Actions
                  </th>
              </tr>
          </thead>
          <tbody>
          {% for paymentSource in paymentSources %}
              <tr>
                  <td>{{ paymentSource.description }}</td>
                  <td>
                      <form method="post">
                          {{ csrfInput() }}
                          {{ actionInput('commerce/payment-sources/delete') }}
                          {{ redirectInput(entry.uri) }}
                          <input type="hidden" name="id" value="{{ paymentSource.id }}"/>
                          <button type="submit">Delete</button>
                      </form>
                  </td>
              </tr>
          {% endfor %}
          </tbody>
      </table>
  {% endif %}
  
  ```
  
  You can then show a form to add a new payment source:
  
  ```
  {% set customer = craft.commerce.customers.getCustomer() %}
  {# 
      Note: this next line fetches a single subscription - if you support multiple 
      subscriptions, you'll need to do it a little differently 
  #}
  {% set currentSubscription = customer.getSubscriptions()|first %}
  {% set plan = craft.commerce.plans.getPlanById(currentSubscription.planId) %}
  {% set gateway = plan.getGateway() %}
  
  <form method="post" accept-charset="UTF-8" autocomplete="off" novalidate>
      {{ csrfInput() }}
      {{ actionInput('commerce/payment-sources/add') }}
      {{ redirectInput(entry.uri) }}
      <input type="hidden" name="gatewayId" value="{{ gateway.id }}">
  
      {{ gateway.getPaymentFormHtml({})|raw }}
  
      <button type="submit">Add card</button>      
  </form>
  
  ```
  
  This is probably the simplest answer to your question, though you can get creative with how you present the payment sources and the add card form to the user.
  
  > **Comments:**
  > **username_0**: Great answer, thank you username_1! Much appreciated.  
  
  ---
  
  