#_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/1303416618302443641
๐ Have more to share? Add more details, code, screenshots, videos, etc. below.
Below are links to other discussions we've had with you in the past week in case you want to review that information. If your question is related to one of these previous discussions, please provide a comprehensive summary of the current state and what you need help with now. We help many users simultaneously, so a summary allows us to resolve your issue as soon as possible.
- _unexpected, 6 days ago, 149 messages
- _api, 6 days ago, 42 messages
Hello! Sounds like you want to add some metadata to the Checkout Session when you create it: https://docs.stripe.com/api/checkout/sessions/create#create_checkout_session-metadata
Pretty much this, if the user is logged into our cart system, I want to send that user id so it comes in with the order. I did try adding meta data to a product but was not able to figure out how to retrieve it. it seemed to be only visible in the dashboard
the intent here, is if a customer has an account, with us, to attach the order to the account they are logged in with us on.
If you add metadata to the Checkout Session itself it should be included in the checkout.session.completed Event. Do you have an example Checkout Session ID I can take a look at where you tried to do this?
i haven't tried because I really don't know how to implement that part. I can paste what I am doing to build the cart as it is:
I can't provide code reviews or tell you what will happen if you run your code.
I have a loop on our cart to do this :
// create a line item for stripe checkout
formParams["line_items[#itemIndex#][price_data][currency]"] = "usd";
formParams["line_items[#itemIndex#][price_data][product_data][name]"] = "#pkProductID#: #productName#";
for(productPhoto in productPhotos) {
formParams["line_items[#itemIndex#][price_data][product_data][images][#photoIndex#]"] = productPhoto;
photoIndex++;
}
formParams["line_items[#itemIndex#][price_data][unit_amount]"] = amount;
formParams["line_items[#itemIndex#][quantity]"] = quantity;
The next step would be to try this in test mode and see what happens.
^ no code review required . showing what fields I am passing
Those are all line items, nothing to do with metadata there.
right, so metadata is that a root thing at the same level line_items[] are added to the session ?
and format is what ?
metadata[mykey]=value ?
Correct for both, yep.
so not
metadata[0][mykey]=value
It depends on the context/language you're using.
Probably not though.
It's recommended to use one of our official SDKs if possible.
Makes things a lot easier. ๐
can't use your sdk because nothing available for coldfusion
also, using a beta feature for shipping, so the java jar can't be used
curl equivalent requests. so raw form params as the stripe api expects them
really wish stripe let me post json, but, alas lol
testing quickly with a simple value. one moment.
Im trying to add these (think curl)
metadata[coupon]="discountCode"
metadata[gvuser]=0
and getting a problem
What's the problem?
since I have you here, maybe you can suggest a better way to handle this. I have some error handling that does some additional checks. for example, when the stripe js makes the call to create the session to our server side script, i will build all the stuff from the cart at that point and check to make sure it is allowed (country restrictions etc)
if not allowed, i return null for the session id. which causes the stripe js to bail eventually.
(intentional). i also do these checks before displaying the button to checkout with stripe.
the checks on the session, are for mitigation reasons only -- potential future problems with attempting to checkout for something they are not allowed to or whatever.
the question for this : is there a better json response i can give that is better than { session: null } like, can i give a reason or something ?
the reason i am asking, is because there are multiple points where this could fail, and having them all respond with { session: null } for any broken cart/etc issue, is a pita to troubleshoot -- which is what I am running into now
I need a bit more context. You said, "for example, when the stripe js makes the call to create the session to our server side script" but I'm not sure what that means. Usually your own code would fetch details from your server like that, not Stripe.js itself. Can you provide more details about that part of the flow? Also, are you using embedded Checkout or are you redirecting to hosted Checkout?
the stripe js, calls a script on our server via XHR, to get the stripe session id
in that script is where we build the cart, pass to stripe server to server, and return a response in json that the stripe js then uses for whatever other underlying magic
When you say "the stripe js" are you referring to Stripe-related JavaScript you wrote, or are you saying Stripe.js itself is doing this on its own?
Can you share the JavaScript in question so I can better understand what's happening?
to set up the session
ok
<html>
<head>
<script src="https://js.stripe.com/v3/"></script>
<script type="text/javascript">
var stripe = Stripe('pk_test_51PGS1b2MMD1HzYgM3aqEYSHM2J3FwPkQS4cQsa1577cFqGSRnWrYuUYS4d0MdsBoBX0MaxbjBJ4fKYXU9rfxXrpz00Jslhzp3I'); // Replace with your actual Stripe public key
async function fetchClientSecret() {
const response = await fetch("/stripe/session.cfm", { method: "POST" });
const { clientSecret } = await response.json();
return clientSecret;
}
async function onShippingDetailsChange(shippingDetailsChangeEvent) {
const { checkoutSessionId, shippingDetails } = shippingDetailsChangeEvent;
const response = await fetch("/stripe/shipping.cfm", {
method: "POST",
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ checkout_session_id: checkoutSessionId, shipping_details: shippingDetails }),
});
const responseData = await response.json();
return responseData.type === 'error' ? Promise.resolve({ type: "reject", errorMessage: responseData.message }) : Promise.resolve({ type: "accept" });
}
async function initialize() {
const checkout = await stripe.initEmbeddedCheckout({
fetchClientSecret,
onShippingDetailsChange
});
checkout.mount('#stripecheckout');
}
// wait for the page to fully load before initializing stripe
window.addEventListener('load', function() {
initialize();
});
</script>
</head>
<body>
<div id="stripecheckout"></div>
</body>
</html>
the embedded vs non-embedded, only minor differences, still had to pass an async method that fetches the session id from our server for a stripe checkout session
more in line with a php integration, than nodejs
Okay, gotcha. So that's all code you're expected to modify to suit your own needs and requirements. It's a starting point only. A common approach is to modify both the frontend and backend code to handle things like the scenario you describe by adding additional detail to the response from the server, and additional logic on the frontend to handle that additional information.
html/js client, coldfusion/cfml server
For example, your server could return JSON with far more properties and information. It could have an error property with an error code as a value. It could have an errorMessage with a user-facing error. You could then write JS to check for those and, if present, branch off and display the error instead of doing anything Stripe-related at all.
yes, the backend is where we build the stripe checkout session, pass to the stripe api, get back the response and pass that on as the output from /stripe/session.cfm which is a json response that the stripe js library digests
Oh, I see what you're saying.
what I am looking to do is probably something like this :
async function initialize() {
const checkout = await stripe.initEmbeddedCheckout({
fetchClientSecret,
onShippingDetailsChange
});
>>> check here and don't mount or display anything stripe related if check fails <<<<
>>> else
checkout.mount('#stripecheckout');
}
Honestly, no. I think what you really want to do is first ask your server to run your validation logic, determine if a Checkout Session should even be created, and respond with ๐ or ๐ . If it responds with ๐ you never even run stripe.initEmbeddedCheckout.
ugh... doesn't the stripe.init require a promise for the values ?
meaning, no real way to intercept and then pass it on.
stripe.initEmbeddedCheckout is designed to be called once you're sure you want to display Checkout on your page. If you're not sure yet, you shouldn't call it.
like ideally :
if(fetchClientSecret.id === <somebadvalue>) {
// die here, show pretty your cart is bad message
} else {
// do mount stuff
}
as for the meta stuff, it looks like stripe ate it at the base level.
yes, but not sure unless i get a valid session id
Right, what I'm saying is that you need to split that part up.
You need to first check to see if Checkout is going to happen or not, then separately after that (and only if Checkout is going to happen) initialize Checkout.
would love to, but i don't know how i can take the promise out , if the method requires a promise
Sorry, I think we might be talking past each other, I'm not saying you should remove a promise.
move ?
You said, "but i don't know how i can take the promise out" and I said. "I'm not saying you should remove a promise" in response.
i would like the check the validity of the response of that promise, and/or pass something in that promise response to stripe to say "hey, something went wrong"
You can't do that. That's what I'm trying to say; your approach will not work.
You're trying to use this incorrectly.
so what you are saying, is i should check the stuff twice --- because i will always check the data in the script the data is being manipulated for output somewhere
but you are saying, i should duplicate those checks somewhere else, on a separate XHR, make those requests to see if valid, and THEN --- respond
Before you call stripe.initEmbeddedCheckout you first need to determine if you even need to use Checkout or not. That means your first step is to check with your server and validate whatever you need to validate first. Then, if your server says everything is good to go, then you call stripe.initEmbeddedCheckout and then it will fetch the Checkout Session ID from your server. If Checkout isn't going to happen you shuold never call stripe.initEmbeddedCheckout.
what happens when stripe returns "null" -- which it has
that is where i got that idea from, passing a null value for stripe checkout id
checkout is intended to happen
but stuff goes wrong
stripe.initEmbeddedCheckout isn't expecting fetchClientSecret to get null or anything like that. If it does it will fail, as you've found.
It usually displays an error in the area where Checkout would normally be embedded.
maybe a user added something mid transaction on another tab, and we need to account for that at the moment the session is being requested from stripe
so what you are saying, is that initEmbeddedCheckout has no error handling
Not in the way you're describing, no.
so if something breaks between our server, stripe and the response back, then there is no way to account for that ?
to get the session id, we need to build the form data to hand off, and params, etc.
then call the stripe checkout api posting that data
An error will be displayed on the page if something goes wrong.
stripe checkout api response with either a session, or null for the session id
that is passed down the pipe through the promise (in this case fetchClientSecret).
in this process, stuff can go wrong
i have dealt with trapping and sending us debug notices/etc when it does, however the user experience really sucks when (for example) we get a null for checkout session
Yes, and you can either rely on the error displayed by Checkout or add additional logic to handle errors inside your fetchClientSecret function.
whether it be from stripe servers, or our end
what error ?
it's always the same, because the only bad response is "null"
Errors like getting back null instead of a client secret.
sorry, and if clientsecret is missing completely from the response (that happened)
i was sending the wrong init for checkout session to stripe api and got back a valid session id, but no clientsecret which is what was required for the beta shipping feature
The main issue is that you have an incorrect mental model for how stripe.initEmbeddedCheckout is designed. The idea is that you never call stripe.initEmbeddedCheckout unless you're certain you want to display Checkout. If something goes wrong with the fetch of the client secret that means something actually went wrong, like a network error, or an unexpected server error. You're trying to also shoehorn in validation into this process, but it's not designed for that.
You need to do your validation prior to this entire process.
and here, i am certain i want to display checkout
the problem is in the response from checkout api
i want to handle that when it breaks
No, you're not. You're not certain because your server not returning a client secret is an expected outcome.
yes, it is an expected outcome.
If your server not returning a client secret is an expected outcome then you shouldn't be calling stripe.initEmbeddedCheckout.
You should instead be doing other work/validation/whatever before that to get to the point where the only expected outcome is that your server will return a client secret.
just passing the data on and forward to the client from what we receive from stripe
Can network or other unexpected errors happen at that point? Sure. But the only expected outcome when you call stripe.initEmbeddedCheckout is that your server will return a client secret for a Checkout Session.
i did use that later to do other things, like some checks, as should be done when building the data to send to stripe -- pretty simple really
but things fail
yes
network errors/etc. i want to account for these
i suppose i could probably do a promise of a promise
You can account for those inside your fetchClientSecret function.
For example, you can display your own error message/instructions on your page if you don't get a client secret back.
get the response from one promise, check the data, then pass that promise response to another promise as a result of a promise method that can be passed to the stripe init
You could instruct your customer to reload the page, for example.
the fetchClientSecret() -- i have not tried, but typically, when something is inside something being called as a hook on a 3rd party library, there really is no ui/ux control at that point which doesn't get overridden by the final response from the promise
entirely dependent on how that library handles the promise
You're too focused on the Promise. This isn't about the Promise. Inside fetchClientSecret you can do whatever you want, you can write whatever code in there. You can make updates to your UI, you can make multiple fetch requests, you can write any logic. You are expected to return a client secret at the end, but beyond that you're free to do whatever you want.
For example, you can fetch from your server, then write code to check for any errors or unexpected stuff in the response, then update your UI to show an error, etc.
right, and that end response, is handled by the stripe library, and stripe library will display /alter the ui based on that
here is a better question
Yes. If it gets a client secret it will display Checkout. if it doesn't it won't. That's it.
You can pass whatever you want, but if you pass anything other than a valid client secret Checkout will display an error.
so it doesn't have to be a promise ?
Give it a try.
^ true
nope
Invalid initEmbeddedCheckout(options) parameter: fetchClientSecretValue is not an accepted parameter.
must be a promise
ya ๐
It has to be a Promise that resolves to a string, specifically. See here: https://docs.stripe.com/js/embedded_checkout/init
well, i will work a way around it. will do some hacky stuff i guess to get the response, then parse, then if it's good, set a value in a faux promise that returns that scoping nightmare value, as a parameter to the embedded checkout.
in the future, would be nice if maybe there were some options say
init( { promise, promise }, { options: { failPromise } } )
maybe it already exists. but from our conversation, i get the feeling it is just assumed it is working at that point.
which is fair, nothing "should" go wrong.... but.....
I don't believe there's something that exists today. You can file a feature request via
https://support.stripe.com/?contact=true
Find help and support for Stripe. Our support site provides answers on all types of situations, including account information, charges and refunds, and subscriptions information. Get your questions answered and find international support for Stripe.
true. in my case, the problem i first encountered and didn't realize, there was a connectivity issue that was periodically giving back "unauthorized" with http code 0, and/or corrupting response/data sent resulting in no session created
the user experience, was the pre-render loading images for the stripe embed, then eventually a non-specific error in the middle of the screen
it wasn't a stripe problem, but it was rough to nail down. my other concern is this -- a user can call the file stripe is requesting to generate the session
they can then use that session to alter their cart -- theoretically, which is why (even if you believe the code is perfect), taking that into account by checking at the final point (in addition to checks before), is a good idea. tbh, people that do this, i don't care if they get a crap message or bad user experience
Yup but if you'd like that level of granularity then you should look into using PaymentElement instead.
my concern here was if something else legitimate messed up
client requires :
- custom shipping
- 1 - click checkout
- coupon support using existing system
client doesn't want to collect address/etc except after checkout is completed.
i went down the paymentelement road, and it was nice, full control.
it's one of those "we want full control" but "we don't want to handle any of the data until after" situations lol.. making it work
I see
thank you guys for the help
again. really appreciate your responses here โค๏ธ