20

I have saved stripe customer id's in my db for later payments. A customer will have multiple cards and I would like to check/validate new customer cards with their existing cards.

Suppose the same card details can be stored multiple times as multiple cards.

I want to check using the Stripe token whether a newly entered card already exists or not. It will use it if it's already there, if not it will create a new card.

fgblomqvist
  • 2,244
  • 2
  • 32
  • 44
Raju akula
  • 1,255
  • 1
  • 13
  • 18
  • 1
    `fingerprint` is the way to check duplicate card. you can check `fingerprint` in card object or token object. please follow this : https://stackoverflow.com/questions/29222249/stripe-api-checking-for-existing-card?answertab=votes#tab-top – Manoj Kumar Jul 19 '19 at 02:46

4 Answers4

29

Unfortunately while working on Stripe today I noticed that it do allows storing of duplicate cards. To avoid this, I did following steps:

#fetch the customer 
customer = Stripe::Customer.retrieve(stripe_customer_token)
#Retrieve the card fingerprint using the stripe_card_token  
card_fingerprint = Stripe::Token.retrieve(stripe_card_token).try(:card).try(:fingerprint) 
# check whether a card with that fingerprint already exists
default_card = customer.cards.all.data.select{|card| card.fingerprint ==  card_fingerprint}.last if card_fingerprint 
#create new card if do not already exists
default_card = customer.cards.create({:card => stripe_card_token}) unless default_card 
#set the default card of the customer to be this card, as this is the last card provided by User and probably he want this card to be used for further transactions
customer.default_card = default_card.id 
# save the customer
customer.save 

fingerprint of a card stored with stripe is always unique

If you want to make fewer calls to stripe, it is recommended that you store the fingerprints of all the cards locally and use them for checking uniqueness. Storing fingerprints of cards locally is secure and it uniquely identifies a card.

double-beep
  • 5,031
  • 17
  • 33
  • 41
Sahil Dhankhar
  • 3,596
  • 2
  • 31
  • 44
  • Are you storing card_id's in your db? – Batman Oct 22 '15 at 05:11
  • 14
    This answer is only partially complete. The card fingerprint is only useful for matching the **card number**. You must also check to make sure the expiration date hasn't changed as well. If a customer has the same card number, but an updated expiration date, this answer will not create a new card. – Sean S Jun 06 '16 at 22:49
17

For people reading this in 2016: Sahil Dhankhar answer is still correct, although Stripe have apparently changed their API syntax:

customer.cards

is now:

customer.sources

So, correct syntax would now be:

#fetch the customer 
customer = Stripe::Customer.retrieve(stripe_customer_token)
#Retrieve the card fingerprint using the stripe_card_token  
card_fingerprint = Stripe::Token.retrieve(stripe_card_token).try(:card).try(:fingerprint) 
# check whether a card with that fingerprint already exists
default_card = customer.sources.all.data.select{|card| card.fingerprint ==  card_fingerprint}.last if card_fingerprint 
#create new card if do not already exists
default_card = customer.sources.create({:card => stripe_card_token}) unless default_card 
#set the default card of the customer to be this card, as this is the last card provided by User and probably he want this card to be used for further transactions
customer.default_card = default_card.id 
# save the customer
customer.save 

Hope this helps someone!

Edu Wass
  • 1,969
  • 1
  • 21
  • 22
10

The card fingerprint is only useful for matching the card number. You must also check to make sure the expiration date hasn't changed as well. If a customer has the same card number, but an updated expiration date

customer = Stripe::Customer.retrieve(customer_stripe_id)

# Retrieve the card fingerprint using the stripe_card_token
newcard = Stripe::Token.retrieve(source_token)
card_fingerprint = newcard.try(:card).try(:fingerprint)
card_exp_month = newcard.try(:card).try(:exp_month)
card_exp_year = newcard.try(:card).try(:exp_year)

# Check whether a card with that fingerprint already exists
default_card = customer.sources.all(:object => "card").data.select{|card| ((card.fingerprint==card_fingerprint)&&(card.exp_month==card_exp_month)&&(card.exp_year==card_exp_year))}.last
default_card = customer.sources.create(source: source_token) if !default_card

# Set the default card of the customer to be this card, as this is the last card provided by User and probably he wants this card to be used for further transactions
customer.default_card = default_card.id

# Save the customer
customer.save
Jai Chauhan
  • 4,035
  • 3
  • 36
  • 62
  • This is the correct way of doing it (in 2018), all the other answers miss a thing or two. However, the variable name `default_card` is wrong/confusing since the code does not retrieve the default card, but rather it returns a boolean that shows whether the card already exists or not. – fgblomqvist Nov 30 '18 at 20:02
  • 1
    the `&&` is better than `and` – srghma Feb 22 '23 at 11:52
  • Updated `&&` operator with `and` – Jai Chauhan Feb 23 '23 at 05:20
6

It sounds like you're caching the card data locally to be able to display it to the customer.

If that is correct, Stripe provides a fingerprint for each card/token which you can begin storing in the card records (if you're not already). 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.

As a simple example, assuming a User has_many :cards:

token = Stripe::Token.retrieve("tok_a1b2c3d4")

unless current_user.cards.find_by(fingerprint: token.card.fingerprint)
  current_user.cards.create( ... # data from token )
end

If you're not caching the card data locally, Stripe handles duplicates for you and you don't need to do anything.

colinm
  • 4,258
  • 24
  • 19
  • 3
    Here, I just creating the card with new token for the particular customer. Next will get fingerprint for that card and will check with this fingerprint to rest of cards from that customer. If any found already, will delete this card. If not found any duplicate then will keep this card as usual. So that here, we won't get multiple cards with same card details like duplicate cards for particular customer. – Raju akula May 23 '14 at 05:59
  • 3
    As of now, stripe creating duplicate cards as If i enter same card details multiple times it will create multiple cards with that same details for that particular customer. So I done as above. Please let me know your comments If I am wrong anything. – Raju akula May 23 '14 at 06:04
  • 3
    @colinm unfortunately stripe currently not handling duplicates – Sahil Dhankhar Sep 27 '14 at 13:40
  • Stripe still does not handle duplicates – fgblomqvist Nov 15 '18 at 15:52