 It's the end of the day, so everyone's like chatty and ready for beer. Yeah, so we'll be starting in about a minute here. It's mic, so it doesn't matter. All right, well, I guess we can probably begin, and then people can come in as we get started. So my name is Ryan Wheel. I am based in Montreal, and I've traveled, I guess, from Canada, and here I am at Drupal Con, so welcome. Today I'm talking about my session rather as called Shut Up and Take My Money, Using Stripe Checkout in Drupal 8. And this is how we built a simple module for Drupal 8, but also an easy solution for getting payments into Drupal and managing that process. We'll talk a bit about how you could potentially do this with other payment gateways and things of that nature. So first, what is Stripe Checkout? It's a payment gateway, but the checkout aspect of that is specifically for using embed codes to do this, and there's a reason that we want to do this, which we will see in the next slide. Just a quick visual of what this looks like is we have here just a credit card input form, and you see that it pops up over top of our Drupal 8 site. You also see that it has the currency code in this case, which is Canadian dollars, which is where I live, so we're building this for our own website because we want to charge people money, obviously, and we don't need a shopping cart, so we're going to look at these reasons. So Stripe is a nice gateway because it has multiple currency support. They support European money, US dollars, Canadian dollars, BTC as well, bitcoins. It is very easy for PCI compliance necessity, and this is something that has recently become more of an issue than in the past, which we'll talk about on the next slide. The benefit of doing this method is our site never sees the credit card details at all, so that's handy. The pricing, this is, of course, subject to change. I'm not affiliated with Stripe, so I just grabbed this because in the past people have asked me about this, but typically it's 2.9%, and then a small fee for per transaction stuff. And then Pay Now buttons are in fashion again, and the reason for that, drumroll please, is PCI compliance has been changed. So for those not familiar, PCI compliance is where the credit card industry, credit card payment card industry is what PCI stands for, is a consortium of the banks that process transactions, and they have standards that we are supposed to be meeting, so if you're ever collecting money on a site, you are subject to this. Now, what that implies is that you do a quarterly scan on your site to ensure that there's no security issues with your site, and then they have you answer a survey. So there's quarterly scan and a survey. Now, the survey has been updated, and so for circumstances where you're taking the credit card number into PHP and actually touching the credit card number, you have to go through a very detailed survey of like 350 plus questions, and in the case of web companies, a lot of what the questions asked doesn't necessarily apply to you, so most of your responses to those questions will be, like, do you have video cameras in this particular context, and they'll say no, and they'll say why, and then you have to say, well, we don't have on-site things, and things of this nature, so they've made special categories to deal with web agencies, and this is great, but we, of course, want to minimize the scope of this for smaller sites. Additionally, there is some changes in terms of the liability. It gets pushed down to the merchant now, so that's something that's somewhat new, and you must also document who is responsible for compliance, so that means, like, you need a paper trail to say, like, the client is responsible, or I am responsible as an agency. There's this great white paper that I've got in this URL posted here on the slide. It's produced by three Drupal developers who are mentioned at the end of the presentation. It's a really wonderful document. It explains everything. You can go through that and find out which category best fits your situation and then what the compliance needs are for that, so that's worth looking at. It's good to keep in mind that in the world of, like, Drupal 6 and Drupal 7, a lot of the times we were taking the credit card numbers and processing them ourselves, which actually puts you into one of the highest categories of, like, documentation needed, and that implies that you have network maps of where everything is located, as well as, like, your security procedures, as well as, like, your employees all having to have acknowledged that these things are all documented and everything. It's quite complex, so it's really worth taking a look at this. So in order to simplify this, what we've done is we've said, let's just use an HTML embed code and let's let Stripe manage all of that themselves. Now this isn't really specific to Stripe because most payment gateways do offer some form of solution like this. The benefit with Stripe in this case is that their interface is kind of pretty, so it's nice in that sense. It's also nice in the sense that most of their API documentation is written for developers specifically and provides wonderful examples. So we'll take a look at a couple of those things. And this way we can do, like, a simple implementation and we don't have to worry about it. So we're going to need a field that we can accept, we can put a number in and then that will render as a payment button. So this is what the payment button looks like. It says pay with card. You can override this, so that's a possibility. If we went into the documentation on Stripe's website, they actually do this wonderful thing where they inject all of your personalized settings into it. So here you can see the test code and it gives you some pre-filled values. So in this case my currency code is in there, which is Canadian dollars again, and then the data amount you see is 2,000. This is actually an integer because of course floats are really kind of unwieldy when we're dealing with money because we're dealing with fixed units and if the sense change because it's a float that can be quite dangerous. All of these things, most of them are static. We don't often change the name of our company. We don't want to change the icon very often. We don't really need to change anything, but maybe sometimes we might want to change the currency code because in Canada we often do a lot of business with the US. So that was one of the needs that we looked at when we were wanting to implement this. But of course the main thing that's changing time after time is going to be the amount. In my mind we thought about what are our storage needs, how much can we reduce this to a single item that changes and really the main thing that changes is the dollar value or rather the sense. So with that we thought we could just use an integer field and then that manages all of the storage for us and we don't have to go and create this monolithic module. We can use an integer field and that might be able to take care of this. It's a little side track diversion here. There is of course commerce that's being developed for Drupal 8 and it's a I believe it's like a major rewrite so there's some fantastic stuff happening in there. But what we found in circumstances where we just want to bill somebody is that we're often like undoing the things that are implicit defaults in a shopping cart situation so for example if you were wanting to bill someone in a cart based solution you would have to pre-fill the cart and then you would have to make sure they don't change what's in the cart and then you have to push them through the purchase process. So it's a little convoluted and it's a lot of detail and it's a lot of undoing assumptions so that's kind of like overkill so we decided on using nodes and again this is just mostly as an example but we are planning to use this in our site so the reasons we use nodes, nodes have always been well supported in Drupal going I started doing Drupal in Drupal 5 and everything was nodes back then, nodes are still good now. We can allow and deny access using a hook which is handy so we don't have to worry about creating custom entities so again like we have basically no storage yet defined at this point so we don't have to worry about even dealing with the database at all. If you're doing a migration you can migrate into nodes very easily because all of that stuff exists. You can also do custom entities but this was our, we have a minimum need so we're going to do the minimum first because we want a viable product and then of course we can support other entities with like trivial changes later on so nodes can do anything it's what we know in Drupal so now with that in mind let's like start to drill down our requirements here we want to feel that renders a payment button so it's going to pop up that interface now once that happens we have to know a little bit about how Stripe works and this would be quite similar to how the other gateways work with their iframe based solutions essentially what we're doing is we're taking the user somewhere else and saying can you go put your credit card over there and then that gateway comes back to us with the token so all we're dealing with is the token when they go and do that step nothing actually happens except that their credit card becomes a token reference at the gateway so at that point nothing's happened and then we come back with this token in our Drupal site and we can then make the actual charge using the token and we can see the result and deal with it there so now there's a couple limitations that we had to work around which is like okay well how do we mark something as paid and we realize that one simple solution is that if we approach it as though this field is actually a balanced due that if the balanced due is zero that means that it's paid so that's one little hack that we did so that we don't again have to create a storage interface for dealing with database things so really this is all just like a field formatter and then we actually use make use of the revision history of the node in order to change that value when it comes in and then we log stuff into the revision history so again like no storage requirement really really simplified and then important note that we because Stripe actually and all the gateways do this they kind of make use of you can use them as a back office so you can have your address information and sort with them you can do all of that stuff on their side and then you can access it using the API so we don't need to collect addresses we don't have to worry about like transaction logs and all that because that's all at Stripe and you can just export it so again we're simplifying things down to just like okay we really just need to render a button and then when it comes back we need to take the token and charge it so now that we've got that in mind we've got to like learn how to do Drupal 8 so the steps that we went through to figure out like how we can do this was to look at the core implementation you can use Grap to like look for things in the code base as well as like review the tests we looked at change records when we found that functions that we were used to using were no longer in existence the examples module handles a lot of things like how to create config forms things of that nature and then the really big surprise was that we realized this kind of the concept already exists and that's in the YouTube module and that uses a field formatter to render a link field with a YouTube embed code so again it's like really similar it's like we've got a core field and we're using an embed code and we're just like rendering it differently so that's to minimize our needs so now we've got it narrowed down to a really simple list we've got to make a settings page so we can put our API keys there we need to have a field formatter so we can render that HTML embed code and then we need to have a hook theme implemented to actually put that embed code on the screen then when the token comes back from Stripe what we've got to do is go to the HTTP library that Stripe provides again they've like been wonderful in like just creating this whole package that in this case you can just go composer install in the directory and that will fetch the library but you can also just like download it and put it there and then we're going to use the example code that Stripe provides in the documentation so now we've just got six steps so this is great let's take a look at how to if you've ever created forms in Drupal 6 or 7 I think going way back even further than that forms are simply arrays and they're easy to implement there's been a change to where the forms are located you can put those in the source form directory there's a form base that you can extend because we're now containing that in an object and form state so this is like the reply that comes back the form when you click submit is now an object as well so this is all pretty familiar but there's some slight details that have changed and of course there's also like how do we register the path to this page so if we look at this page here we've got a path defined at the top sorry it's quite small on this resolution but so we've got a path to a configuration page and then that points to a particular form that we've defined in the system and we're addressing the form using the namespace that was defined so this is sort of stuff that's coming to Drupal from the symphony world and we're just making use of it here there's also a preview in this one of another URL this is going to this also defines our callback URL that we're going to see later on in the presentation so you can see that that's defined there and later on when we talk about it we've already defined both paths that are necessary for this interaction to occur so this is just a snapshot of the code I'm not going to go into a lot of detail here but effectively what we're doing is we're implementing a custom configuration form and we've used examples here that others have implemented there's core modules that implement settings forms so there's some methods that you should always include and essentially if I go to the next page you'll see here there's our form array that's really familiar to us and then at the end we're just returning the form to the system and that allows it to render and then here at the end is the return values of the form so this is basically where we're setting some configurations so we're using the configuration management for our API keys and a path to an icon so that's all very simple and once that's in place then we can go into the system and we can take a look at in this case it's under the configuration section in the web services section because this is kind of third party content and we've got just like our fields that we've defined in that previous form and then a path to an icon we've added a checkbox here for content security policy it's an added security benefit that is recommended by the payment gateway so so that's how to create a settings page really straightforward not very different than what we've dealt with in the past now for creating a payment button we have two different things we need to do one is to create a custom field formatter this is a plugin which is something that resides within a module in Drupal 8 and plugins are kind of scary at first but they're actually remarkably simple they just need to exist in a specific directory and you see here that's the source plugin field formatter directory if you're looking to build a field formatter you can go through the whole code base and find an existing one and simply copy it into the same directory within your own module and the things that you'll need to make sure you're aware of is the comments at the top of the file the annotation and annotations are code so double check your comment before you just if you just copy an existing plugin into a similar folder structure you should just have to update that annotation and then you can modify the code as you see fit so that's what's really happened in this case is we've looked at the integer field formatter and we've simply gone in, updated the annotation changed some names and we've also added some field level settings and we just again throw those into config management so all of our storage that we have to deal with is all configs so that's really great and then once we've done all of that we need to make sure that we've taken care of it on the front end side and that's going to be in a hook theme and that lives in the stripe checkout dot module file so now this is just a snapshot of the field formatter again I'm not going to go into a huge amount of detail here just to show you again we're using our Drupal 8 namespaces so if you've got like this function is missing you might want to find out what namespace to load so that it is present and then we've got our class that we built and it extends the field formatter so again just taking look at other examples and this is how they implemented it so we'll do the same and then we define the name of it and once we've done that we've got a settings form and that's where we actually provide for the currency so that you can go and say our little hack to support multiple currency is that we've just provided two fields in our template so one of them or content type sorry so one of them is for US dollar in our case and one of them is for Canadian dollar and if there's no value provided in the field at all we just don't even render the field which is the default in Drupal anyway so in order to get that separation we've provided some variation there for that so going onward at the end of this we've got the view elements method and that's basically we're going to load all of our variables into that and that's what's going to be provided to the hook theme that we're using and now I'm jumping ahead into the stripe checkout dot module file and here we've got stripe checkout theme as our first function and that pulls all those variables into another function that we've specified here and then that function follows and we then load all of the settings that we need using config management and on the next page here we see that that's our HTML embed code that we saw earlier so this is what had been provided by stripe and we're loading it into an output variable and then we're passing that back so this is just again a standard hook implementation really similar to what was done in Drupal 7 would be fairly straightforward to implement for another payment gateway if you're not necessarily wanting to use stripe and then actually at the very top of this particular slide you can see that we've added the content security policy header and that respects the value of that checkbox that you saw in the configuration so now the big part of this is actually creating the callback and again stripe provides wonderful examples of this we need to get our values and fetch those back from the nodes so the callback of course needs a URL and that was referenced back in the earlier slide where we defined the path to the config form so those are both in that same routing file that replaces what used to be hook menu when we were trying to define paths the callback function typically lives in the slash src source folder within your module and that's new your name for this can be anything really because you define you link the name to the path in the routing file so basically we're giving it a name that we choose and this is where it goes so again to remember what we're looking at doing we're trying to load this callback function when stripe replies with the token we take the token and we take the node and we look okay it was $20 or $100 and then we make the charge using Stripes API calls and that's all provided by the Stripe PHP project if the charge is successful we mark the value of the balance do field to be zero and then we update the node revision table if that is present on that particular content type just worthy note here is what the Stripe PHP project looks like and they maintain it regularly so the last update was seven days ago this snapshot was taken today so you see that it's very active and Stripe manages this themselves so as a developer I don't need to worry about this I just know that it exists and composer will install it for me or I can go and fetch it and just put it as a sub folder within this module you'll see at the top of this we've got a node file that's referenced and that pulls that stuff into here and then we've got our class that we defined and really all we're doing here is we're taking back the Stripe token and making sure that token exists if it doesn't exist then we just fail out and that's gone so that's not a big deal we're not going to worry about processing a charge that didn't exist toward the bottom here we've got the actual charge code and this is again just an example that came from Stripe and so we've got the value of that field and we just make sure that okay this is the value of the field and we've got this token and we charge it and then we pop an error if there was an error and otherwise we update the node to set that value to zero and we move on so we're basically just after the callback has run we're redirecting the user back to the same node and at that point the cache will be reset because we've actually updated that node since they were last there and thus they'll get a fresh version of the page with the value set to zero and it will say thank you so okay so in the user interface this stuff looks like a couple config steps and then a step to create a node so that we can actually do a charge again we can set the currency node on the field level and then at that point we should be able to use this so if we go to the manage display tab on our content type you'll see here that we have three integer fields we've left the label as the default the format we're selecting the Stripe checkout formatter and then you'll see here that we've got some configuration and this again all lives in config management so all we're setting is use the node title and it will take any text field that you supply so you can just configure that to your heart's content and then we set the currency code so these should match whatever Stripe works with and as long as it's enabled in your account it should be fine in my case my account supports USD and CAD and those are great so when we move back to the node now you'll see that we've got three fields here and I filled in again an integer format so we could go a step further and try to do this as whole numbers but we just left it as sense and we put a suffix on it that has the sense symbol so that we know when we input stuff that it's like if we put a hundred zero zero that's a hundred dollars when we save that this is what we should see it sometimes takes a second if you're on like a 3G connection but it renders the payment button and that button actually is loaded from Stripe so that is an external JS that's happening there and then I've added a second field called total and that is just a free format text field so we can put anything in there the reason that again we do this is because we need a balance due that we can zero out we still want people to know what the history of the transaction was it's all recorded in Stripe but it's nice to have it so that if they come back and say okay what was that I need to print this out or whatever they have that in the case of Stripe you can actually have them because they manage the entire back office aspect of the system you can have them email the client by default so it will actually have your node title in there because that's what we used as the description and if we were to click that button we'll see our node name here if we we see that the node name is if we come here we see first the icon and the company name that are in our settings page then we see the title of the thing that we're charging so this is the node name and there's an option in Stripe to ask for the address info it's not enabled by default but I do need to have things for regulatory purposes you know you do need to know what the billing address is in most cases so in this case it's a two step form and that way we've got all of that data gathered we don't really need that data in Drupal but we could always fetch it later using the API on the second screen we see the credit card number standard info here so we've got month, year and then of course the CV it's usually CVV but it goes by different names CVC number in this case and that is the three digit code on the back of the card I think sometimes there's an option as well to accept just the postal code or zip code and that will appear on this one if you don't use the address request thing the remember me function is specific to Stripe so if people were using that then they could potentially save their credit card with Stripe and then they don't have to re-enter this but of course there's a login step for that as you would expect last note on this is that it shows the currency code it doesn't show the currency code for Americans so if it's in the United States it will just say pay $100 but if it's anywhere else it will say pay 100 euros or whatever so again when we return to the node so we've now gone we've submitted that the token came back it went through the callback the callback accepted it charged the account and then redirected us back to the node it now says paid thank you and that's a translatable string so we could put whatever we want in there and you could actually translate there's a fun feature in the multi-lingual system now where you can translate from the system language to English so you could actually override that as well in that manner if you wanted to Stripe back office looks like this so we would see our successful charge for today rings us up to $100 and on the side you have all your operations that you can perform so you can look at who your clients are and all of that stuff and at the bottom there's events and web hooks you could go and look at all of the individual transactions and then there's like a view button that would expand and you could see the same thing but if we go to the events and web hooks we can see this one has replied with charge.succeeded and it gives us actually the JSON object that was used to make this transaction happen so if you get failures you can just go and look at the JSON object and that would explain to you what happened you could see like if some other strange characters got inserted in there for whatever reason and that's just that's standard with Stripe that's kind of like you know how I said earlier they are very developer focused they don't really hide this stuff from you they're like okay it's a pretty interface and it has just the numbers and all the basic stuff for the client but for a developer you just have to click view more and it's going to give you all of that so I mentioned the content security policy thing this was something that I had been surprised that I had not encountered in the past but you know it's one of those things the content security policy header that you can provide to PHP will notify PHP what sites are allowed to run javascript on this site and any other external resources so that's that checkbox that we added sets it to only run javascript from this site and from Stripe.js when from the Stripe server when you hit a page with that button so if you had like a bunch of YouTube embed codes and like other stuff happening on that page if you had that enabled it would only load stuff from Stripe and from the local host it would like when you come back to the page you're processing that button is no longer present and the cache has been reset so you would then see all of that stuff of course those codes are still present on the page even when the button is there but they just don't run so if you look through the documentation they recommend this and it's kind of a helpful feature if you are working with a group that maybe has too much stuff going on and you want to just minimize it you may want to not use that checkbox and define your own because maybe you want to have analytics running and you would like to see where people drop off or something like that so it's just a recommendation there's also a recommendation and this really applies to any like Drupal 6 or 7 site that you're doing as well if you have like live API keys you can put those into your settings PHP file that way they can't be changed in the user interface so that can be really helpful that way if your site was to get hacked they can't go in there and change it there's a lot of nefarious things that can be done when someone finds the API keys so you may of course risk like charge backs or something if someone writes their own API implementation to ruin your life we provided this on the module page for this module we've actually published this module to Drupal.org on the module homepage we've provided the code example that you need to just copy and paste into your settings PHP file in production and that way you don't have to have that in your development environments either you can use your test API keys in your test zones and then you can put that into your live environment so that your developers may not even have access to it themselves so that can be also an awesome thing the third recommendation for additional security because we're super paranoid and Drupal 8 is still in beta until a couple weeks from now so there's this awesome module I found called config read only that's made by Pierre Willanen and somebody else needs a couple patches but what it does because we're using the new the settings form that we define we're extending the configuration system base class this is a very cool module because what it does is it says I know that this form is a config form don't let anybody ever change a config form so the system knows what types of forms they are and you can restrict them by using this module it's kind of like a simple hack but it's really awesome because you could do things like lock the whole site down and the only thing that can happen is content editing and block editing but you couldn't even move blocks around for example so you could actually lock your whole layout and lock your stuff down for payment purchases as well so that's a nice little hack that you can do to ensure that your D8 site that's in production you push it all up to production and everything's locked down in production except for content editing so less risk now there's a couple settings at Stripe that we've enabled in order to further lock things down some of them are also just for convenience so the convenience one is that we have added multiple bank accounts for multiple currencies and that way if it's just coming in in US dollars we don't necessarily convert it at that time we hold that in a US dollar account and then we can transfer it at our leisure and see values fluctuate wildly sometimes I think it's very important that you set the gateway to decline when people screw up the number on the back of their credit card it's also important to decline on the postal code or zip code failing this can be a way to prevent yourself from getting dinged on fraud because there's always reputation considerations when you're looking at charge backs, generally speaking you don't want to do charge backs like refunding people the more you do, the more the gateway is going to dislike you the same type of circumstances though, you had NSF checks if someone were to write you a check and it were to bounce there's extra fees that are associated so I'm not exactly sure what the fees are for Stripe in that circumstance but generally you don't want to be doing charge backs so in order to minimize that you want to discourage people who are trying to test cards that have been stolen from using your site as a testing bed for seeing if those cards are valid and that's a pretty common case in our case one of the reasons we went with using nodes as the basis for the entity type that we want to use this field for was that there's a hook access and that way we're actually not giving people access to this at all so we don't have a risk of these types coming in and testing out they're like stolen database cards I haven't found this setting in the Stripe backend but most gateways allow you to restrict to one IP address so I need to read the documentation myself for that because I would like if you can lock it down to one IP address and there's no PHP module in the PHP input format in Drupal 8 that doesn't exist anymore there's no way to create PHP code so if you lock the payment gateway down to just one just to one IP address and they're not able to do any PHP work on that address that means you effectively can't do anything even if you have the API keys so that would also be another way to lock it down even further and then of course it's kind of obvious but don't use the live API keys for testing like use your test keys, make sure everything works, the reason that they exist is like for this reason yeah so I mean there's always a good it's always a good idea to do a test charge when you finally do go live using a live account but you know you don't want to be doing that all day long I've heard of people using like the they're not really temporary credit cards the ones that you can like buy at the post office and charge up with like 10 bucks or something I've heard of people using these as an alternative to using the test API and it's like why would you do that it just waste money so since we've created this module we've had some feedback and feedback is always super welcome so there's a few things that we have on our to-do list and some of those are like implementing this change that went in last week which is the T function and the correspondent this T the T function is sometimes a method when you're working with classes so those also need to be cast as a string now in order to have them work due to some of the safe markup stuff that's happening so so we have an update to do for that we would like to support other entity types right now this method the way that we've described it it really works with like one node one charge I don't know if it'd be worth doing an unlimited like ongoing charge because you know we haven't really we don't person we don't have a use case for that there's also a possibility of course of like doing address collection in Drupal and then just passing through the the postal code or zip code along with your API request so that's a that's a different method if you were looking at wanting to collect more of that stuff in Drupal or to just have it on file commerce guys made this really awesome address module that supersedes what used to be address field and it's very generic and it has all this wonderful stuff in it so that would be one potential patch that we could look at accepting so that would be really great API errors are always worth catching so in some circumstances it's not obvious like that for example the currency code was typed wrong or something and it throws like a an error you wouldn't see very often but it's still an error so catching errors is always good and then of course you can never have more tests so now if you're still working in the Drupal 7 universe there's a couple things that might be helpful if you're looking to immediately reduce your PCI scope and you are using Stripe there was some work done on making check out one of the options for that so that has been committed as of a few months ago there's also a D8 module called payment which is the successor to the payment module in Drupal 7 I imagine that this kind of proof of concept module will eventually make its way into payment module payment module does a bit more where it can handle it has a storage back end essentially and you can plug it into things the Drupal 7 one can either stand on its own and just be that or you can you can charge money on nodes like this in Drupal 7 you can integrate it with web form in Drupal 7 and you can integrate it with commerce in Drupal 7 so those things are really great because they're generic and the payment module does exist in Drupal 8 and there are some examples so we're kind of hoping that now that we've got like minimum viable products for our Drupal 8 site that we can then turn around and you know make something a bit more robust now that we've got our heads around how to do stuff in Drupal 8 and then I've already noted but Braintree, Authorize.net and others have their own versions of like a hosted solution and again that's just where like all of the code and all of the stuff that touches the credit card is hosted by your gateway not by you and that way you never, never, never touch the credit card so this same approach could easily work in Drupal 7 we did have a request to do this in Drupal 7 but it's not on our radar at the moment because we're sort of pressed for time so yeah some special mentions kind of need to be made my colleague Anna Kalata was responsible for creating the Field Formatter and like kind of reverse engineering the YouTube module as we found it was a great example to work from and then of course we've listed out the YouTube module authors because it was a really great example to follow and they had published this a long time ago for reference because I know people are like are we ready to use Drupal 8 yet we haven't changed anything since May 19 like anything and it still runs against Drupal 8 head the only thing that we've changed since like January in our projects has been to update the menu links because those are now multi-lingual and they're now proper entities and we had another change that was again not for this module but another module where we had to update some paths because we were referring paths have changed in the past few months where they used to be like they are in Drupal 7 where it's like node slash 19 is what you would put in a reference field but now it's slash node slash 19 and that's just trying to standardize I think with what's done and common in symphony so PCI compliance paper authors this is like a fantastic resource and they all deserve like honorable mention because like it's you put yourself at so much risk if you just do like it's like you want to grab a D7 module and like someone punches their credit card into your site and you're taking it into PHP there's a lot of potential issues that could arise from that and it's important to know like what what kind of danger you're putting yourself in especially if you're dealing with smaller sites where they may not be charging a lot of money but if they are not updating for security and things like that there's they're running a huge risk and the liability is now on them whereas it used to be on the credit card company to manage that so really really really happy that they were able to publish that document and they keep it up to date so that's wonderful alright so I guess we'll open it up to questions if there are any I've tried to address most that I've heard in the past in the sessions so yeah and again my name is Ryan Wiedel so my contact information is there if you wish oh can you use the mic if you don't mind when you get the token is it on? oh yeah okay cool thank you when you get the token returned what is in that is it just a number it is the credit card token because you said you couldn't you didn't know how to figure out whether it was paid or not until the value was zero yeah so the token itself is just the card and there is one other thing that comes back with that I think it's the email address that comes back so you really just get the token and the email address and then you do the charge yourself you use the token to make the charge and you get a return value from that so the return value I believe contains a success statement and I think the email address as well and then with that information I think it has a transaction code as well and then you can use that information using the Stripe PHP library to make subsequent calls to get the rest of the data so if you need to get the address information that they input you can use that successful charge token to look back and see what else they provided to Stripe so you can retrieve any of the information the credit card information is limited to like the last four digits and a few things of that nature but not the actual credit card itself so basically anything that was in that API call I kind of cut this screen but you can retrieve anything that's in this JSON object so any other questions? alright well thanks for coming I know it's the end of the day so we can head out a couple minutes early and we can get a head start on the beers so thanks again