The Goal: There are a few buttons on the screen, like so –
[Product 1 – $20]
[Product 2 – $35]
and so on...
Users can select as many products as they like. In the JavaScript, I have a variable amount
that increments by how much ever the product costs when the user selects it. So the flow is like this:
User selects product 1 & 2 --> amount = 20 + 35 = 55
Then, the user can press the Pay with Card button to launch the Stripe Checkout modal. Fill that out, pay, done.
The Problem: Now, I'm using the custom button version of Checkout, so I can style the button my way and put this variable amount in. So, that implementation is pretty simple:
var handler = StripeCheckout.configure({
key: 'pk_test_XXXXXX',
image: 'assets/logo-stripe.png',
locale: 'auto',
token: function(token, args) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
$.ajax({
url: 'php/charge.php',
type: 'post',
data: {tokenid: token.id, email: token.email, amount: amount},
success: function(data) {
if (data == 'success') {
console.log("Card successfully charged!");
}
else if (data == 'failure') {
console.log("Card error");
} else {
console.log("Other error");
}
},
error: function(data) {
console.log("AJAX error!");
console.log(data);
}
});
}
});
$('#pay-button').on('click', function(e) {
if (amount == 0) {
$('#pay-button').addClass('animated shake'); // Animates the button and refuses to open the modal if user didn't select any products
$('#pay-button').one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', removeAnimation);
} else {
handler.open({
name: 'Company, Inc.',
description: "Description",
amount: amount // Here's the variable
});
e.preventDefault();
}
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
This is the JavaScript logic. I left out the call to checkout.js, since that's not really of any consequence to this question.
From a front end perspective, this is peachy. Now comes tokenization and actually charging the card. Here's where things start having issues. If you look at the token handling, I'm trying to POST email, amount, and token data to charge.php. Based on the fact that I don't get any errors from the console about this, I think that's working.
In charge.php, I have this: (updated Apr. 20: This is working code)
<?php
require_once('stripe-php/init.php');
// Set secret key
\Stripe\Stripe::setApiKey("sk_test_XXXXXXX");
// Get the credit card details submitted by the form
$token = $_POST['tokenid'];
// Create the charge on Stripe's servers - this will charge the user's card
try {
$customer = \Stripe\Customer::create(array(
'email' => $_POST['email'],
'source' => $token
));
$charge = \Stripe\Charge::create(array(
"amount" => $_POST['amount'],
"currency" => "usd",
"customer" => $customer->id
));
echo "success";
} catch(\Stripe\Error\Card $e) {
// The card has been declined
echo "failure";
}
?>
Whenever I try to make a purchase, the log gives me "Success Error." I'm loosely following code presented here – How to create a stripe charge with a checkout token sent via AJAX to php. So, I don't know what Success Error is, but my guess is that the data was sent to charge.php fine, but the card wasn't charged. This is supported by the fact that my Stripe dashboard doesn't show any record of payment.
What I have tried:
1) I thought the error might be my config.php. I'm not using Composer (because I have no idea what that is or how to even start using it), so instead I'm calling init.php from stripe-php. This is an acceptable alternative to Composer, according to Stripe's own documentation.
Here's the config.php:
<?php
require_once('php/stripe-php/init.php');
$stripe = array(
secret_key => getenv('sk_test_XXXXXX'),
publishable_key => getenv('pk_test_XXXXXX')
);
\Stripe\Stripe::setApiKey($stripe['secret_key']);
?>
No longer using config.php, all combined into charge.php
2) In my POST call, I pass a tokenid but in my charge.php, I use stripeToken. This probably happened because I tried using a Stack Overflow answer and the Stripe docs to craft a complete solution. I thought it was odd that stripeToken isn't being sent from my front-end. So, I tried using tokenid in my charge.php (replace stripeToken
with tokenid
. Changing to tokenid didn't work and presented safety concerns (I'd rather stick to the compliant stripeToken, but I don't know how to implement it).
3) I worried about sending the amount variable to charge.php. I didn't want users to change it in their console, but if I don't send it, I don't know how to have variable pricing. I need variable pricing, since users are selecting multiple products with different prices (see: The Goal). So, that's another conundrum for me.
It might be worth noting that I had to test this in production to even get Success Error. In localhost, I get a 500 Internal Server Error. Don't know why, but guessing it has to do with the lack of PHP environment or file structure.
Any help would be greatly appreciated! Thank you.