1
votes

I am creating a simple web page where the Stripe Checkout will prompt the user for their card info, generate a token, and send it to my backend Go webserver that processes the payment for that token. The issue I'm having is that when I get the token, I try and create a customer and set the source to the token created by Stripe, but I get this response everytime:

charge failed: {"type":"invalid_request_error","message":"Customer cus_######### does not have a linked source with ID tok_#########.","code":"missing","param":"source","request_id":"req_######","status":404}

Creating the customer and associating the card with that customer works just fine. But, charging the card based on the token Stripe generated fails. Even though in the logs for that customer in my Stripe Dashboard it shows the attempted charge. So, it's trying to associate the charge with the correct customer, but failing because the token was generated without a specific customer in mind? I'm not really sure what is going on.

The code I have on the backend that accepts the token and processes everything is below:

stripe.Key = "sk_test_################"

customerParams := &stripe.CustomerParams{
    Desc:          "Customer for xyz.com",
    Email:         "[email protected]",
}

err := customerParams.SetSource("tok_####################")
if err != nil {
    return nil, err
}

cus, err := customer.New(customerParams)
if err != nil {
    return nil, err
}

// Charge the user's card
cp := &stripe.ChargeParams{
    Amount:   100,
    Currency: "usd",
    Desc:     "some description",
    Customer: cus.ID,
}

err = cp.SetSource("tok_####################")
if err != nil {
    return nil, err
}

err = charge.New(cp)

Also, if I remove the customer portion of this example, the charge goes through just fine with the above code. It just doesn't associate the charge with a customer obviously. However, as soon as I try to set the customer on the charge it fails.

3
Questions seeking debugging help ("why isn't this code working?") must include the desired behavior, a specific problem or error and the shortest code necessary to reproduce it in the question itself. Questions without a clear problem statement are not useful to other readers. See: How to create a Minimal, Complete, and Verifiable example.peterSO

3 Answers

2
votes

Turns out the issue was setting the token source on the charge params after I had already set the source of the new customer I was charging. The following worked as expected to create a new customer and associate the new charge with the customer:

stripe.Key = "sk_test_################"

customerParams := &stripe.CustomerParams{
    Desc:          "Customer for xyz.com",
    Email:         "[email protected]",
}

err := customerParams.SetSource("tok_####################")
if err != nil {
    return nil, err
}

cus, err := customer.New(customerParams)
if err != nil {
    return nil, err
}

// Charge the user's card
cp := &stripe.ChargeParams{
    Amount:   100,
    Currency: "usd",
    Desc:     "some description",
    Customer: cus.ID,
}

err = charge.New(cp)
0
votes

That's expected: the customer you just created doesn't have a payment source attached, so they can't pay your $1.00 charge. You can make the above succeed by, for example, using one of the test tokens when you create the customer:

customerParams := &stripe.CustomerParams{
    Desc:          "Customer for xyz.com",
    Email:         "[email protected]",
    Source:        "test_visa"
}

More on test cards and sources here: https://stripe.com/docs/testing#cards

You will of course want to use Elements or Checkout to tokenize card numbers in your production application, which makes sure that raw credit card numbers pass only to Stripe and not your application servers: https://stripe.com/docs/elements

0
votes

I had the same problem with stripe subscriptions.

Bottom line, if a customer already exists without a valid payment source;

  1. You either need add/associate a source to a customer after the fact Attaching a Source to an existing Customer object or,
  2. Update existing customer with a new token as the source from checkout i.e update customer

    func updateCustomer(custID, email, source string) (cus *stripe.Customer, err error){ params := &stripe.CustomerParams{ Email:email, } params.SetSource(source) cus, err = customer.Update(custID, params) return }