Search for PHP example new stripe "checkout" integration stripe-php - php

What do I have to change in my code to immigrate from legacy stripe checkout to the new checkout?? I am confused with their wording. And most examples I find are old (2015-1016...and are the "old way")
Stripe wants me to upgrade to new checkout because of SCA
This is my working stripe checkout, I have a button that opens the checkout box
<script>
var handler = StripeCheckout.configure({
key: '<? echo $stripe_p_key;?>',
image: 'https://stripe.com/img/documentation/checkout/marketplace.png',
locale: 'auto',
token: function(token) {
var $form = $('#f2');
var token = token.id;
showloader('loaderid');
$form.prepend($('<input type="hidden" style="display:none" name="stripeToken">').val(token));
$form.prepend($('<input type="hidden" style="display:none" name="cc_currency">').val('<? echo $dialog_waehrung_kreditkarte;?>'));
$form.get(0).submit();
}
});
document.getElementById('customButton').addEventListener('click', function(e) {
// Open Checkout with further options:
handler.open({
name: '',
description: '<? echo $dialog_titel;?>',
zipCode: true,
currency: '<? echo $dialog_waehrung_kreditkarte;?>',
email: '<? echo $dialog_email_kreditkarte;?>',
amount: <? echo $dialog_preis_kreditkarte;?>
});
e.preventDefault();
});
// Close Checkout on page navigation:
window.addEventListener('popstate', function() {
handler.close();
});
</script>
then I charge the card in the next step
Stripe::setApiKey($params['private_live_key']);
$pubkey = $params['public_live_key'];
try {
$charge = Stripe_Charge::create(array(
"amount" => $amount_cents,
"currency" => $_SESSION['cc_currency'],
"source" => $_SESSION['stripeToken'],
"description" => $description,
"expand" =>array("balance_transaction")
)
);
If no error is thrown I forward the customer to his download page.
I want a very simple way, I do not need customers, bills, recruing payments or whatever..just single payments. I do not want customers address or such things. Payment and goodbye...
Stripe says I have to change this process.
But their example is confusing for me:
https://stripe.com/docs/payments/checkout/migration#api-products
(I did never create a customer for exampley...why should I?)
Can someone tell me what I have to do to migrate to the new checkout version?

Basic setup (you can build it up from here)
Back-end:
Update your Stripe PHP Library.
Change from \Stripe\Charge to \Stripe\PaymentIntent following this format:
$charge = \Stripe\Charge::create([
'source' => $token_id,
'amount' => $amount,
'currency' => 'usd',
]);
$intent = \Stripe\PaymentIntent::create([
'payment_method_data' => [
'type' => 'card',
'card' => ['token' => $token_id],
],
'amount' => $amount,
'currency' => 'usd',
'confirmation_method' => 'manual',
'confirm' => true,
]);
Front-end:
Update your Stripe JS to use v3.
<script src='https://js.stripe.com/v3/' type='text/javascript'></script>
Update JS code that handles your payment form:
document.addEventListener("DOMContentLoaded", function(event) {
var stripe = Stripe('xxxxxxxxxx'); // test publishable API key
var elements = stripe.elements();
var card = elements.create('card');
// Add an instance of the card UI component into the `card-element` <div>
card.mount('#card-element');
// Handle events and errors
card.addEventListener('change', function(event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit the form
form.submit();
}
function createToken() {
stripe.createToken(card).then(function(result) {
if (result.error) {
// Inform the user if there was an error
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
// Send the token to your server
stripeTokenHandler(result.token);
}
});
};
// Create a token when the form is submitted.
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(e) {
e.preventDefault();
createToken();
});
});
Edit your HTML form:
<form action="process_payment.php" method="post" id="payment-form">
<div class="form-row">
<label for="card-element">
Credit or debit card
</label>
<div id="card-element"><!-- Your form goes here --></div>
</div>
<!-- Used to display form errors -->
<div id="card-errors" role="alert"></div>
</div>
<button type="submit">Pay</button>
</form>

With the new SCA regulations coming in as you mentioned in your comment, you need to use Payment methods and Payment intents now.
Basically from taking a look at your sample code you will need to rewrite pretty much everything (if you haven't already)
Their current docs are here -> https://stripe.com/docs/payments/checkout
The reason for Payment Intents and Payment methods is due to SCA - https://stripe.com/docs/strong-customer-authentication
They have a migration guide too which can be found on the side bar.
However from their examples this is how you would create your new payment intent
$intent = \Stripe\PaymentIntent::create([
'amount' => 1099,
'currency' => 'gbp',
]);
Here is also their guide for migrating from the charges API - it has a tab for stripe.js V2 if you've been using it https://stripe.com/docs/payments/payment-intents/migration

I agree. We have been using Stripe Checkout for about a year. The original implementation was dead easy. Trying to migrate to SCA compliant code is just a mess. Their online Chat is useless, and from the response in Chat, they bascially don't care if you stay with them or go.
We're going to revert to PayPal which we used before and look for an alternative payment processor.

Related

Stripe avoid paymentintent with status 'Incomplete'

I am using Stripe's 'Payment' element for creating paymentintent and card charges, Using PHP, HTML & JS.
https://stripe.com/docs/payments/payment-element
a) As soon as i load the payment page, Stripe generates a paymentintent with status 'Incomplete'.
b) After i enter Credit Card details and hit 'pay', Stripe again issues a second paymentintent with status accordingly (say 'Succeeded')
The result is, that my Dashboard is now full of unnecessary records
This is, because i initialize the $paymentIntent = \Stripe\PaymentIntent::create as soon as the page loads.
I understand that this is Stripe default behaviour, because at that moment, no payment_method is attached yet.
My question is: How is this resolved best, to avoid such 'Incomplete' records?
Maybe attach an object and fire the paymentintent creation only when
that object is present?
Or onclick of the 'pay' button..awaiting paymentintent, confirm presence and then submit the form?
Or retrieve that 1st paymentintent, store it and then update with
form submission?
create.php
header('Content-Type: application/json');
try {
// retrieve JSON from POST body
$jsonStr = file_get_contents('php://input');
$jsonObj = json_decode($jsonStr);
// Create a PaymentIntent with amount and currency
$paymentIntent = \Stripe\PaymentIntent::create([
'amount' => 1000,
'currency' => 'eur',
'receipt_email' => 'whatever#mail.com',
'automatic_payment_methods' => ['enabled' => true,],
'description' => 'Reservation Dimi123 / Name: John Doe',
'metadata' => ['order_id' => '12345']
]);
$output = [
'clientSecret' => $paymentIntent->client_secret,
];
echo json_encode($output);
} catch (Error $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
script.js
const stripe = Stripe("pk_test_..");
let elements;
initialize();
checkStatus();
document
.querySelector("#payment-form")
.addEventListener("submit", handleSubmit);
// Fetches a payment intent and captures the client secret
async function initialize() {
const { clientSecret } = await fetch("../create.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
}).then((r) => r.json());
elements = stripe.elements({ clientSecret });
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
}
async function handleSubmit(e) {
e.preventDefault();
setLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
return_url: "https://localhost/stripe/prebuilt-checkout-custom-flow/public/checkout.html",
},
});
if (error.type === "card_error" || error.type === "validation_error") {
showMessage(error.message);
} else {
showMessage("An unexpected error occurred.");
}
setLoading(false);
}
How to Avoid Incomplete Payment Intents? You don't.
his is how the system is designed to function since you need the client_secret from the Payment Intent (or Setup Intent) to render the Payment Element. There is no negative impact to your account.
You should feel comfortable ignoring them. You can adjust the filters in your Payments tab to not see them. They aren't a great metric of individual customers coming to your payment interface and navigating away since any user refreshing their browser would trigger a new one.

Stripe PaymentIntent PHP client_secret resolved to null

I am trying to integrate Stripe in a php project and all is working fine except the fact that the payment intent client_secret is always null and I actually know why but couldn't figure how to fix it, I am using a javascript file in which there is a listener for the submit button for the payment intent creation. The problem is that the listener try to fetch the json data before its creation, the client_secret value is null because I am setting its value just after creating the payment intent, how could solve this? any advice could help, thanks.
Here is the code I wrote:
intent.php:
$intent= \Stripe\PaymentIntent::create(
array(
'amount' => $price + ($price * $tva),
'currency' => 'EUR',
'setup_future_usage' => 'off_session',
)
);
$intentcls=$intent->client_secret;
intent.js:
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
var response = fetch('/secret').then(function(response) {
return response.json();
}).then(function(responseJson) {
var clientSecret = responseJson.client_secret;
stripe.confirmCardPayment(
clientSecret,
{
payment_method: {card: card}
}
).then(function(result) {
if (result.error) {
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
var errorElement = document.getElementById('card-errors');
errorElement.textContent = 'Paiement effectué avec succées';
stripeTokenHandler(result.token);
}
});
secret.php:
echo json_encode(array('clientsecret' => $intentcls));
You'll need to rearrange your logic to ensure the PaymentIntent is created before (or during) your fetch request to the backend.
If you already know the amount, you could create the PaymentIntent on page load.
A better solution is to create it when the call to /secret is made, then return the client_secret after the creation call to the Stripe API is complete.
secret.php could be:
$intent = \Stripe\PaymentIntent::create(
array(
'amount' => $amount, // calculate amount before this block
'currency' => 'EUR',
'setup_future_usage' => 'off_session',
)
);
echo json_encode(array('client_secret' => $intent->client_secret));
// perhaps store the ID in your database here

How to make Stripe Checkout V3 SCA ready

I'm using the below script to take payments via Stripe checkout V3. I was hoping this would make my payments SCA Ready, however i'm being told my payments are still not SCA ready. Am i missing some code from the below?
var stripe = Stripe('XXXX');
var elements = stripe.elements();
var card = elements.create('card', {
style: style
});
// Add an instance of the card Element into the `card-element` <div>
card.mount('#card-element');
// Handle real-time validation errors from the card Element.
card.addEventListener('change', function (event) {
var displayError = document.getElementById('card-errors');
if (event.error) {
displayError.textContent = event.error.message;
} else {
displayError.textContent = '';
}
});
// Handle form submission
var form = document.getElementById('payment-form');
form.addEventListener('submit', function (event) {
event.preventDefault();
stripe.createToken(card).then(function (result) {
if (result.error) {
// Inform the user if there was an error
var errorElement = document.getElementById('card-errors');
errorElement.textContent = result.error.message;
} else {
stripeTokenHandler(result.token);
}
});
});
// Send Stripe Token to Server
function stripeTokenHandler(token) {
// Insert the token ID into the form so it gets submitted to the server
var form = document.getElementById('payment-form');
// Add Stripe Token to hidden input
var hiddenInput = document.createElement('input');
hiddenInput.setAttribute('type', 'hidden');
hiddenInput.setAttribute('name', 'stripeToken');
hiddenInput.setAttribute('value', token.id);
form.appendChild(hiddenInput);
// Submit form
form.submit();
}
Here is my charge code ...
\Stripe\Stripe::setApiKey('XXXX');
$error = '';
$success = '';
try {
if (!isset($_POST['stripeToken']))
throw new Exception("The Stripe Token was not generated correctly");
$charge = \Stripe\Charge::create(
array(
'amount' => $_POST['stripeAmount'],
'currency' => 'gbp',
'source' => $_POST['stripeToken'],
"receipt_email" => $_SESSION["email"],
'description' => 'Booking - ' . $_SESSION['description'],
)
);
To be SCA compliant you need to be using the paymentIntents API
Your current code suggests you are using the charges-api.
There is a full migration guide here.
Basically you need to replace calls from the client:
stripe.createToken(card)
with:
stripe.createPaymentMethod(
'card',
cardElement
)
and calls in the server from:
$charge = \Stripe\Charge::create([
'source' => $json_obj->token_id,
'amount' => 1099,
'currency' => 'eur',
]);
to
$intent = \Stripe\PaymentIntent::create([
'payment_method' => $json_obj->payment_method_id,
'amount' => 1099,
'currency' => 'eur',
'confirmation_method' => 'manual',
'confirm' => true,
]);
After that you need to handle possible additional actions as explained here

Stripe Checkout charging a card

I have this code that works great.
<input class="form-control"
type="number"
id="custom-donation-amount"
placeholder="50.00"
min="0"
value="50"
step="10.00"/>
<script src="https://checkout.stripe.com/checkout.js"></script>
<button id="customButton" class="pay-button">
<h4 class="donate-text button">Donate by
<img src="http://#/testing/credit-card.png" ></h4>
</button>
<script>
var handler = StripeCheckout.configure({
key: 'pk_test_mytestingkey',
image: '',
locale: 'auto',
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id`
}
});
$('#customButton').on('click', function(e) {
// Open Checkout with further options
var amount = $("#custom-donation-amount").val() * 100;
handler.open({
name: 'Testing',
description: 'Testing',
amount: amount
});
e.preventDefault();
});
// Close Checkout on page navigation
$(window).on('popstate', function() {
handler.close();
});
</script>
It states on the documentation:
"On your server, grab the Stripe token in the POST parameters submitted by your form. From there, it's one simple API call to charge the card:"
I am trying to CHARGE the card information. Stripe provides the following API call to do that: I am assuming this is a charge.php file?
// Set your secret key: remember to change this to your live secret key in production
// See your keys here https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey("sk_test_mykey");
// Get the credit card details submitted by the form
$token = $_POST['stripeToken'];
// Create the charge on Stripe's servers - this will charge the user's card
try {
$charge = \Stripe\Charge::create(array(
"amount" => 1000, // amount in cents, again
"currency" => "usd",
"source" => $token,
"description" => "Example charge"
));
} catch(\Stripe\Error\Card $e) {
// The card has been declined
}
My question: how do I charge the card using the following code without there being a <form> method post, or <form> action...? It's using javascript to capture the token. But I don't know how to send that token to a charge.php file... Basically how do I grab that stripe token and initiate the API call? How do I initiate the API call....?
You should have a charge.php file on your server and use $.post to send to the token to the php.
// make sure you have the right path to charge.php
// pass the token to the php file with POST, your php is expecting $_POST['stripeToken']
token: function(token) {
// Use the token to create the charge with a server-side script.
// You can access the token ID with `token.id
$.post( "charge.php", { stripeToken: token.id})
// check if it worked
.done(function( data ) {
console.log( "Card charged: " + data );
});
}
Your charge.php file, make sure you installed the Stripe PHP library
<?
// composer require stripe/stripe-php
require 'vendor/autoload.php';
// Set your secret key: remember to change this to your live secret key in production
// See your keys here https://dashboard.stripe.com/account/apikeys
\Stripe\Stripe::setApiKey("sk_test_mykey");
// Get the credit card details submitted by the form
$token = $_POST['stripeToken'];
// Create the charge on Stripe's servers - this will charge the user's card
try {
$charge = \Stripe\Charge::create(array(
"amount" => 1000, // amount in cents, again
"currency" => "usd",
"source" => $token,
"description" => "Example charge"
));
} catch(\Stripe\Error\Card $e) {
// The card has been declined
}
?>
Like you say, you need to generate a Stripe token and do a form post. Without a valid token you can not charge the card.
Here's a guide on how to create custom forms with Stripe, including how to generate a token:
https://stripe.com/docs/custom-form
An easier way is to simply embed their ready-to-use checkout:
https://stripe.com/docs/checkout/tutorial
If your are using mamp. UPDATE TO MAMP 4
stripes API no longer supports older versions of MAMP.

How to pass stripe token to the server, create a user account, charge the credit card and have it all show up on the dashboard

So I'm trying to get stripe setup on my server but I'm having a problem.
I'm using checkout v2 on my page and the form works perfectly, however the token never passes through to my php file. the card is charged but the information does not show up on the dashboard, it is in the log though.
here's what I have:
<form action="assets/php/slingshot.php" method="POST">
<button id="customButton">Purchase</button>
<script>
$('#customButton').click(function(){
var token = function(res){
var $input = $('<input type=hidden name=stripeToken />').val(res.id);
$('form').append($input).submit();
};
StripeCheckout.open({
key: 'pk_live_*************************',
address: true,
amount: 2500,
currency: 'usd',
name: 'test',
description: 'A bag of test',
panelLabel: 'Checkout',
token: token
});
return false;
});
</script>
</form>
and then for slingshot.php:
<?php
require_once(dirname(__FILE__) . '/config.php');
$token = $POST['stripeToken']; //get the creditcard details from the form
try {
$charge = Stripe_Charge::create(array(
'card' => $token,
'amount' => 2500, //amount in cents
'currency' => 'usd',
'description' => 'Get Bacon Direct, LLC'
));
} catch(Stripe_CardError $e) {
// The card has been declined
}
echo '<h1>Successfully charged $25.00 </h1>';
}
?>
and my config.php file:
<?php
require_once('stripe-php/lib/Stripe.php');
// 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 = array(
"secret_key" => "sk_live_************************************",
"publishable_key" => "pk_live_************************************"
);
Stripe::setApiKey($stripe['secret_key'] );
?>
could you please help me out?
I'm not entirely sure how the charge is being made, but I'm fairly confident that the reason you aren't getting the token, is because of this line
$token = $POST['stripeToken']; //get the creditcard details from the form
When accessing POST data in PHP, the global variable is prefixed with an underscore, so you'd need to do
$token = $_POST['stripeToken']; //get the creditcard details from the form
That should fix it.
-- UPDATE ---
Just for readability, in your javascript, I would specify the input field as follows
var $input = $('<input type="hidden" name="stripeToken" />').val(res.id);
I've also checked out the stripe documentation again, and it looks like the card attribute is optional, as is customer, but it does state that one must be provided. Chances are, it's not throwing an error because of an issue with their code that doesn't catch the eventuality of neither being provided.

Categories