Update billing details for a subscription
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 %}
    &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 %}

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() %}

&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;

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.