Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stripe update customer default card (PHP)

I'd like to update the default card for a customer using Stripe.

In the update customer API docs it is not clear what to feed in for the card parameter.

In PHP, I've tried setting the card based on the retrieve card method like this:

$customer->card=$card['id']

but that doesn't appear to work. Nor does using the token like this:

$customer->source=$_POST['stripe_token]

so I'm a bit at a loss. Thoughts?

like image 609
tim peterson Avatar asked Apr 20 '15 16:04

tim peterson


People also ask

How do I change my default card in Stripe?

Create new card & assign card as default source If you want to create a new card & set that new card to be the default card try this. *Note the stripe token should come from a stripe js request and the stripe customer id will likely come from the authenticated user.

How can my clients update their card information on Stripe?

To update the payment information of an existing customer, you'd need to first collect the new card's information (using Checkout or your own form with Stripe. js), then send a customer update request with the new card's token in the source parameter.

Does Stripe automatically update card?

Stripe works with card networks and automatically attempts to update saved card details whenever a customer receives a new card (for example, replacing an expired card or one that was reported lost or stolen).

Can I check whether a Stripe customer already has a specific card before adding a new one?

Each fingerprint is unique to a card, so before storing additional cards for a customer, you can simply search the user's cards by fingerprint. If you're not caching the card data locally, Stripe handles duplicates for you and you don't need to do anything.


3 Answers

I was able to answer my own question with Stripe's support on IRC #stripe channel:

The card parameter is specified by default_source like this:

Stripe::setApiKey($stripe_private_key);
$customer = Stripe_Customer::retrieve($stripe_cus_id);
$customer->default_source=$card['id'];
$customer->save();  
like image 81
tim peterson Avatar answered Sep 30 '22 01:09

tim peterson


Create new card & assign card as default source

If you want to create a new card & set that new card to be the default card try this.

*Note the stripe token should come from a stripe js request and the stripe customer id will likely come from the authenticated user.

// Get the customer
$customer = Customer::retrieve("cus_9jF6ku4f2pztRo");

// Add a new card to the customer
$card = $customer->sources->create(['source' => "tok_19PmcMI94XzVK71QeIwtUJmM"]);

// Set the new card as the customers default card
$customer->default_source = $card->id;
$customer->save();
like image 42
Rob Avatar answered Sep 30 '22 02:09

Rob


1. Overview

@tim peterson's answer is complete and satisfies the question originally posed. However, this Stackoverflow question is one of the first hits for setting the default card for Stripe - so I wanted to document my own findings in a bit more detail.

 

2. Flow

It's first important to understand the flow of saving a card, and it's importance for securely storing references to credit cards.

Generally you will either add a card and set it as default on the spot, or store the credit card id (not credit card number!) in your database to perform actions against.

Note that when adding a first card to a user, it will be the default by, well, default.

 

2.1. Customer Creation

  1. From your app create a customer in Stripe via the api
  2. A customer object is returned by Stripe, including, customer->id
  3. At minimum, store customer->id in your app. This would typically be in the user table or similar.

A VARCHAR at 255 characters seems appropriate - however, after chatting with Stripe directly, they don't have a document length of id's in their system.

 

2.2. Card Creation

At a later stage, you will want to add a card.

  1. First use the Stripe JS library as well documented on their site. The idea here is that the form's submit action points directly at the Stripe servers, so when the form is submitted the real credit card details never hit your server. Although it's technically possible to create cards without Stripe JS, unless there is a good reason, I would stick to the recommend way and let it do the heavy lifting.
  2. The user is on your credit card form, and the following happens:
  3. They enter their credit card details into your form
  4. They hit submit
  5. All form input is sent to Stripe via ajax
  6. Upon success Stripe JS will return a response with the following data:

    • response.id
    • response.card.id
    • response.card.last4
    • response.card.brand
    • response.card.exp_month
    • response.card.exp_year
  7. In Stripe's examples, they append to the DOM a bunch of hidden form elements, fill the above data, then "submit the form for realz this time".

  8. Your backend, whatever that may be, will receive the above data, and you can store it as you see fit.

 

2.3. Setting the Default

Now back to the original question. At some stage, you may have a user with multiple cards and need to set one as default.

Because you stored the return data from the above form, you should now have a list of cards, card ids, and whatnot in your database. So simply loop over them, and which ever card the user clicks as the default, fetch the card id, and update the default_source property against the customer object with the card id value.

 

3 Examples

This will mirror the above three steps with some very loose code snippets (using PHP but should be easy enough to follow along).

Note I am skipping over error catching and exceptions for the sake of brevity. When doing any interaction with an external source it's alway good practice to be diligent with your exception handling - basically assume that the service will fail.

 

3.1 Customer Creation

// Send details to Stripe
$customer = \Stripe\Customer::create([
    'email' => $this->user->email,
    'description' => $this->user->name,
]);

// Then update our application
$this->user->stripe_customer_id = $customer->id;
$this->user->save();

 

3.2 Card Creation

3.2.1 Javascript

module.exports = (function() {
    function CreditCard() {
        $('#payment-form').submit(function(e) {
            var $form = $(this);

            // Disable the submit button to prevent repeated clicks
            $form.find('button').prop('disabled', true);

            Stripe.card.createToken($form, function(status, response) {
                var $form = $('#payment-form');
                if (response.error) {
                    // Show the errors on the form
                    $form.find('.payment-errors').text(response.error.message);
                    $form.find('.payment-errors').parents(".row").show();
                    $form.find('button').prop('disabled', false);
                } else {
                    // token contains id, last4, and card type
                    var token = response.id;
                    var cardId = response.card.id;
                    var last4 = response.card.last4;
                    var brand = response.card.brand;
                    var expMonth = response.card.exp_month;
                    var expYear = response.card.exp_year;

                    // Insert the token into the form so it gets submitted to the server
                    $form.append($('<input type="hidden" name="stripeToken" />').val(token));
                    $form.append($('<input type="hidden" name="cardId" />').val(cardId));
                    $form.append($('<input type="hidden" name="last4" />').val(last4));
                    $form.append($('<input type="hidden" name="brand" />').val(brand));
                    $form.append($('<input type="hidden" name="expMonth" />').val(expMonth));
                    $form.append($('<input type="hidden" name="expYear" />').val(expYear));

                    // and re-submit
                    $form.get(0).submit();
                }
            });

            // Prevent the form from submitting with the default action
            return false;
        });
    }

    return CreditCard;
})();

 

3.2.2 Backend

public function save(string $token, string $cardId, string $last4, string $brand, int $expMonth, int $expYear)
{
    // Store in our application
    $creditCard = $this->user->creditCards()->create([
        'token_id' => $token,
        'card_id' => $cardId,
        'last4' => $last4,
        'brand' => $brand,
        'exp_month' => $expMonth,
        'exp_year' => $expYear
    ]);
}

 

3.3 Setting the default

    Customer::retrieve($this->user->stripe_customer_id);
    $customer->default_source = $cardId;
    $customer->save();
like image 44
Chris Avatar answered Sep 30 '22 01:09

Chris