This entry is part 6 of 9 in the Integrating Stripe.com with WordPress Series
- Stripe Integration Part 1 – Building the Settings and a Simple Payment Form
- Stripe Integration Part 2 – Recurring Payments
- Stripe Integration Part 3 – Variable Prices and Enhanced Plan Handling
- Stripe Integration Part 4 – Multiple Recurring Payment Options
- Stripe Integration Part 5 – Accepting Discount Codes
- Stripe Integration Part 6 – Payment Receipts
- Stripe Integration Part 7 – Creating and Storing Customers
- Stripe Integration Part 8 – Working with Invoices
- Stripe Integration Part 9 – The Stripe Button
The Stripe API includes a system called “webhooks”, which are used for notifying your site of events happening in your Stripe account, such as received payments, account creation, customer cancellation, etc. One of the first features you will find webhooks are useful for is sending payment receipts, both for one time payments and recurring subscription profiles. This tutorial will walk you through the basics of how to work with the webhook system in Stripe.
Unlike many payment processors, such as PayPal, Stripe does not include automatic payment notification emails for the payer, only the recipient. If we want out customers to be alerted when they make a payment (primarily a recurring payment), we need to add an additional set of functions to our plugin.
We are going to utilize what Stripe calls webhooks for creating payment receipt emails. This payment receipts will be sent both for recurring and non recurring payments.
Before we jump into the code for creating our purchase receipts, let’s figure out what exactly a webhook is. This is how Stripe describes a webhook:
Interacting with third party APIs like Stripe often suffers from two important problems:
- Services not directly responsible for making an API request may still need to know the response
- Some events, like disputed charges and many recurring billing events, are not the result of a direct API request
Webhooks solve these problems by letting you register a URL that we will POST anytime an event happens in your account. When the event occurs, for example when a successful charge is made in your account, Stripe creates an event object. This object contains all the relevant information, including the type of event and the data associated with that event.
Essentially, webhooks are a notification system for your Stripe account that can alert you (or your site) about events happening in your account. Anytime something happens, such as a payment being made, Stripe will send POST data to your site which can then be used for performing necessary actions.
If you are familiar with what many other payment systems call IPN (Instant Payment Notification) or Remote Notification URL, then this will be really easy to understand and follow. Even if you’ve never used an IPN or similar, getting a grasp on Stripe’s webhooks should not be difficult.
Let’s start by going to the Webhooks section in our Stripe account settings.
This is the page where you will enter your webhook URLs, which are the URLs that get notified when an event happens. You can see in the screenshot above that I have a webhook URL of http://easydigitaldownloads.com/?listener=stripe, which is the URL used by Restrict Content Pro on Easy Digital Downloads.com.
Note the presence of the query parameter called “listener”; it is set to a value of “stripe”. This parameter let’s us easily detect when a webhook has been sent (you will see in a minute). The query var can be anything, but I like to use names that make sense. Think of it this way: the query var is used to listen for webhooks.
If you wanted to, you could also point the webhook to a .php file, rather than a page with a query var. The query var is my preferred method.
In our Stripe + WordPress plugin, we will use a query var called “wps-listener”, which stands for “WordPress Stripe Listener”.
Before we jump into the code specific to our plugin, let’s look at same samples given by Stripe on their Webhooks documentation page. This is their very basic PHP example:
1 2 3 4 5 6 7 8 9 | // set your secret key: remember to change this to your live secret key in production // see your keys here https://manage.stripe.com/account Stripe::setApiKey("vtUQeOtUnYr7PGCLQ96Ul4zqpDUO4sOE"); // retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); $event_json = json_decode($body); // do something with $event_json |
If you’re not familiar with what @file_get_contents(‘php://input’); does, then you’ll likely have a hard time understanding this at first glance. Let’s see if I can clear it up a little.
Stripe sends event (payment received, payment failed, customer created, etc) data to your site using POST, which means that the information sent is available via the $_POST super global in our PHP. @file_get_contents(‘php://input’); is a way of grabbing all of the POST data and storing it into a variable of our own, though we could also access it via $_POST if we wanted to as well.
Once we have the body of the data, we parse it into a json object. This json object will contain all of the information about the event. The data in the object will vary based on the kind of event that has occurred, but the basic structure looks like this:
{ "type": "invoice.updated", "created": 1340924356, "data": { "object": { "amount_due": 1000, "subtotal": 1000, "id": "in_LXiFJZM5wXNKHJ", "lines": { "subscriptions": [ { "period": { "end": 1343512535, "start": 1340920535 }, "amount": 1000, "plan": { "interval": "month", "currency": "usd", "object": "plan", "trial_period_days": null, "amount": 1000, "name": "Basic Level", "livemode": false, "id": "basiclevel" } } ], "invoiceitems": [ ], "prorations": [ ] }, "ending_balance": 0, "discount": null, "starting_balance": 0, "next_payment_attempt": null, "date": 1340920637, "closed": true, "livemode": false, "period_end": 1340920535, "period_start": 1338242135, "attempt_count": 1, "customer": "cus_Oy3TD2QrWEcX1o", "attempted": true, "object": "invoice", "total": 1000, "paid": true, "charge": "ch_Q3QLWTE7KyVRh2" }, "previous_attributes": { "ending_balance": null, "next_payment_attempt": 1340924237, "closed": false, "attempted": false, "paid": false, "charge": null } }, "object": "event", "livemode": false, "pending_webhooks": 0, "id": "evt_YdBiBaTbvrskne" } |
With the data present here, we can do anything we want, in this case we’re going to create payment receipts, so we will look at the type of event that is being submitting (to make sure it is for a payment received) and then we will grab the payer’s information from the data object so that we can send them an email.
If you are feeling like you’re in way over your head at this point, don’t worry, it will all make much, much more sense in a moment.
We are going to now start laying out the basic structure for our code. The first thing we need to do is create a new file called stripe-listener.php and place it inside of our includes/ folder.
Start by adding this function to the new file:
1 2 3 4 5 6 7 8 9 | <?php function pippin_stripe_event_listener() { if(isset($_GET['wps-listener']) && $_GET['wps-listener'] == 'stripe') { // we will process the events here } } add_action('init', 'pippin_stripe_event_listener'); |
This function will “listen” for events sent by Stripe, but will sit silent and harmless at all other times.
As we have done with most of our other functions that utilize the Stripe API, we need to make the Stripe functions available by loading the API libraries, so we modify our function to this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | <?php function pippin_stripe_event_listener() { if(isset($_GET['wps-listener']) && $_GET['wps-listener'] == 'stripe') { global $stripe_options; require_once(STRIPE_BASE_DIR . '/lib/Stripe.php'); if(isset($stripe_options['test_mode']) && $stripe_options['test_mode']) { $secret_key = $stripe_options['test_secret_key']; } else { $secret_key = $stripe_options['live_secret_key']; } Stripe::setApiKey($secret_key); } } add_action('init', 'pippin_stripe_event_listener'); |
Next we need to retrieve the POST data sent by Stripe, and we will do this in the same way as the basic example I showed above:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | <?php function pippin_stripe_event_listener() { if(isset($_GET['wps-listener']) && $_GET['wps-listener'] == 'stripe') { global $stripe_options; require_once(STRIPE_BASE_DIR . '/lib/Stripe.php'); if(isset($stripe_options['test_mode']) && $stripe_options['test_mode']) { $secret_key = $stripe_options['test_secret_key']; } else { $secret_key = $stripe_options['live_secret_key']; } Stripe::setApiKey($secret_key); // retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); // grab the event information $event_json = json_decode($body); // this will be used to retrieve the event from Stripe $event_id = $event_json->id; if(isset($event_json->id)) { // process event here } } } add_action('init', 'pippin_stripe_event_listener'); |
Once we have the Event ID, we will re-retrieve the event from Stripe using the API. This is a security measure to help ensure we are processing a real event and not one that a malicious person has tried to send our site.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | <?php function pippin_stripe_event_listener() { if(isset($_GET['wps-listener']) && $_GET['wps-listener'] == 'stripe') { global $stripe_options; require_once(STRIPE_BASE_DIR . '/lib/Stripe.php'); if(isset($stripe_options['test_mode']) && $stripe_options['test_mode']) { $secret_key = $stripe_options['test_secret_key']; } else { $secret_key = $stripe_options['live_secret_key']; } Stripe::setApiKey($secret_key); // retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); // grab the event information $event_json = json_decode($body); // for extra security, retrieve from the Stripe API $event_id = $event_json->id; if(isset($event_json->id)) { try { // to verify this is a real event, we re-retrieve the event from Stripe $event = Stripe_Event::retrieve($event_id); } catch (Exception $e) { // something failed, perhaps log a notice or email the site admin } } } } add_action('init', 'pippin_stripe_event_listener'); |
As soon as we have retrieved and verified the event from Stripe, we can process it. What we will do here is setup a conditional that checks to see what kind of event has been sent and then perform the necessary actions. I’m going to show you the code for two event types, but there are many more. You can see the complete list of event types on the Stripe API Documentation.
The event type is accessible with this:
$event->type == 'this.is.the.event.type' |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | <?php function pippin_stripe_event_listener() { if(isset($_GET['wps-listener']) && $_GET['wps-listener'] == 'stripe') { global $stripe_options; require_once(STRIPE_BASE_DIR . '/lib/Stripe.php'); if(isset($stripe_options['test_mode']) && $stripe_options['test_mode']) { $secret_key = $stripe_options['test_secret_key']; } else { $secret_key = $stripe_options['live_secret_key']; } Stripe::setApiKey($secret_key); // retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); // grab the event information $event_json = json_decode($body); // this will be used to retrieve the event from Stripe $event_id = $event_json->id; if(isset($event_json->id)) { try { // to verify this is a real event, we re-retrieve the event from Stripe $event = Stripe_Event::retrieve($event_id); $invoice = $event->data->object; // successful payment, both one time and recurring payments if($event->type == 'charge.succeeded') { // send a payment receipt email here } // failed payment if($event->type == 'charge.failed') { // send a failed payment notice email here } } catch (Exception $e) { // something failed, perhaps log a notice or email the site admin } } } } add_action('init', 'pippin_stripe_event_listener'); |
When a payment is successfully made, it triggers the charge.succeeded event, so inside of this conditional we can setup our purchase receipt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | <?php function pippin_stripe_event_listener() { if(isset($_GET['wps-listener']) && $_GET['wps-listener'] == 'stripe') { global $stripe_options; require_once(STRIPE_BASE_DIR . '/lib/Stripe.php'); if(isset($stripe_options['test_mode']) && $stripe_options['test_mode']) { $secret_key = $stripe_options['test_secret_key']; } else { $secret_key = $stripe_options['live_secret_key']; } Stripe::setApiKey($secret_key); // retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); // grab the event information $event_json = json_decode($body); // this will be used to retrieve the event from Stripe $event_id = $event_json->id; if(isset($event_json->id)) { try { // to verify this is a real event, we re-retrieve the event from Stripe $event = Stripe_Event::retrieve($event_id); $invoice = $event->data->object; // successful payment if($event->type == 'charge.succeeded') { // send a payment receipt email here // retrieve the payer's information $customer = Stripe_Customer::retrieve($invoice->customer); $email = $customer->email; $amount = $invoice->amount / 100; // amount comes in as amount in cents, so we need to convert to dollars $subject = __('Payment Receipt', 'pippin_stripe'); $headers = 'From: "' . html_entity_decode(get_bloginfo('name')) . '" <' . get_bloginfo('admin_email') . '>'; $message = "Hello " . $customer_name . "\n\n"; $message .= "You have successfully made a payment of " . $amount . "\n\n"; $message .= "Thank you."; wp_mail($email, $subject, $message, $headers); } // failed payment if($event->type == 'charge.failed') { // send a failed payment notice email here } } catch (Exception $e) { // something failed, perhaps log a notice or email the site admin } } } } add_action('init', 'pippin_stripe_event_listener'); |
Pretty simple right? We simply grab the customer’s email from the data returned by Stripe, format the payment amount, and then send a basic email. If this was a complete plugin, we’d probably include an option in our admin settings to define the exact contents of the purchase receipt email, but this basic implementation is better for demonstrative purposes.
When a payment fails (perhaps if a credit card has expired), the charge.failed event is triggered, so inside of our conditional for this event type we can send our “Failed Payment” notice:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | <?php function pippin_stripe_event_listener() { if(isset($_GET['wps-listener']) && $_GET['wps-listener'] == 'stripe') { global $stripe_options; require_once(STRIPE_BASE_DIR . '/lib/Stripe.php'); if(isset($stripe_options['test_mode']) && $stripe_options['test_mode']) { $secret_key = $stripe_options['test_secret_key']; } else { $secret_key = $stripe_options['live_secret_key']; } Stripe::setApiKey($secret_key); // retrieve the request's body and parse it as JSON $body = @file_get_contents('php://input'); // grab the event information $event_json = json_decode($body); // this will be used to retrieve the event from Stripe $event_id = $event_json->id; if(isset($event_json->id)) { try { // to verify this is a real event, we re-retrieve the event from Stripe $event = Stripe_Event::retrieve($event_id); $invoice = $event->data->object; // successful payment if($event->type == 'charge.succeeded') { // send a payment receipt email here // retrieve the payer's information $customer = Stripe_Customer::retrieve($invoice->customer); $email = $customer->email; $amount = $invoice->amount / 100; // amount comes in as amount in cents, so we need to convert to dollars $subject = __('Payment Receipt', 'pippin_stripe'); $headers = 'From: "' . html_entity_decode(get_bloginfo('name')) . '" <' . get_bloginfo('admin_email') . '>'; $message = "Hello " . $customer_name . "\n\n"; $message .= "You have successfully made a payment of " . $amount . "\n\n"; $message .= "Thank you."; wp_mail($email, $subject, $message, $headers); } // failed payment if($event->type == 'charge.failed') { // send a failed payment notice email here // retrieve the payer's information $customer = Stripe_Customer::retrieve($invoice->customer); $email = $customer->email; $subject = __('Failed Payment', 'pippin_stripe'); $headers = 'From: "' . html_entity_decode(get_bloginfo('name')) . '" <' . get_bloginfo('admin_email') . '>'; $message = "Hello " . $customer_name . "\n\n"; $message .= "We have failed to process your payment of " . $amount . "\n\n"; $message .= "Please get in touch with support.\n\n"; $message .= "Thank you."; wp_mail($email, $subject, $message, $headers); } } catch (Exception $e) { // something failed, perhaps log a notice or email the site admin } } } } add_action('init', 'pippin_stripe_event_listener'); |
And that’s it! We now have a fully functional payment receipt and failed payment notice system.
This system demonstrates some of the things you can do with the Stripe webhook system, but this is much, much more you can do.
Hopefully webhooks make a bit more sense now, as I know they can be very confusing when you first look into them.
The complete source for the Stripe plugin up to this point can be downloaded below.
[download id=”47″ format=”1″]
Dude, this is great thanks man! Keep on rockin’
This is an amazing tutorial series – THANK YOU SO MUCH!!
When will the Part 7 – Creating and Storing Customers go live?
Not sure, probably sometime next week.
awesome, lookin forward to it. thanks again pippin!
Thanks so much for putting this all together, I’m learning a lot. I know I’m missing something simple here, but I’m not sure what the webhook URL should be exactly…I’ve tried both the ‘?wps-listener=stripe’ query and pointing directly to the php file. Is it possible to clarify at all?
My webhook URL is setup as “http://jonhillman.com/?wps-listener=stripe” in Stripe, and the stripe-listener.php is living in the includes folder of the wordpress-stripe-integration plugin…
I’m getting 408’s returned to Stripe when testing the webhook… Is that because we’re not responding to the POST, and this is normal?
If I point the webhook right at stripe-listener.php, same thing…opening that URL directly results in an error as add_ action() is undefined (I think because WP is not handling things at that point).
Any advice would be great…this tutorial rocks!!!
Can you show me the complete contents of your stripe-listener.php? You need to include the file into your main plugin file (this will make add_action() available).
The function that intercepts the webhooks needs to be connected to the “init” action; this makes it possible for the function to “listen” for the $_GET variable (in this case, wps-listener) and then process the webhook as needed.
Does that help?
I did not have it included in the main plug-in file, now it is. Still problematic…should the URL be able to point at my domain directly and query there? (www.jonhillman.com/?wps-listener)
This is the complete contents of stripe-listener.php, it’s lifted exactly (I think) from your example. Thanks so much again for your help!:
Code removed. Please use pastebin.com
Can you please paste your code into pastebin.com and then share the link? Posting it in the comment removes all formatting and makes it very difficult to read.
I have created wordpress site in localhost and try to create webhook of localhost but cant able to create it because there is no “.com” in localhost url, how can i fix this ?
Webhooks do not work for local sites. You must have a live URL in order to test on a local site.
Hello, I’ve got a question for part 6, I can successfully make a payment, but I don’t seem to be receiving any emails. Stripe dashboard shows charge.succeeded. I’ve tried http://sitename.com/login/wp-content/plugins/wordpress-stripe-integration/includes/stripe-listener.php and http://sitename.com?wps-listener=stripe, no errors are reported anywhere, but no emails are received either.
I click on the entry under “events & webhooks” and “Webhook Details” say success, but there is no response shown.
When testing the webhooks in the stripe dashboard for charge succeeded, the response for the query is the source code of my home page, and the result returned for the full url to stripe-listener.php is just empty.
I tried starting from scratch using the download plugin link at the end of part-6 but still no change.
Once again I appreciate your help very much, thank you.
Chuck
The ?wps-listener=stripe is the URL you want.
Can you show me your complete code for the listener?
I’ve set the webhook back to ?wps-listener=stripe
stripe-listener.php can be viewed here, http://pastebin.com/f9VbqUxX but it’s the same one that can be downloaded above
I’m wondering if I just stumbled on part of the issue, I don’t seem to be creating new customers. I’m not logged in to the site, I use a new email address never used to enter an order previously, enter cc#, cvc, exp. Success! Check stripe dashboard, Logs I’ve got a new charge and token, Events & Webhooks charge.succeeded, but no new customer.
In the scenario I just explained I should have a new customer, correct?
Your code looks right. Can you give me a screenshot of the webhooks in your Stripe account?
Customer creation was covered in the next part of the series, so unless you’re using code from that part or later, no, customers will not be created.
I have been playing with code beyond part 6, came back to part 6 to get get payment receipts working, I actually started back at the beginning a little bit ago, going through step by step again, at least becoming more familiar, if not figuring out where I’m going wrong.
screenshot – property-rejuvenation.com/pippin/hook.jpg
Just finished re-doing part-7, customers are working again, but still no payment receipts.
Ok that all looks perfect.
What other plugins do you have installed?
Below are all that are installed, but even if I deactivate all but the stripe plugin I still get no email.
Adminimize – http://wordpress.org/extend/plugins/adminimize/
Google Analytics for WordPress – http://wordpress.org/extend/plugins/google-analytics-for-wordpress/
ManageWP – Worker – https://managewp.com/
Meta Box – http://wordpress.org/extend/plugins/meta-box/
Quform – http://www.themecatcher.net/iphorm-form-builder/
Slider Pro – http://sliderpro.net/
Theme Test Drive – http://wordpress.org/extend/plugins/theme-test-drive/
WordPress HTTPS – http://wordpress.org/extend/plugins/wordpress-https/
WP-Crontrol – http://wordpress.org/extend/plugins/wp-crontrol/
I’m guessing that it’s an issue with WordPress HTTPS. Can you try disabling it and then making sure that Stripe is pointing to http://?
I’m back, WordPress HTTPS has been turned off, I actually tested with all plugins disabled and received no email. When you say make sure stripe is pointing to http:// I assume you mean the webhook?
Ok, thanks. Something has got to be blocking it. Is your site running on nginx by chance?
Happy New Year, Nope not running nginx, I just ran a transaction, and checked my log files, and found these two lines, perhaps it offers a clue, I think everything looks good but I’m unsure what the 4 numbers & “-” represent.
50.18.189.108 – – [02/Jan/2013:19:04:07 -0500] “POST /?wps-listener=stripe HTTP/1.1” 200 7640 “-” “-”
50.18.189.115 – – [02/Jan/2013:19:04:07 -0500] “POST /?wps-listener=stripe HTTP/1.1” 200 7636 “-” “-“
I just tried on another install, unfortunately all the sites I have access to are the same host, so I assume the same server setup, I checked the log files for the other install test and had similar results.
Dang. That’s just weird. Sorry but I really don’t know what’s going on.
No problem, you’ve helped get me this far, it’s getting late here but I’m going to look into this deeper tomorrow, I was just looking at https://github.com/keven/stripe-webhook-php/blob/master/webhook-php/index.php you’ll see at line 21 “this will fail in Test Webhooks”, and the screen shot of your webhook shows your webhook as live, as opposed to test. Were you testing this in live mode?
Oh! I do recall that now! If you change it to only use $event_id = $event_json->id;, does it work?
Do you mean to just comment out $event = Stripe_Event::retrieve($event_id);, that didn’t appear to make a difference.
It was also suggested to me to try SMTP authentication instead of mail() or wp_mail()
I figure I’ll get to the bottom of this eventually.
So using smtp, mail() and wp_mail() doesn’t seem to be an issue.
Am I correct in thinking that if I add wp_mail(‘address@gmail.com’, ‘test’, ‘test’); just after function pippin_stripe_event_listener() {, in stripe-listener.php, it should trigger an email if it picks up stripes web hook?
If the webhook is picked up, yes that would trigger an email.
Hmm, that’s what I suspected, no email is received with that modification. I can throw wp_mail(‘address@gmail.com’, ‘test’, ‘test’); on the payment page, and when I hit the page I get an email, so I know the server has no issue sending emails with wp_mail, so I guess for some reason it’s not picking up the webhook.
So I’ve been troubleshooting this today and I wonder if any of this gives you an idea why I might be having issues.
In stripe-listener.php
This works, but sends the email twice.
function pippin_stripe_event_listener() {
mail(’email@gmail.com’, ‘listener’, ‘message’, $headers);
}
pippin_stripe_event_listener();
This doesn’t work.
function pippin_stripe_event_listener() {
mail(’email@gmail.com’, ‘listener’, ‘message’, $headers);
}
add_action(‘init’, ‘pippin_stripe_event_listener’);
I tried both variations in Twenty Eleven thinking maybe something in my theme was the issue, but it had the same results. I currently have my webhook pointing directly to stripe-listener.php. I noticed in Stripe when I test my webhooks, the one that was directed at the file had an empty response field, the webhook using the query var had what you would see if viewing the source in a browser for the sites home page.
Also I take back my previous statement about wp_mail working properly, apparently it works if I add it tot he theme, and hit the page, but using it in stripe-listener.php did not work.
In the first example do you have the function call placed directly into the plugin/theme file?
I have the function call in the file stripe-listener.php, below is currently the only thing in stripe-listener.php
<?php
function pippin_stripe_event_listener() {
mail('mail@gmail.com', 'listener5', 'message', $headers);
}
pippin_stripe_event_listener();
If that’s not firing then something is blocking it before it ever gets there.
What I was trying to point out that wasn’t working is this fires
function pippin_stripe_event_listener() {
mail(‘email@gmail.com’, ‘listener’, ‘message’, $headers);
}
with
pippin_stripe_event_listener();
but not with
add_action(‘init’, ‘pippin_stripe_event_listener’);
That seems to indicate that the webhook is definitely getting picked up. Do you by chance have another WordPress install you can test this on?
Hi Pippin,
Thanks for the great tutorial.
Here is my issue.
I have a sales page with a time-sensitive offer. Whoever comes to the page and buys first gets the product.
Therefore when charge succeeded event is triggered, I want the sales page to be redirected to an out of stock page.
So for example, I have a page called http://www.example.com/sales-page.
It is available for 3 days.
1 day into the sale someone comes along and buys the product.
If someone else comes to http://www.example.com/sales-page after the product has been purchased, I want it to go to http://www.example.com/too-late.
I see where the redirect code should go in your example above, but I am not sure exactly what the function itself should be in wordpress.
The function that redirects the customer or the function that checks if they are early enough to purchase?
The function that redirects them. I can’t tell if it is supposed to be written to .htaccess or if it can be a php header redirect.
Stripe supports email receipts as of May. Read up on it here:
https://stripe.com/blog/email-receipts
I created a simple service to test webhooks from behind a firewall (i.e. localhost) – http://www.ultrahook.com
Hi there – thanks so much for this, it really is an amazing learning resource. There’s one thing that I can’t seem to get right though, and I’m hoping you can help me – I’ve followed your instructions very carefully, and included “include(STRIPE_BASE_DIR . ‘/includes/stripe-listener.php’);” in my plugin file as well as put all of your code into stripe-listener.php itself, but when I test the webhooks on stripe’s website I get a 302 error.
No idea what’s going on – can you give me a hint?
Thanks
Turns out it was the password protection system I’d put on the site while it was in developement. Foolishness!
This is gold. God bless you