stripe / stripe-node

Node.js library for the Stripe API.
https://stripe.com
MIT License
3.88k stars 751 forks source link

Error payment_methods #636

Closed Taakn closed 5 years ago

Taakn commented 5 years ago

Hello,

I am migrating from the charges API to the payment intent API for 3D Secure. I am using Stripe API 6.36.0 and node 8.4

Initial request from the Stripe Dashboard: POST Request /v1/payment_methods

{
  "type": "card",
  "card": {
    "number": "424242******4242",
    "cvc": "***",
    "exp_month": "12",
    "exp_year": "19"
  },
  "billing_details": {
    "address": {
      "postal_code": "75002"
    }
  },
  "guid": "ed4e8e7e-bd47-4926-808d-1bf0813f4907",
  "muid": "858fa8f7-c76d-441b-b62c-c848d12a825f",
  "sid": "d9ddbd87-0747-49fb-ae61-30a5606983aa",
  "pasted_fields": "number",
  "payment_user_agent": "stripe.js/74d012ca; stripe-js-v3/74d012ca",
  "key": "pk_test_********************n2re"
}

Response body:

{
  "id": "pm_1EgTq0EqCinWwzYxBu1Za5g2",
  "object": "payment_method",
  "billing_details": {
    "address": {
      "city": null,
      "country": null,
      "line1": null,
      "line2": null,
      "postal_code": "75002",
      "state": null
    },
    "email": null,
    "name": null,
    "phone": null
  },
  "card": {
    "brand": "visa",
    "checks": {
      "address_line1_check": null,
      "address_postal_code_check": "unchecked",
      "cvc_check": "unchecked"
    },
    "country": "US",
    "exp_month": 12,
    "exp_year": 2019,
    "funding": "credit",
    "generated_from": null,
    "last4": "4242",
    "three_d_secure_usage": {
      "supported": true
    },
    "wallet": null
  },
  "created": 1559382560,
  "customer": null,
  "livemode": false,
  "metadata": {
  },
  "type": "card"
}

Followed by POST request /v1/payment_intents

{
  "amount": "1900",
  "currency": "eur",
  "payment_method": "pm_1EgTq0EqCinWwzYxBu1Za5g2",
}

And 400 Response:

{
  "error": {
    "code": "resource_missing",
    "doc_url": "https://stripe.com/docs/error-codes/resource-missing",
    "message": "No such payment_method: pm_1EgTq0EqCinWwzYxBu1Za5g2",
    "param": "payment_method",
    "type": "invalid_request_error"
  }
}

Can't understand why the payment method is being denied since it's confirmed just above. I am following your guide here: https://stripe.com/docs/payments/payment-intents/quickstart#manual-confirmation-flow

Thanks so much for your help

tdamant commented 5 years ago

@Taakn Did you manage to understand what was the problem here? I'm facing the same issue currently, however if I use curl it works.

karlr-stripe commented 5 years ago

@tdamant this type of error is usually caused by accidentally using API keys from a different account, or if you're using Connect, not authenticating as the relevant account. I'd suggest double- and triple-checking that you are using the same API keys from https://dashboard.stripe.com/test/apikeys across your frontend and backend. Sometimes if you copy an example from Stripe's docs, they have dummy keys that don't belong to your account and that can cause issues so it's best to check everywhere you're using an API key that it's from the right account.

If you're facing trouble, you can contact Stripe's support team at https://support.stripe.com/email with a request ID from the failed request and as many other details at possible, and they'd be glad to help!

tdamant commented 5 years ago

@karla-stripe - yeah that was it, double checked all the api keys and it's working now. Thanks!

Crapulax commented 5 years ago

For others who might face this issue as I did too on mkt place (stripe connect).

When you were using Destination with charges you need to use Transfer. With Transfer you also need to set onbehalfof field. If not, you get the error message about payment method. Not that for further Tranfers you get back the charge id from transferIntent.charges.data field

oreporan commented 5 years ago

I'm facing the same issue using stripe connect with direct pay flow. Anyone have a solution?

remi-stripe commented 5 years ago

@oreporan you might want to read https://stripe.com/docs/payments/payment-methods/connect

Otherwise I'd recommend following up with our support team instead: https://support.stripe.com/contact

Crapulax commented 5 years ago

Hereby Stripe answer on the working workflow I implemented. The important stuff is this:

var params = &stripe.CustomerParams{
InvoiceSettings: &stripe.CustomerInvoiceSettingsParams{DefaultPaymentMethod:&payMethod.ID},
}

Stripe Answer: After reviewing your flow it does appear to be correct, yes. You are first creating a Setupintent as outlined here:

https://stripe.com/docs/payments/cards/saving-cards-without-payment And creating the Payment Method with that. If a customer exists already you would attach it using this call here: https://stripe.com/docs/api/payment_methods/attach Otherwise you would create a new customer with the Payment Method specified, here: https://stripe.com/docs/api/customers/create#create_customer-payment_method You can then update the customer to have their default payment under the default payment method in the invoice settings, here: https://stripe.com/docs/api/customers/create#create_customer-invoice_settings-default_payment_method Or you could specify the Payment Method when creating the subscription, here: https://stripe.com/docs/api/subscriptions/create#create_subscription-default_payment_method

Since you are creating a subscription from a Setupintent, you would want to also specify the off_session parameter so it doesn't attempt to request authentication having that been done on the Payment Method already:

https://stripe.com/docs/api/subscriptions/create#create_subscription-off_session

My working workflow:

oreporan commented 5 years ago

@remi-stripe I have read basically every documentation. on my backend the request looks like this:

const intent = await stripe.paymentIntents.create(
                {
                    amount: parseInt(amount),
                    currency,
                    confirmation_method: 'manual',
                    confirm: true,
                    metadata,
                    payment_method: id,
                    customer: customerId,
                },
                {
                    stripe_account: restaurantStripeAccountId,
                },
            );

the restaurantStripeAccountId is indeed a connected account. However, I saw in some other documentation that on the client I need to connect using the connected account as well? I saw this here It shows this:

// Set the connected Stripe Account on which the PaymentMethod should be created
var stripe = Stripe('my_key', {
  stripeAccount: "{{CONNECTED_STRIPE_ACCOUNT_ID}}"
});

stripe.createPaymentMethod('card', cardElement, {
  billing_details: {
    name: 'Jenny Rosen',
  },
}).then(function(result) {
  // Handle result.error or result.payment_method
});

Is this true? I don't have the connected account ID on the clientside. But I feel that this must be the reason its not working. As if I need to create the paymentMethod in the name of the connected account on the client and then create the intent with the same connected account on the server?

oreporan commented 5 years ago

I believe the issue lies here

It says -

// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
const stripe = require('stripe')('sk_xxxx');

stripe.paymentIntents.create({
  payment_method_types: ['card'],
  amount: 1000,
  currency: 'eur',
}, {
  stripe_account: '{{CONNECTED_STRIPE_ACCOUNT_ID}}',
}).then(function(paymentIntent) {
  // asynchronously called
});

This does not mention anything that needs to be done on the clientside. However doing this results in the error no such payment method: pm_xxx

The only workaround for this is to add the CONNECTED_STRIPE_ACCOUNT_ID on the clientside. However this is not logical, as the clientside should not need to be aware of the CONNECTED_STRIPE_ACCOUNT_ID at all

remi-stripe commented 5 years ago

@Taakn That is correct and that's what is mentioned on the documentation I linked. We're working on improving that documentation so hopefully it's easier to find in the future!

oreporan commented 5 years ago

@remi-stripe But wouldn't that be the same case in charges API as well? and my charges flow works fine without having to pass CONNECTED_STRIPE_ACCOUNT_ID in the client when I initialize Stripe

Sorry but I don't see how its possible. Stripe on the client is a singleton, it doesn't make sense that I need to tell it the ID of the connected stripe account.

In my flow you can pay on the same client to several different connected accounts, am I supposed to call

var stripe = Stripe('my_key', {
  stripeAccount: "{{CONNECTED_STRIPE_ACCOUNT_ID}}"
});

Before every operation I do with stripe ?

In the stripe.js API reference it seems that this stripeAccount option has always existed, but in my charges flow (before migration) its not needed... So there must be a serverside-only way of doing this

remi-stripe commented 5 years ago

@oreporan No because Tokens work on connected accounts. Sources and PaymentMethods don't.

I'm sorry but this really isn't a support channel. I'd recommend talking to our support team or to developers on IRC on Freenode in #stripe instead!

damayantinama commented 5 years ago

@karla-stripe

but I have used the same key but not working and customer and token API worked I checked on log section of the stripe account but subscribe not working.

remi-stripe commented 5 years ago

@damayantinama I would recommend talking to our support team instead: https://support.stripe.com/contact

razvangherghina commented 5 years ago

I don't understand why exactly, but reading this: https://stripe.com/docs/payments/payment-intents/use-cases#connected-accounts

and trying with the second option (on_behalf_of and transfer_data) instead of passing { stripe_account: '{{CONNECTED_ACCOUNT_ID}}' },

just works!

macmatrix commented 5 years ago

Hello, I am having the same exact issue as @oreporan and @remi-stripe and after talking to the Stripe support I was told I need to connect in the client. However they do not support flutter so they do not know how to achieve it in flutter

The only workaround for this is to add the CONNECTED_STRIPE_ACCOUNT_ID on the clientside. However this is not logical, as the clientside should not need to be aware of the CONNECTED_STRIPE_ACCOUNT_ID at all

So my question now is how can I achieve it? I am using flutter and the plugin stripe_payment (https://pub.dev/packages/stripe_payment) which is a port from tipsi-stripe for React Native ( https://github.com/tipsi/tipsi-stripe/tree/experimental-connect/website/docs-md )

remi-stripe commented 5 years ago

@macmatrix I'm not sure this issue is the right place to get help here. I don't think it's an issue or bug with the library. It seems to be a misunderstanding with the product and how to use the API.

I'd recommend going back to our support team and providing detailed code that you're using and example requests that are failing so that they can help clarify how to make this work

bviale commented 3 years ago

Another dumb error that I made, I hope it can save some people time. Using stripe.js, I was trying to handle authentication actions on a setup intent with handleCardAction(client_secret)instead of confirmCardSetup(client_secret), resulting in the same http error, as my setup intent ID didn't match any payment intent id. So if you don't want to loose a couple of hours just like me, ensure that you're working with the right entity on the right endpoint (payment intent ids look like pi_xxx and setup payment ids look like seti_xxx).

wesleyxiao commented 3 years ago

i was figure out , something wrong on backend should use paymentintent not charge and replace "source" with paymentmethod pm**

$charge = \Stripe\PaymentIntent::create(array(

"amount" => 1000,
"currency" => "usd",
// "application_fee" => $applicaiton_fee,
"payment_method" => ''//payment_method id  that create by front end,
"confirmation_method" => 'automatic',
"confirm" => true,
), array(
    'stripe_account' => '' //you connect account to take application fee
));