#devquestionuser4242_api
1 messages ยท Page 1 of 1 (latest)
๐ 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.
Hi ๐
payment_method_data.type is referenced here:
https://docs.stripe.com/api/payment_intents/confirm#confirm_payment_intent-payment_method_data-type
And it will definitely accept card as an enum value.
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?
What information are you attempting to pass?
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).
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?
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.
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.
When using Stripe.js which handles the tokenization itself. Your approach would require a thorough PCI compliance review
I'm very confused, why would I require PCI compliance when I'm not sending PANs to the server?
I am following the custom same flow as https://docs.stripe.com/payments/quickstart?lang=python#fetch-payment-intent
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");
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.
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.
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).
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.
Sure, I'm following the guidelines presented in https://docs.stripe.com/payments/paymentintents/lifecycle
- [server-side]
POST /v1/payment_intentsto get aclient_secret
- [server-side] pass the
client_secretto the [client-side] (same as in the example here: https://docs.stripe.com/payments/quickstart?lang=python#fetch-payment-intent)
- [client-side]
GET /v1/payment_intents/:idusing theclient_secretto retrieve the payment types available (one of which iscard)
- Render the payment details fields needed (e.g. PAN, expiration, etc.) for the user to fill out.
- The user fills out the needed payment details fields.
- [client-side]
POST /v1/payment_intents/:id/confirmwith thepayment_method_dataobject populated with the provided payment details from the user.
- [client-side] If the returned
PaymentIntent.status==succeededsend a success to the server (the server-side also verifies the PaymentIntent succeeded)
- [client-side] If the returned
PaymentIntent.status==requires_action, then handle whateverPaymentIntent.next_actionis (following the https://docs.stripe.com/payments/3d-secure/authentication-flow#manual-three-ds )
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)
Yeah, that is our legacy flow and with the new PaymentIntent, Stripe.js handles that piece.
So the PaymentIntent API can't be used without Stripe.js?
That is correct
ok, thanks for the clarification
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.
We are not handling raw PANs, since they are entirely handled on the client-side
What does 'since they are entirely handled on the client-side' mean?
(steps 3-9 above)
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
PaymentIntents can be created without card details (as demonstrated in your own server-side code on the example custom flow https://docs.stripe.com/payments/quickstart?lang=python#fetch-payment-intent )
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']
})
Yes, it can be created without a payment method. However, for the payment to occur, you would still need to pass payment method details.
?
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).
That is for Stripe.js, the client secret is needed to render Elements so Stripe can collect the payment method details safely.
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
And it appears that https://docs.stripe.com/payments/3d-secure/authentication-flow#manual-three-ds is working using this method (at least with the 3DS test cards), too
thanks very much, but I found a workaround
Are you referring to https://docs.stripe.com/payments/accept-a-payment-deferred?platform=web? If so, it still used Stripe.js.
If not, I'm glad you found a workaround.
nope
Ok, I'm glad the workaround is working!
It would be most helpful if y'all could document the APIs that can be authenticated using the publishable API key (https://docs.stripe.com/keys#obtain-api-keys)
are those endpoint available anywhere?
We do document what is attainable using the publishable key: https://docs.stripe.com/api/payment_intents/object. However, I'm unsure what you mean here, can you add more context?
Hmmm, being able to use publishable keys on POST /v1/payment_methods doesn't appear to be listed in the docs for that endpoint https://docs.stripe.com/api/payment_methods/create
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.
Are you referring to this, https://docs.stripe.com/js/payment_methods/create_payment_method?
That's the Stripe.js reference
Can you share the request if where you create this payment method? Here's how you can find a request ID: https://support.stripe.com/questions/finding-the-id-for-an-api-request
I would like to further understand what you're seeing here and test on my end.
Thank you!
Are you just creating the payment method, stripe.paymentMethods.create() using the publishable key instead of the secret key?
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
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.
right, which is why I'm trying to use only the documented APIs
That's how the legacy POST /token works (and still works)
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?
my use case prohibits 3rd-party tracking and libraries, and Stripe.js sends tons of requests to your servers for analytics
We use that telemetry for fraud prevention, but you can disable it if you want: https://docs.stripe.com/disputes/prevention/advanced-fraud-detection#disable-advanced-fraud-detection
"...and libraries", which means no third party code included
Alright, can you redirect to Stripe-hosted Checkout instead?
no... because that means the user is subject to third party code...
Okay, are you fully PCI compliant? It would be the "Direct API" one in the table here: https://docs.stripe.com/security/guide#validating-pci-compliance
no, and we do not want to see or pass through PANs
we can always fall back to using the legacy token API
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.
Existing legacy integrations continue to use the POST /token endpoint just fine without the server ever seeing PANs.
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.
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)
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.
ok, thanks
Again, not recommended to use it, especially to build new things with it, but it's not going anywhere anytime soon.