#devquestionuser4242_api

1 messages ยท Page 1 of 1 (latest)

patent glacierBOT
#

๐Ÿ‘‹ Welcome to your new thread!

โฒ๏ธ We'll be here soon! Typically we respond in a few minutes, but sometimes we might take a bit longer if the server is busy or if you have a particularly tricky question.

โฑ๏ธ We close idle threads, which makes them read-only. Once a thread is closed it won't be reopened, but you can always start a new thread if you have another question.

๐Ÿ”— This thread will always be available, even after it's closed. You can find it again using Discord's search, or you can save this link: https://discord.com/channels/841573134531821608/1274069673603764234

๐Ÿ“ Have more to share? Add more details, code, screenshots, videos, etc. below.

frozen wharf
modern oracle
#

Right, but in the objects listed as possible objects within the payment_method_data object, card is not a listed possible object. So where can I find documentation on what to put in that payment_method_data.card object?

frozen wharf
#

What information are you attempting to pass?

modern oracle
#

In legacy versions of Stripe's API, for non-Stripe.js integrations (i.e. entirely API-based), you would submit the card number/expiration/etc. to the /tokens endpoint using your pk_... and get back a token id, that you'd use to create a charge on the server-side (thus your server never sees the customer's card number). However, with the new PaymentIntent APIs, I don't know where to submit the actual card number/expiration/etc. on the client-side APIs. Stripe.js uses the /confirm endpoint to submit them, but I don't see documentation for those fields (the payment_method_data.card object).

frozen wharf
#

Are you passing raw PANs back to your server and that is what you are attempting to pass using the Payment Intent API?

#

Or are you tokenizing the card data on the client?

modern oracle
#

I'm following the documentation's recommendation to 1. Create a PaymentIntent on the server-side, 2. Take the PaymentIntent.client_secret that's returned and send it to the client-side, 3. Use that client_secret directly on the client-side to submit the /confirm endpoint with the card information. This is what Stripe.js does.

frozen wharf
#

What data are you passing?

#

PANs or a tokenized card?

modern oracle
#

PANs (from the client-side to the /confirm endpoint using the PaymentIntent's provided client_secret). It's my understanding that with PaymentIntents, cards no longer need to use the /token API, and should use the /confirm API instead.

frozen wharf
#

When using Stripe.js which handles the tokenization itself. Your approach would require a thorough PCI compliance review

modern oracle
#

I'm very confused, why would I require PCI compliance when I'm not sending PANs to the server?

frozen wharf
#

I thought you said you were not using Stripe.js?

The first line of Checkout.js is initiliazing Stripe.js

// This is your test publishable API key.
const stripe = Stripe("pk_test_51JticYIlCeH6bP8REulC9GlUO09hWuGsCljwJ3VNWhqqLmTTW0CedWXOoABWyXkplmqMtwfA4SiXkdeqCMvesIii00BCpJb9Vb");
patent glacierBOT
modern oracle
#

Correct, I'm saying I'm working to build a custom UI flow that does not use Stripe.js, but does use the same APIs that Stripe.js uses.

frozen wharf
#

Stripe.js includes more functionality than just making that API call. It does plenty of actions "under the hood" to ensure security. If you want to roll your own solution that would likely require a lot of validation on our part before we support it.

modern oracle
#

ok, so should I revert to using the legacy /token endpoint for tokenizing cards instead of the PaymentIntent API?

#

my situations prohibits using third party libraries (i.e. Stripe.js).

proven mist
#

Hi, stepping in and catching up

#

Can you share the exact steps of how you imagine to implement this integration? You shared a documentation that you said were following, however, that uses Stripe.js so I'm a bit confused.

modern oracle
#
  1. [server-side] POST /v1/payment_intents to get a client_secret
#
  1. [client-side] GET /v1/payment_intents/:id using the client_secret to retrieve the payment types available (one of which is card)
#
  1. Render the payment details fields needed (e.g. PAN, expiration, etc.) for the user to fill out.
#
  1. The user fills out the needed payment details fields.
#
  1. [client-side] POST /v1/payment_intents/:id/confirm with the payment_method_data object populated with the provided payment details from the user.
#
  1. [client-side] If the returned PaymentIntent.status == succeeded send a success to the server (the server-side also verifies the PaymentIntent succeeded)
#

From what I can tell, these are the same base APIs that Stripe.js uses, but I'm unable to find the documentation for the payment_method_data.card object that Stripe.js is using (rather than the legacy POST /token endpoint)

proven mist
#

Yeah, that is our legacy flow and with the new PaymentIntent, Stripe.js handles that piece.

modern oracle
#

So the PaymentIntent API can't be used without Stripe.js?

proven mist
#

That is correct

modern oracle
#

ok, thanks for the clarification

proven mist
#

Yeap, I also confirmed it with another engineer on my team. If you do not allow a thrip party library, then you would need to handle PCI compliance on your end

#

You would be handling the raw PAN in this case.

modern oracle
#

We are not handling raw PANs, since they are entirely handled on the client-side

proven mist
#

What does 'since they are entirely handled on the client-side' mean?

modern oracle
#

(steps 3-9 above)

proven mist
#

But that is not how it works, and the client_secret is something that the Stripe.js needs to render the payment page for instance.

#

Your customer would have to pass the card details to you so you can create a PaymentIntent if you're not using Stripe.js

#

For this reason, you would be handling rad PANs

#

as you need to pass that card details to Stripe when you create the PaymentIntent

modern oracle
#
intent = stripe.PaymentIntent.create(
    amount=calculate_order_amount(data['items']),
    currency='usd',
    # In the latest version of the API, specifying the `automatic_payment_methods` parameter is optional because Stripe enables its functionality by default.
    automatic_payment_methods={
        'enabled': True,
    },
)
return jsonify({
    'clientSecret': intent['client_secret']
})
proven mist
#

Yes, it can be created without a payment method. However, for the payment to occur, you would still need to pass payment method details.

modern oracle
#

?

#

Correct, that's what the client_secret is for (to push payment method details to the PaymentIntent from the client-side, so they don't have to pass through the server-side).

proven mist
#

That is for Stripe.js, the client secret is needed to render Elements so Stripe can collect the payment method details safely.

modern oracle
#

ok, nevermind, I was able to figure out another way (it's not clearly documented, but you can POST /v1/payment_methods using your publishable key (pk_test_...), so we can tokenize cards using PaymentMethods on the client-side and then include that in the PaymentIntent confirm:

curl -v -X POST \
    -u "$PUBKEY:" \
    -d "type=card" \
    -d "card[number]=4000000000003220" \
    -d "card[exp_month]=8" \
    -d "card[exp_year]=2026" \
    -d "card[cvc]=314" \
    "https://api.stripe.com/v1/payment_methods"

curl -v -X POST \
    -u "$APIKEY:" \
    -d "payment_method=$PAYMENT_METHOD_ID" \
    -d "return_url=http://localhost:8000/" \
    "https://api.stripe.com/v1/payment_intents/$PAYMENT_INTENT_ID/confirm"
#

So you don't actually need to use Stripe.js or client_secret to continue to support client-side payments without using the legacy /token API

#

thanks very much, but I found a workaround

proven mist
modern oracle
#

nope

proven mist
#

Ok, I'm glad the workaround is working!

modern oracle
#

are those endpoint available anywhere?

proven mist
modern oracle
#

but it does work

#

So I guess my request is to add the fact that you can use your publishable key in the API docs notes for that endpoint.

proven mist
modern oracle
#

That's the Stripe.js reference

proven mist
#

I would like to further understand what you're seeing here and test on my end.

modern oracle
#

sure, one moment

#

making a fetch()

proven mist
#

Thank you!

#

Are you just creating the payment method, stripe.paymentMethods.create() using the publishable key instead of the secret key?

patent glacierBOT
modern oracle
#

yes

#

oh interesting

#
STRIPE_PUBLISHABLE_KEY="pk_test_..."

# no Origin header (returns 200 with created PM obj)
curl -v -X POST \
    -u "$STRIPE_PUBLISHABLE_KEY:" \
    -d "type=card" \
    -d "card[number]=4000000000003220" \
    -d "card[exp_month]=8" \
    -d "card[exp_year]=2026" \
    -d "card[cvc]=314" \
    "https://api.stripe.com/v1/payment_methods"

# with Origin header (returns 401, saying "You did not provide an API key...")
curl -v -X POST \
    -u "$STRIPE_PUBLISHABLE_KEY:" \
    -H "Origin: http://localhost:8000" \
    -d "type=card" \
    -d "card[number]=4000000000003220" \
    -d "card[exp_month]=8" \
    -d "card[exp_year]=2026" \
    -d "card[cvc]=314" \
    "https://api.stripe.com/v1/payment_methods"
#

the presence of an origin header determines whether the publishable key can be used

dawn imp
#

Hello! I'm taking over and catching up...

#

It's very much not recommended to send raw PANs to the API like this using your own code. If you really want to do this you'll need to be fully PCI compliant and I recommend sending the PANs from your server, using your secret key.

#

You should absolutely not be trying to mimic what Stripe.js is doing, as what it's doing is subject to change at any time.

modern oracle
#

right, which is why I'm trying to use only the documented APIs

#

That's how the legacy POST /token works (and still works)

dawn imp
#

We don't document how to send raw PANs to Stripe because we don't recommend doing so.

#

Why don't you want to use Stripe.js?

modern oracle
#

my use case prohibits 3rd-party tracking and libraries, and Stripe.js sends tons of requests to your servers for analytics

dawn imp
modern oracle
#

"...and libraries", which means no third party code included

dawn imp
#

Alright, can you redirect to Stripe-hosted Checkout instead?

modern oracle
#

no... because that means the user is subject to third party code...

dawn imp
modern oracle
#

no, and we do not want to see or pass through PANs

#

we can always fall back to using the legacy token API

dawn imp
#

It doesn't matter if you see them or not. If you're writing code that touches raw PANs you need to be PCI compliant.

#

If you don't want to see/pass through/touch PANs at all you need to use Stripe.js.

#

You can't have it both ways.

#

Or you need to redirect to a Stripe-hosted surface like Checkout or the Invoice payment page.

modern oracle
#

Existing legacy integrations continue to use the POST /token endpoint just fine without the server ever seeing PANs.

dawn imp
#

And those integrations are legacy and not recommended for good reasons. They also still require a higher PCI compliance burden than using modern integrations with Stripe.js.

modern oracle
#

Will the token APIs be removed at any point, so that Stripe is only usable using Stripe.js?

#

We will need to plan our migration (and it will be a pretty big one, so we will need a fair bit of lead time)

dawn imp
#

It will probably be removed one day, but it will be far in the future, and we'll provide ample warning and lead time. It probably won't happen for a very long time.

modern oracle
#

ok, thanks

dawn imp
#

Again, not recommended to use it, especially to build new things with it, but it's not going anywhere anytime soon.

modern oracle
#

yeah, understood, we'll still start investigating alternatives, now that we know that PaymentIntents isn't available except via Stripe.js

#

thanks very much for the discussion