Episodes
tbcooney PRO said almost 3 years ago on Payment Gateway Basics with Stripe :
I think the way that Stripe handles Subscriptions and Customers has changed recently, where `Stripe::Subscriptions.create` no longer requires the source, but must be passed to `Stripe::Customers.create` instead. I'm having trouble creating the `stripe_customer` method because of this (since the token must be passed to where ever the Customer is being created. Any chance you code shed some insight on this?

David Kimura PRO said almost 3 years ago on Payment Gateway Basics with Stripe :
I believe you're correct. Here's something similar to how I'm handling it now. I fetch the stripe customer, create a source from the token generated from stripe, set the source to the customer and then create a subscription on the customer with the plan and personally, I always pass in an idempotency key. ``` customer = current_user.stripe_customer source = customer.sources.create({ source: token }) customer.default_source = source customer.save subscription = customer.subscriptions.create({ plan: plan }, { idempotency_key: unique_key }) ```

tbcooney PRO said almost 3 years ago on Payment Gateway Basics with Stripe :
Gotchya...thanks for the quick reply man! I'll rollback my custom `stripe_customer` approach to follow yours, creating a customer from the email, and try to create the `source` after as you outlined above.

tbcooney PRO said almost 3 years ago on Payment Gateway Basics with Stripe :
Also, I like the idea of using an idempotent key, since we don't have the single-use guarantee that comes with a token generated by Stripe.js. Are you passing your idempotency key through the user's browser via the payment form and back into your controller? Not sure how to set this up exactly but I think it would help alleviate accidental double clicks along with any network hiccups

David Kimura PRO said almost 3 years ago on Payment Gateway Basics with Stripe :
It's kind of strange how it works. The client browser side of things only communicates to the Stripe servers. The Stripe servers respond back with a token. In our javascript, we then add the token to the form parameters and then submit our form to the application. So, we would have something like a plan name and then the generated stripeToken which gets sent to our servers (never the credit card information!). From there, we will do the actual charge. The stripeToken is really just a "preauthorization" rather than a purchase. We then create the idempotent key. So, if you were to have it all in the create action of the subscriptions controller, it would look something like this. However, I would move out the logic for creating the stripe customer and the subscription into a service object. The unique_key can really be anything that will be unique. In this case, you could generate a timestamp for the user as an epoch time in milliseconds. ``` def create begin customer = current_user.stripe_customer source = customer.sources.create({ source: params[:stripeToken] }) customer.default_source = source customer.save subscription = customer.subscriptions.create({ plan: 'plus' }, { idempotency_key: unique_key }) current_user.update(stripe_subscription_id: subscription.id) redirect_to root_path, notice: 'Thanks for subscribing!' rescue Stripe::CardError => e flash.alert = e.message render action: :new end end private def unique_key @unique_key ||= Rails.cache.fetch(['stripe', current_user], expires_in: 5.minutes) { (Time.now.to_f * 1000000).to_i.to_s } end ```

David Kimura PRO said almost 2 years ago on Payment Gateway Basics with Stripe :
  sbryans1210  can you provide more context? It sounds like you're passing the name parameter into a Stripe call and it doesn't recognize that parameter. Is this when trying to create a Plan? If so, look at the show notes for an update to this as their API has changed.

atayl16 PRO said over 1 year ago on Payment Gateway Basics with Stripe :
I had the craziest time getting this to work. In the end, my element was just not showing (maybe browser extension problems -_-). If you only see a tiny grey box on your screen when you expect to see a credit card input box, try adding this to the .StripeElement in your subscription.css file:

min-width: 300px;

So it now looks like this
.StripeElement {
  background-color: #EEEEEE;
  margin-top: 20px;
  margin-bottom: 20px;
  padding: 10px;
  border-radius: 4px;
  border: 1px solid transparent;
  box-shadow: 0 1px 3px 0 #e6ebf1;
  -webkit-transition: box-shadow 150ms ease;
  transition: box-shadow 150ms ease;
  min-width: 300px;
}

Thanks for the lesson! Spot on, as always =)

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
   Marco De Rossi I prefer Stripe Checkout now since it handles a lot of things out of the box that you don't have to think about like the 3D Secure credit cards and any other security practices. I do have recent episodes on that topic.

However, if you still want to go this route, check your browser's dev console to see if there are any javascript errors on the page and let us know.

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
  Marco De Rossi The Stripe API 2020-08-27 and later no longer have the customer.subscriptions option by default. Instead to get the user's subscription you can do this.

Stripe::Subscription.retrieve(user.stripe_subscription_id)

or

Stripe::Subscription.list(customer: user.stripe_id).first

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
In the stripe_customer method, You wouldn't need to search the subscriptions with customer: user.stripe_id since you're in the user model already. Just use stripe_id
On the create action, You should create a Subscription and pass in the stripe customer id.

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
I'm not sure why the stripe_customer is nil. Are you getting any errors from the stripe_customer method in the user model. The guard clause that you have may be problematic as you're likely returning nil since the user has a stripe_id (assuming). If the stripe_id exists, but you're getting nil returned when looking up the customer, you may have some other kind of problem going on. Looking a bit closer at it. you're trying to return a subscription on the stripe_customer method. You should be retrieving the customer (https://stripe.com/docs/api/customers/create?lang=ruby and also see the retrieve customer section) 

The second issue you'll run into is the customer.subscriptions. Once you do have a customer object, you'll get the undefined method subscriptions for the stripe customer. You'll need to look up the subscription based on the subscription_id. https://stripe.com/docs/api/subscriptions/retrieve?lang=ruby

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
The stripe_customer method returns nil?

Did you change your stripe_customer method to pull the customer instead of the subscription (i.e., return Stripe::Customer.retrieve(stripe_id) if stripe_id?
)

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
This needs to be changed. You cannot scope subscriptions on the customer anymore.
subscription = customer.subscriptions.create(source: params[:stripeToken], plan: 'starter')

to something like this. I haven't tested this, but this is likely the basic flow where you attach the source to the customer (i.e., the payment method) and then you create the subscription.

customer.update({ default_source: params[:stripeToken] })
Stripe::Subscription.create({
  customer: customer,
  plan: 'starter'
})



David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
That's strange. The docs, https://stripe.com/docs/api/customers/update?lang=ruby , show the customer object using the update method.



David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
  Marco De Rossi Maybe try

customer.default_source = params[:stripeToken]
customer.save

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
  Marco De Rossi  Can you drill into the Starter plan, there should be an ID in there which is what you need to use within your code.

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
Stripe::Plan.create(
  { 
    product: { 
      name: 'Pro',               
      id: 'pro'
    }, 
    id: 'pro',
    interval: 'month', 
    currency: 'usd', 
    amount: 1500
  }
)

This is what I use to create the Product/Plan

Marco De Rossi said over 1 year ago on Payment Gateway Basics with Stripe :
ok  David Kimura
now this

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
what happens when you call customer.save after you set the customer.default_source?

Marco De Rossi said over 1 year ago on Payment Gateway Basics with Stripe :
  David Kimura   i get a  "No such source: 'tok_1IEyevCNZVElf42nsxKMkPnA'" ERROR


David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
Ah, okay, I thought that Stripe created the source, but it looks like they're just verifying that the source would be valid.

source = Stripe::Source.create(token: params[:stripeToken])
customer.default_source = source
customer.save

Marco De Rossi said over 1 year ago on Payment Gateway Basics with Stripe :
  David Kimura The errors are not stopping. Are you available for a zoom mentoring?
 def create
      customer = current_user.stripe_customer
      source = Stripe::Source.create(token: params[:stripeToken])
      customer.default_source = source
      customer.save
      begin
        Stripe::Subscription.create(
          customer: customer,
          plan: 'pro'
        ) 
        current_user.assign_attributes(stripe_subscription_id: subscription.id)
        current_user.save
        redirect_to root_path, notice: 'Thanks for subscribing!'
      rescue Stripe::CardError => e
        flash.alert = e.message
        render action: :new
      end

Error

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
  Marco De Rossi I am really trying to help guide you without giving all of the answers because there is so much in learning to troubleshoot these issues. In your particular case, the Stripe::Source.create has a required parameter called type. Since it would be impossible (or improbable) for anyone to know what that means except for the Stripe developers, it's important to look at their provided documentation. In this case, the Stripe::Source.create points to this reference in the documentation. https://stripe.com/docs/api/sources/create#create_source-type

Since they don't give much meaning to what the type parameter is as far as the available values, we need to look at the source object. https://stripe.com/docs/api/sources/object#source_object-type

Since you're taking in credit cards, you would use the type "card"

So your code should look like

source = Stripe::Source.create(type: 'card', token: params[:stripeToken])

I am not positive, but I would avoid the card_present option as that is typically when the card is physically present when entering the details. 

Marco De Rossi said over 1 year ago on Payment Gateway Basics with Stripe :
  David Kimura   i am having this new error. I have look at the doc. the source on the API doc is different from the source on my app. Is that normal behaviour

this is the source on my stripe


this is from byebug

(byebug) customer.default_source
#<Stripe::Source:0x8200 id=src_1IF0owCNZVElf42nYAuFRW1v> JSON: {
  "id": "src_1IF0owCNZVElf42nYAuFRW1v",
  "object": "source",
  "amount": null,


David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
Their API within their Docs should be the latest ways of handling changes. Was this all from the same request? It's really strange that the source in the first image doesn't match the source ID from the byebug.

Marco De Rossi said over 1 year ago on Payment Gateway Basics with Stripe :
  David Kimura No sorry, my mistake. I took the screenshot and made another request.  The source from the byebug always matches that of the error. 
I really need help. I am stuck here. Any idea the reason for the error

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
With byebuy enabled, and once it gets triggered, head over to stripe to see if you can look up the source that was created before it is assigned to the customer.

David Kimura PRO said over 1 year ago on Payment Gateway Basics with Stripe :
And honestly, I would still really recommend checking out Stripe Checkout. It is so much easier to work with than the Payments API. I would only recommend the Payments API if you are dead set on having a single experience. And, personally, I have some assurance feeling knowing that I'm entering my card details on Stripe's website itself and not through the Payments API as I cannot always trust how a website is handling that information.

Marco De Rossi said over 1 year ago on Payment Gateway Basics with Stripe :
   David Kimura  Thanks .

nelsonchavespro said 3 months ago on Payment Gateway Basics with Stripe :
does this not work anymore? or is it still up to date? it keeps breaking for me on ```customer.subscriptions.create``` from the subscriptions controller

David Kimura PRO said 3 months ago on Payment Gateway Basics with Stripe :
They may have changed the api again. I stopped using their Stripe Payments solution and prefer the Stripe Checkout. But, if this is the route you want to go. see this resource of their latest API docs. https://stripe.com/docs/api/subscriptions/create

Stripe::Subscription.create({
  customer: 'CUSTOMER_NUMBER',
  items: [
    {price: 'price_1aUj7wdGdu1FeVHa2AEY0Rph'},
  ],
})

Login to Comment