 OK, guess I need to speak up a bit more. We're going to wait a couple more minutes because there's still folks signing in. But if you want already, you can get started signing up. Well, not signing up, sorry. Connecting to the Wi-Fi. So down here, we have the LASAL.js Conf. The password is just lowercase altogether. JS Conf Asia. And then you can already check out. We have a little sort of boilerplate repo. You can have a look at. That's just at bit.ly-stripe.js-conf. So maybe just have a look at that to see that the internet and everything is working. Updates to the latest stable note version, things like that. And then we'll kick off in a couple minutes. Cheers. Is that my water? It's not mine. Oh, yeah, something else you can do is you can, if you don't know each other sitting on your group tables, you can just introduce yourselves to each other. Cool. We don't? We might even have chairs. Oh, we might? OK. I think let's kick off into the general conference. Oh, that's the recording mic. So we might have to be careful. Yeah, yeah, yeah. We've got some more chairs up here. Does everyone have a chair? There's some free space over here in the front. Don't worry, I'll try not to. No, spit. Cool. Oh, I haven't installed my updates. Great. Cool. Should we kick off? Change what? Oh, it's, well, it's not going to change. It's literally just one slide. But then it's going to change to the screen. But maybe I can do, like, introductions and stuff. Yeah. I'm on mirror mode, yes. Should I unplug, re-plug? Does anyone know what that is? Is that the metro? Oh, oh yes, National Day. When is that, Singapore? Any Singaporeans? Sorry? August 8. OK, cool. Should I try to unplug, re-plug, or? OK, I think it's 10 pass. We're going to kick off. Hello, everyone. Can you hear me in the back? Is that OK? Perfect. Yeah, as you can probably see, I'm not Paul. So it's a bit of wrong advertisement there on the door. But I actually live in Paul's home country. So I live in Amsterdam in the Netherlands. The team here imported me, so to speak, because we actually, all of our engineering team in the Singapore office is currently in Europe. So they are doing an offsite. It's a bit of bad timing. But I got lucky, so I got to come out here and work with you guys, which is really cool. So my name is Thor. It's actually Tostan, which means Thorstone. But no one can remember that. So Thor. Yeah, I'm an integration engineer and developer advocate at Stripe. I generally work with our users in northern Europe. Very different climate over there. It's a bit colder. But yeah, generally help them build more complex marketplace integration. So money goes in. Money goes out. Yeah, that's a marketplace. We have some other stripes here. So we have Paul, whom you've met at the talk earlier. We have Daniel and Chris. So they're going to be around to help you out if there are any issues, any questions. Yes, and Cheng Wei in the back, of course. Sorry. So if you have any questions, we're all wearing Stripe t-shirts, so you can just point at us or just race your hand. We're going to be running around. Wi-Fi, so we have the LaSalle.js Conf Wi-Fi down here. We're going to need that because we're going to need to communicate with the Stripe API. And then the password is jsconfasia, just lower case. And we have sort of a boilerplate repo that I'm just going to run you through in a second there, which you can access by going to bit.ly slash Stripe.js Conf. Cool. Did everyone have a good lunch? Are you a bit tired now? No, it's good. OK, so we can jump in. On the recording there, are you getting a signal? All good? Fantastic. Cool, so if you go to bit.ly Stripe.js Conf, you're going to get to this repo here. So we've set together to set up this boilerplate repo here. What we want to do is take you through a couple different integration approaches with Stripe. So we're going to kick off in the beginning with Stripe checkout. Actually, can I get a quick show of hands who here has integrated Stripe before? OK, some folks. If you've done so, have you integrated the new checkout already? No, OK, so we're going to look at a new version of checkout. And that is actually something we can implement. There's a client-only version with checkout where, for example, you can implement payments into a static site with Gatsby, for example. Yeah, that's actually something that we can do with the client-only checkout. So in that case, we don't need a server. But we're going to look also at the checkout session piece, which then needs a server. And from there, we're going to move on to a more customized checkout using drop-in UI components called Stripe Elements. Chris is going to take you through that. And then lastly, we want to look at the payment request API, as well as Apple Pay on the web and Google Pay using the payment request API. Cool. In terms of the repo here, you can see we have two different modes. So we have a vanilla.js mode. And we have a React mode. Now, if you're not very familiar with React, I think choose maybe the vanilla.js mode. Or if you have an existing project that you want to add payments to that you have on your machine locally or somewhere, you can do that, of course, as well. Otherwise, feel free to use the repository for React. If you're familiar with React, you can use the Stripe React Elements library that is linked also here in the docs. The React Stripe Elements. So if you're familiar with React, use the React mode. Lastly, we have some documentation here. We're going to jump into that. Before we do that, you can use this repo. If you're using this repo, you can simply clone it and run it locally. We have different NPM scripts set up to run the vanilla mode, as well as the React mode. We've implemented Ngrok. Anyone know what Ngrok is? Cool. Who doesn't know what Ngrok is? OK, everyone's sort of awake. So Ngrok actually allows us to have a tunnel from our local host to the web. And specifically, that is an easy way for us to test webhooks. If we have the server running locally on our machine. So we're actually going to look at webhooks in a bit. So these are HTTP requests with information from Stripe that are sent to your server. And using Ngrok, we can tunnel those requests to our local host. Alternatively, I've seen Glitch being used quite a lot here at JAS Conf, so that's something you can do as well. In Glitch, if you open a new project, you can simply paste in the URL. So here, if you go into HTTPS mode, you can paste in the URL and set up the project on Glitch with that. If you want to do that, then you don't have to use Ngrok because it's actually available on the internet. Maybe a quick question. Who does have a Unix-based OS? So something like Mac OS or Linux? Good amount. Anyone who has a Windows-based system? OK. You're probably used to everything being a bit more difficult, but that's OK. Alternatively, do feel free to use Glitch if the setup doesn't work. Cool. From that, let's actually jump into the docs. Let's open that in a new tab. So the new Stripe checkout, if you've known if you worked with Stripe checkout before, there was actually a modal pop-up on your site that was basically an iframe that's injected to securely submit the card details and the payment details to Stripe. We would then exchange these details to a token that can only be used with your secret key and then using that token, you can charge the details. Now, with the new Stripe checkout, it's actually even easier than that. So it's a Stripe-hosted checkout experience. And what you actually do is you redirect off to the Stripe checkout page using the Stripe JS Web SDK. So we can quickly look at how this works. So here, if you go into the checkout docs, you can click on Preview Checkout. We can see we go off to a Stripe-hosted checkout page. You can specify the product images that should be shown. If you have a card that has more items, you can have multiple items that are shown on that page. And you can customize that. Here, you can see Stripe Press. We have a little logo up there. So that is a very easy way to get started. And as I mentioned, it offers a client-only checkout version that allows us to actually use checkout without a server component. Now, what I can do is, oh yeah, send me an email if you want to. I can use here. This is running in test mode. I can use our test card details. If you look into the repo, we have a testing section where we also link to all the different test cards that you can use. Here, I'm just using the default test card 4242. Actually, fun fact, a while ago, we bought that specific bin space. So no one can actually issue a credit card with 4242. Just wanted to make sure that doesn't happen. Well, no one except us can do that. So we actually own the bin space. And we can now use this test card. And we made a successful payment. And then up on a successful payment, we get returned back to our success URL. And we can see here we've completed a successful purchase. Cool. Now, in order to do the client-only integration, so that's something that we want to do first. We actually do need a Stripe account. So if you don't have a Stripe test account yet, here in the Getting Started steps, you can just click on the link, open a new test account. I'm just going to, yeah. So actually, just follow along with me. Do that now. Open a quick test account. JSConf. Well, he's implementing that. I just wanted to let you know that this, Vermont's Inferning Charges or anything for you, it actually is just a complete test account. Don't click the Activate button up in the corner. And you won't have to put any sort of details or anything. This is just a lab, you can get started. And here we're seeing the fun effects of our security measures, because you're all signing up at the moment and you're all on the same network. We're thinking this is some fun cart caching going on here, testing. So does anyone else get that error message at the moment? No? Everyone got this Stripe account? Then I might just actually use the one I have. Yeah, so this is a fun thing, because we are probably all on the same IP address on the network. If anyone else runs into that, let me know. I'm just going to try again. Not a robot, trust me. There we are, fantastic. So what we want to select is solutions for developers. And then what we can do here, what can we do? We can get our test API keys, business information. So you don't need to activate the count. This is just a test account now running in test mode. What we can do now is we can quickly look into the settings, maybe look at the checkout settings here. And I think we actually need to enable the client integration. So if we want to use that, maybe quickly check that. Are you a popular key to generate checkout pages? Yes. We want that. Allow. So in test mode, we can provide any. We can call the redirect to-stripe checkout from any domain, like including local host. But in live mode, we actually need you to register the domain, because there's no server component for you to actually validate that the checkout session. Because we're creating the checkout session client site, we actually verify that it is created on the client from your domain. In live mode, don't worry about that in test mode. Cool. Yeah. If anyone has problems at any point, just raise your hand. We have some folks flying around who will live debug with you. OK. And then we create our first product. So because with the client-only integration, we don't have a server component, we actually need Stripe to be aware of what you're selling. As you probably know, we can't trust the front-end. We can't really trust any information that is coming from the front-end. Unfortunately, someone might have tempered with that, even just the person in the Dev Console and the developer tools might have changed the amount. So we actually need to tell Stripe, this is the product we want to sell. This is the amount. So we call that products and skews. So stock keeping unit. That's a skew. So let's quickly ask at a test product. I'm just going to select the one-time purchase theory. You can also create plans for subscriptions for recurring payments. But what I'm just going to do is you probably have seen all the issues of increment we have there in the back, which is a magazine that we publish about different engineering topics and scaling engineering organizations. We probably want Singapore Dollars here. Now I'm not going to upload an image, but I'm just going to say 10 Singapore Dollars. Create that. And now we can see here we have a product ID and we have a skew ID. Does everyone have their product and skew? Awesome. So SKU stands for stock keeping unit. So if you have a product, for example, JSConf t-shirt, and SKU is the actual version or the variant of that t-shirt. So for example, the size, the color, and the printing style. So those three combinations make up one unique SKU. Correct. Yeah, it's sort of a general inventory. If you're selling physical goods, it actually makes more sense. If you're selling digital goods, really isn't that important what the skew is necessarily. Cool. And now what we can actually do here is we can click use with checkout. And you can fill in your success URL and your cancel URL here, which is going to refer to, for example, local host URLs. But we're going to copy and paste that into our code. I just want to quickly walk you through what happens very briefly. So here we load the Stripe.js JavaScript library. We then have a button. The button actually has a role link, just in terms of screen readers, for example, to make sure we know that this is actually going to link us to a different page. We can specify an error message here. And then we can quickly look at the script. So we initialize the Stripe client library, the Stripe JavaScript library with our publishable key. So that is going to identify, OK, this is creating a checkout session for my Stripe account. And for example, it's going to validate the domain, the origin domain in live mode that you've registered. We then here have a click listener for our button. If you look into the boilerplate, we actually have a button in there that you can use. And then we're simply calling Stripe redirect to checkout. And we specify a list of SKUs. Here we have only our single SKU. We can specify the quantity. And then our success, our cancel URLs. And as you can see here, that is a promise. So the reason for the promises here, there is an API request happening to Stripe. And we're waiting for the results to come back. Now, what could the result be? Anyone have an idea here looking at this? Can you see that? Not at this point yet. So we're just at the point where we want to redirect off to the Stripe poster checkout page. And so the reason that is implemented as a promise is we need to validate that the SKU ID that was provided actually belongs to your account, that everything is valid. And if everything was valid, what we return is basically the checkout session with the redirect URL to the Stripe poster checkout. But if there is an error, we want to actually catch that error on our page and react to it. So if there's no error, what actually happens is we're going to redirect off to the Stripe checkout. But if there's an error, we can react to it. Cool. And I think this is the point where I'm going to let you go off to the races and implement that yourself. If you're very quick with the client-only checkout, it's mainly copy and paste here. And if you run into any issues, do just race your hand. But if you're quick, you can go back here to the checkout documentation, and you can look at the server integration piece where you can then actually, you don't need to register the products with Stripe anymore because you're doing all of that on your server. And then you can actually provide a list of line items, and you can have a look at that. Cool. Everyone happy to sort of race off and take some test money? Awesome. Yes, a question? Yeah, so here the, if we go here. Yeah, so stripe.redirect to checkout. That function actually returns a promise. So you can use async away. Oh, if the browser is too old. Is that what you mean? So the browser doesn't support promises. It's a good question. What happens in that case? Does anyone know? Yeah, so we just, we ship sort of a polyfill, I guess. Yeah, if you have more questions, just ask Paul. Brilliant. OK, cool. Then, yeah, I'll let you go off. Let's see what you're selling. And if you have questions, please raise your hands. Awesome. Happy hacking. You guys ready to learn a little bit about stripe elements? Thank you. So I want to talk a little bit about how you would embed a credit card form into your own website and build a checkout form. So now you've implemented, how's everyone doing on implementing checkout? Everyone's kind of got that working, feeling good about it. So now, if you wanted to build a checkout form into your website closer. All right, there we go. You can use Stripe Elements for that. And Stripe Elements allows your website to be PCI compliant because it's hosted on Stripe servers and it's actually embedded in an iframe. So what does this look like for code? If you go to the JS workshop repository, we have a link for Stripe JS in Elements as well as React Stripe Elements. And in here, you can see I'm going to try to live code a little bit of this and how it would work. So you can get an example of what this looks like and see that it will tokenize cards. This form is hosted all on Stripe. And when you submit the payment here on the site, then it gets you a successful token. And what you can do with that token is go to charge your users. And so basically, we just want to get Stripe Elements set up so that you can start collecting those tokens and charging your users. So to get started, Stripe Elements allows you to put in a div to your page and tag it with a card element ID. So using the vanilla workshop that we already have set up, you can copy and paste this form right into your website. And as a part of this, the form action chart goes to forward slash charge figure. Oh, that's really dim. It's definitely harder to see. Can everyone see that? The light background? I don't know how to do that in real time. Where do I go? You've got to code preferences, and then cut a theme. And just do the light to be used to do that. Nice. So much better. All right. So when you post this in, it's actually going to add a form to your site. So we can go look at the site. And notice that we now have a credit and debit card form and a submit payment button that goes to forward slash charge. So once you have that set up, you just need a little bit of CSS to give it some styling. So you can target that stripe element that we put in there. And using this page, you can get started. So you copy and paste this in to your style.css that we already have set up. And then let's go check what that looks like. So now maybe we have. All right. So that style is going to come in as soon as you embed the form from Stripe. So using a little JavaScript, this is kind of the key, the core component of implementing elements into your site. You're going to pass in styling into Stripe, because this is an iframe that's hosted on Stripe servers. And you need to tell Stripe what you want this to look like. What Stripe is going to give back to you and host in this iframe. And then as part of that, you're going to create a card element. If you want to take payments of other types, then you can go and look for these different payment types on the side here. After this, Paul is going to go over how to do payment request buttons, which gives you Apple Pay support. So taking this JavaScript and pasting it in to our index.js and commenting out. Also, I'm using the vanilla.js just for this quick code demo, only just because it's easier to get everything started. So hopefully, if I've done everything right, you'll now get an iframe that's actually loading from Stripe's servers. And you can put in a card and fill it out and get a token. So once I submit this, it's going to submit it to forward slash charge. And that's actually going to pass you back a token that you can use to charge users. So if you look at the code that was generated on the documentation page, you'll see that when the submit happens, when the user hits the submit button, there is an event listener. And that actually calls Stripe.createToken. And from that, we can print out the results so everyone can see. Actually, that will refresh. So here, this code right here is where you can get that token to be able to handle the payment. And if you want to change where the users get sent when they actually hit that submit button, you can change this form action right here. So that's how to get started on getting Stripe elements onto your page. And I didn't do any sort of styling or customization, but now you can kind of play around with embedding a form and accept payments into your site directly. So that's Stripe elements and getting started. So I'm going to give you guys some time to implement that and change the look and feel on this. And just let us know if you have any questions at all. Actually, any questions that you'd like me to answer? Yeah? Recently, when you submit the payment, it goes through this last chart, OK? I mean, is that the expected to be here or for the browser? So the user, are they supposed to see the last chart? Yeah, so the same as, sorry, the question was, is it supposed to redirect to forward slash charge? Is that the expected behavior? You can think of that URL as the same as the success URL for new checkout. So the same, you could change that the same way that you did the success for part of the checkout. Any other questions? Awesome. Does this work? Cool. So the whole reason behind Stripe elements is to give you PCI compliance by injecting an iframe. So only the input field that the card details are typed into, only that piece is an iframe. And everything else in your form, you can completely customize. And even the Stripe element, you can provide a style object to actually style the input field that is hosted by Stripe. And PCI compliance means we want to make sure that there is no card details ever exposed on our server. Because if we store card details or if we even just have the card details hit our server, there are certain requirements with that for handling card details. So let's use the iframe. And what actually happens in the background, the card details are securely sent to Stripe. Using your publishable key, we then encrypt the card details and exchange them for a token. And that token can only be used with your Stripe account. Now, has anyone here heard of 3D secure? Yes, fun. So actually in Europe, there is a new regulation coming into effect in September, which is called strong customer authentication. And strong customer authentication will demand that any payments between European merchants and European card holders are strongly authenticated. And one mechanism for that will be 3D secure. Now, even though that only affects merchants in Europe, looking out into 2020, Singapore and Australia, Brazil and other countries around the world are looking at that as well as a way to tackle online fraud. And so what we've done at Stripe is we've built 3D secure authentication into our client SDKs to help you to handle that dynamically. And we call it dynamic authentication. So the way this works is, first on our server, we create a payment intent. And you can think of the payment intent as an object to basically track our customer's intent to purchase something. So we create the payment intent by simply specifying the amount and the currency that we want to collect. So this is something that we need to do once we know, OK, we want to collect 10 Singapore dollars from our customer. We want to create the payment intent. And then the payment intent itself has a client secret. And so the client secret we need to send down to our front end. And then we can use Stripe.js and the elements that we just used to call handle cart payment. Do you have that in your client, client.js? So using the payment intent client secret, so the payment intent we create on our server. And then we share the client secret with our front end. And then we can simply call Stripe.handleCartPayment. So that's part of Stripe.js. And we pass in the client secret. And cart here is the reference to our Stripe.card element. So what you just set up, that's where the cart details are. And then what we do here with Stripe.js, we attach the cart details to our payment intent. And at that point, we actually evaluate, we run our real-time machine learning-based risk fraud score detection. And depending on rules, you can actually, in the Stripe dashboard, you can write rules when 3D secure should be triggered. So by default, we evaluate the regulation rules. So for example, in September in Europe, we will identify, OK, this is a European cart. It requires to be strongly authenticated. So let's bring up 3D secure. And you can see here in test mode, we render a test 3D secure page where you can then authorize or fail the authentication step. And depending on that, we then resolve the promise. So Stripe.handleCartPayment is a function, again, that returns a promise, bless you, which then resolves with either a successful payment intent status or a failed status, depending on whether it was successful. Yes. And so to test this, actually, you can use a test card that requires 3D secure authentication. We've linked that for you in the repo as well. But so going back, yeah, so here, the payment intent stocks. So if you pull those up, so what we need to do first now is, when our customer gets to our checkout page, we need to create a payment intent. So either we send an HX request to our back end to create a payment intent. Or if you render your page on the server, you can just create that before you actually render out anything. Once you've got the payment intent created, you need to then call Stripe.js HandleCartPayment with the client secret of your payment intent and the reference to your Stripe element. And that will then dynamically handle authentication. OK. Everyone fully confused now? Good. Now, any questions about the payment intent? Yes. After the user has finished the authentication process. Correct. So the question is, does the promise only resolve when the customer has authenticated the payment? So yes, in the case that authentication is required, the promise will only resolve when either the customer has successfully authenticated or they've canceled the authentication step, for example. What if they just pause? Any further action then only like this? Yeah, what if they just pause? In that case, it does time out depending on your bank. So what is actually shown is the issuer page from the bank. And depending on that, it can time out. That is correct. And in that case, if it times out, the promise resolves with an error. Yeah. OK. So the first thing we need to do now is on our server, create a payment intent. And from the repository, you can click in the documentation section on payment intent and then follow the steps there. OK. Cool. Yay, authentication. And again, if you have any questions, please ask us. Awesome. Thanks. This does it in a very nice way. So I do realize that was maybe a bit fast. So let me actually run through this. And if you know what you're doing, feel free to just ignore me and run along. But yeah, let me actually kind of run through this. So if we use payment intents, the first thing we need to do, and let's go into the quick start here, and let's not use .NET. So we need to create our payment intent. So what we actually do is on our server, that's not the server. This is the server. Here. Let me see if I can maybe make that a bit smaller. Cool. Yeah? Oh, OK. So you've got a code, preferences, settings. So code, preferences, and there is color theme. You just pick the light vision to do it. Lights? Yes. We'll get what you see there. OK, cool. Make it a bit bigger. Even bigger? How am I supposed to code then? OK, so what we need is a new route on our back end. And we actually, so I'm going to use an HX request to create my payment intent from the front end. So I'm going to do a post request here. I'm going to call it payment intent. And then what we actually want to do is create our payment intent. Actually, do I have Stripe set up? Yeah, so I have my require Stripe up here. If you haven't in the .NET file add your Stripe secret key. So there's a .NET file in here. Don't share that with anyone. So not like I'm doing right now. And make sure to set your secret key from the Stripe dashboard. So you have that in there. Cool, so we have that. And actually, we can just, so the thing is we need to make sure it's an async function. So I'm going to use async await. So make sure here our function that's executed when the post request hits is asynchronous. And then we can simply say that we want to create the payment intent. So payment intent create. And I'm just going to say we want 10. So we need to specify it in the smallest unit of the currency. So with Singapore dollars, is it sense? Do you call it sense, I guess? So 10 hundred cents. So 10 Singapore dollars here. And then actually what we want to return is, let's use camel case here. The payment intent, yeah. I can just use that. Cool, await, sounds good. Give that a save. So now on in the front end, let's use vanilla JS. So we have here our async main function. And now we need to, here we have a get config. And let's just here, after we loaded the Stripe library, let's just fetch, basically create payment intent. And I never, I can't ever remember fetch post, the post example. Do we need that much stuff? So we need method post. We don't really take. So generally, when you do this, you have a cart on your front end. And the cart probably has a list of skew IDs or item IDs that are in the cart. And then generally, you would post that cart to your back end. On your back end, you would then check in the database based on the items that are in the cart. This is the amount that I need to charge. We just hard coded the amount at the moment. So we're not going to actually send anything. So I think the only thing I need to do is say that we want to post. So let me just quickly take this piece and fetch URL and then the options OK. So here, we called our route payment intent. And then we say, we want method. That's a string. Can it be lowercase? Doesn't matter. Maybe do the uppercase, give that save. And what we're actually doing here, the fetch method returns a promise. And then on that promise, we basically turn the result into chase on. And then we want to store the chase on into, say, payment intent equals await. And then maybe for now, actually just log out that payment intent. And what I like to do is just log it out as an object. Then we can interact with it nicely in the console. Now let's actually start this up. NPM run, vanilla. Cool. You see first we're fetching the config. Then we're posting here to our payment intent. Can you actually see that? Do I need to make that bigger? But if we go into the preview here, we can now see payment intent object that we've created. And here we can see we have a client secret. And the neat thing here is actually, by exposing the client secret to our client, we can now use our publishable key to create a payment. And we can actually sort of hand everything off to Stripe.js, including the handling of the authentication requirements by just handing over the client secret to the payment. The client secret to Stripe.js. And we need our element as well. OK. So does everyone have a way to create their payment intent yet, or should I give you some time before we continue? What do you think? Who's got their payment intent created at this point? OK. I'll give you some time to implement that. OK. I've quickly added the element to my page as well. And so now I'm going to quickly run through bringing our payment intent together with the card details using the card element. So you can see here, I've got my element in the page. We got it here within the card element. So that's our reference to our card element, which then entails the card details. So now here in payment intent, what we do is when our button is clicked, the Submit Payment button, we then call the Handle card payment, as I mentioned, with the client secret. And we can submit additional billing details here, for example, the cardholder name. So let me copy that, make that smaller. So actually my client secret here, I don't have it on the card button. But as you've seen here, I have it on the payment intent that I've fetched via my Ajax Pulse request. So I can say payment intent.client secret. So that's my client secret. If you remember here, you can see in the Network tab. So that's my payment intent object. And so payment intent. So use the client secret. And then my card element is this. And so because I've already used the payment intent name, let me actually do the following. Let's not destructure it here, but let's just call it Result. And then what we're going to do is we're going to await this. So we're going to wait for the promise to resolve. And then we're just going to console log the result. Oh, yeah. And I didn't actually add anything to collect the cardholder name. I'm just going to put in Thor here. Thor is buying everything. Cool. And that should be it. So if I go back to my page, so up on load, I get my config. I create my payment intent. I set up my element. And now I'm going to use the test card details that require 3D secure authentication. And when I click pre-order, I get an error. Yes, card button is not defined. Let's see. That's what you get from copying things. Oh, wait. I already have my pre-order button. So I don't actually need this, do I? I just need, where is it? So that event listener is, I already have my event listener here. The only thing I need to make sure now, because I'm using await for the handle card payment promise, I need to make this an async function. I'm not actually using the event, so cool. Let's try that again. Here we are. Requires authentication. Submit. Well, you should be client secret string. So what am I submitting? Probably not a string. Anyone see what I'm doing wrong now? I mean, this should be globally scoped to my client secret. Should I spell it correctly? OK, three times the charm. If I still get an error, I probably do you see what I'm doing wrong? OK, let's try this. It is undefined. Fantastic. Oh, wait. Am I clicking too quick? No, I mean, we've got the payment here. See. You mean on the fetch? Yeah, so we're going to sort of change. No, so the payment intent here is fine. I think the problem is when we set up the button, I think we've got something funky going on. Yeah, so this is in. I mean, it's just the thing is the chain should be fine. How are you returning on the survey? I'm not sure here. Is the payment intent on payment? Oh, it is. Yeah, so should I modify the server? Oh, yeah, so that is my fault here. I'm actually returning an object on my server. I'm returning an object that then entails the object. So I might actually just do this. So now we should actually have the right objects. Did that restart? Let's see. OK, yeah, now. So now we've got the client secret. We're evaluating the cart details. We recognize that we need to perform authentication. So we're going to approve this. And then the error is not defined. That is great because I changed the result. So we actually here need to say so result.error. But we can already see, I think, a console locked. I console locked the result here. So when the promise resolves, we actually get back our payment intent. And we can now see we have an updated status here that's succeeded. So if we go into the dashboard and we go into payments, now I need to give this a refresh. OK, oh. I'm using a different account. I just realized, what's your account am I using? So in the dashboard, you would then see a payment once you're using the right account. So actually, let me quickly do the following. Just going to update my API keys in the .end file. The thing is, if you update your API keys in the .end file, you actually need to restart the server manually. So here in the .end file. And you should never show anyone your .end file. Just calling that out here. Cool. So now let's restart. Pre-order. Call 3D secure authentication. Europe is happy. Oh yeah, we actually didn't implement any success message. But now if we go back to our dashboard, we can see the successful payment we made for our customer Thor. Yeah, maybe should we do 10 more minutes for you to glue things together. And then I'm going to hand over to Paul to give you a quick look at the payment request API and using Apple Pay in the browser. And then we're going to wrap things up at some point. Cool. Thanks. Yes. OK, I think we lost a couple of people there. That's a bummer because we sort of kept the coolest thing for the end. Have you heard of the payment request API? Who has heard of the payment request API? Cool. So I think everyone has heard of the W3C, the World Wide Web Consortium. So the governing body of kind of the web standards. And the payment request API is something as part of the web payments working group. So there's the payment request API and the payments handler API. And what it aims at is to provide a native browser interface to collect payment details. So instead of everyone having to build their own checkout page, the idea is that the browser can natively render a UI that is a native UI to collect payment details. And so if we here look at, we can actually go into the payment request button. So at Stripe, we're actually part of the W3C web payments working group, which is working on this standard to build a native browser payment detailed collection APIs. And we've wrapped the payment request API into an element that you can use to trigger that UI and securely collect those cart details. So for example, here on Chrome, we can get a Pay Now button that will actually trigger the payment request API. Maybe let me zoom in there a little so you can see that. And here, the payment request API bundles various different payment methods or payment vehicles into the native browser UI. And so for example, here via the payment request API, I can access Google Pay. And Google Pay uses what is called the Payments Handler API to provide via a service worker the Google payment method in this native browser field. So this is actually not a pop-up. This is a native Chrome UI. So here, if we select Google Pay and we click on Pay, this actually uses the Payment Handler API. So Google uses the Payment Handler API to show me the Google Pay interface natively within the browser. And then I can just select my stored payment method here. And I can pay with that. And the details, so now the cart details that I've stored in my Google account are securely shared with Stripe so that the merchant can actually access those details and use them for payment. Now the cool thing is, if we actually open this in the Safari browser, we now get an Apple Pay button. Now the reason for that is that Apple does implement the payment request API. Apple is part of the web payments working group as well, but they only allow access to Apple Pay as a payment method. So that's why we only get Apple Pay here as a button. But we can use Apple Pay and I can then actually access, and unfortunately only on Safari, I can access the cart details that are stored in my Apple account. It couldn't connect to my phone there, but I don't have the fingerprint. If I had the new Mac with the fingerprint sensor, I could actually approve it on the laptop. Otherwise here it tries to hand off to my phone. So with the payment request button, we can actually access native wallets and sort of native payment interfaces. Here, for example, instead of Google Pay, so on Chrome we actually have the center, we can also access cart details that are saved on my Chrome. So for example, these are saved with Autofill, my cart details, and I can access those as well or using Google Pay. So that's really nice because on mobile phones, especially if you build a mobile website, it's very convenient to pay with Google Pay or Apple Pay. And it's cool that the payment request API is part of the whole progressive web app idea. So it's great that we can build experiences that actually allow us to access native functionality and payment details that are stored natively on the device. So if you wanted to put this into your application now, we can actually go, where is it? So here there is a toggle to implement the payment request API with payment intents. So we actually have a callback listener here when we access the payment details on the phone. They are shared directly with Stripe. Stripe then exchanged it for a token. And once we have the token, we fire this callback handler to tell you that we've got a payment method token that you can use. And then what you do is you basically confirm the payment intent that you created, so the payment intent client secret here again, with the payment method that was shared via the payment request API. And then we can react to the results. So either it is successful or we might actually have to handle authentication. So if this uses Apple Pay as a payment method in the background, authentication is actually handled via the fingerprint sensor within the phone. But if we, for example, via the payment request API, if we use just stored card details that are stored on the Chrome browser, then potentially we might need to additionally perform authentication. And that's what we do here with handle card payment. Looking at the time, I don't think we have enough time to actually hook that into the application. If you want to do that, feel free to run here through the payment request quick start. You can see it uses, it's very similar to using elements with the card element. But instead what you do, you actually create the payment request with the details. So here you need to provide the payment details that should be shown on Apple Pay, on Google Pay. So that's why you put them in here as a JSON object. And then we create a payment request button element here with our payment request object. And we then can check why are the browser, so why are the payment request API, we can check if we can make a payment, so if any of the native methods, so Apple Pay, Google Pay, the payment request API with stored card details, or even Microsoft Pay is apparently a thing. We can check if any of those methods are available. And then if they are available, basically, we mount the payment request button into our form. Cool. So that's how we can actually get access to Apple Pay on the web via the payment request API, the payment request button. Any questions on that? Yes? With, you mean with the hosted checkout? Sorry, can you repeat that? So the question is, if I use the payment request API within a React Native application, does it show the native Apple Pay behavior? I think the answer is, yes, Shang Wei, do you? Yes? Yes? OK. Yeah, so if you want to feel free to stick around, I think the talks continue again at 4.30. But if you want to continue, we're going to stick around to answer questions. Thank you very much for joining us for this workshop. We have some t-shirts in the back as well as some issues of increment. Feel free to take one there. And yeah, thank you for joining us. And if you have any questions in general about Stripe or Stripe in APAC in Singapore, feel free to ask us. Thanks a lot. And enjoy the rest of JSConf.