pythondjangostripe-payments

How to make a one-off charge (no UI) reusing the saved customer after initial Checkout?


I’m implementing payments with Stripe and I’ve run into a flow I don’t know how to solve. I’d like to know the right or recommended way.

Scenario

My problem:

  1. When I create the customer in Stripe, I see the payment_method is null. I try to create a new PaymentIntent to charge, but it needs a payment_method.

  2. ChatGPT says I should get the PaymentMethod ID, but I don’t know how. When I try to list the customer’s payment methods, it’s empty or null.

  3. If I try to reuse the PaymentMethod ID from the first charge, Stripe says I can’t use it again.

  4. I don’t know if I’m doing something wrong, or if it’s really not possible to charge again without asking for card details.

  5. How do I associate the card or PaymentMethod with the customer so I can charge them later with no UI, just from backend, no card details again?

Relevant code

# Django DRF, backend
@api_view(['POST'])
def create_payment(request):
    session = StripeSingleton().checkout.Session.create(
        success_url=f'{settings.STRIPE_SUCCESS_URL}?session_id={{CHECKOUT_SESSION_ID}}',
        line_items=[{'price': 'price_XXXX', 'quantity': 1}],
        mode='payment',
    )
    return Response({'success_url': session['url']}, status=200)

# Validation
@api_view(['GET'])
def validate_payment(request):
    session_id = request.GET.get('session_id')
    session = StripeSingleton().checkout.Session.retrieve(session_id)
    # Here I save the customer_id and email

Then for the extra payment, I try:

payment_intent = stripe.PaymentIntent.create(
    amount=2000,  # 20 pesos in cents
    currency='mxn',
    customer=customer_id,
    payment_method=payment_method_id, # I try to reuse this from the first charge
    off_session=True,
    confirm=True,
    description="Extra advice - one-off charge",
)

But Stripe gives me an error: You cannot use a PaymentMethod that was already used. And if I try to list customer’s payment methods, it shows empty or null.


Solution

  • When you create the Checkout Session for the first payment, you need to configure to save the card details automatically on the resulting Customer object. This is done using the payment_intent_data[setup_future_usage] parameter. This is documented here.

    If you configure this, the resulting Customer will have a PaymentMethod (pm_1234) attached automatically that you can then use for future payments. You can find the PaymentMethod id by looking at the payment_method property on the PaymentIntent associated with the Checkout Session for example.