Reputation: 51
I am trying to implement the payment intent api and i kept getting the invalid payment intent status, i saw an answer on stack-overflow but it doesn't help, i don't know if its a bad server side or client side implementation, as i am still new to this
I have tried changing the requires_action to requires_source_action, under the charges but nothing help, tried modifying the html, but i don't know what is wrong.
in charge, i have
<?php
# vendor using composer
require_once('vendor/autoload.php');
\Stripe\Stripe::setApiKey(getenv('sk_test_HERE'));
header('Content-Type: application/json');
# retrieve json from POST body
$json_str = file_get_contents('php://input');
$json_obj = json_decode($json_str);
//$amount=$POST['amount'];
//----------------🤒 changed the intent from null;
$intent = null;
try {
if (isset($json_obj->payment_method_id)) {
# Create the PaymentIntent
$intent = \Stripe\PaymentIntent::create([
'payment_method' => $json_obj->payment_method_id,
'amount' => 1000,
'currency' => 'eur',
'confirmation_method' => 'manual',
'confirm' => true,
]);
}
if (isset($json_obj->payment_intent_id)) {
$intent = \Stripe\PaymentIntent::retrieve(
$json_obj->payment_intent_id
);
$intent->confirm();
}
generatePaymentResponse($intent);
} catch (\Stripe\Error\Base $e) {
# Display error on client
echo json_encode([
'error' => $e->getMessage()
]);
}
//--------------------updated from requires action to requires source action
function generatePaymentResponse($intent) {
# Note that if your API version is before 2019-02-11, 'requires_action'
# appears as 'requires_source_action'.
if ($intent->status == 'requires_source_action' &&
$intent->next_action->type == 'use_stripe_sdk') {
# Tell the client to handle the action
echo json_encode([
'requires_action' => true,
'payment_intent_client_secret' => $intent->client_secret
]);
} else if ($intent->status == 'succeeded') {
# The payment didn’t need any additional actions and completed!
# Handle post-payment fulfillment
echo json_encode([
"success" => true
]);
} else {
# Invalid status
http_response_code(500);
echo json_encode(['error' => 'Invalid PaymentIntent status']);
}
}
?>
in the JavaScript file i have
// Create a Stripe client.
var stripe = Stripe('pk_test_HERE');
// Create an instance of Elements.
var elements = stripe.elements();
// Custom styling can be passed to options when creating an Element.
// (Note that this demo uses a wider set of styles than the guide below.)
var style = {
base: {
color: '#32325d',
fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
fontSmoothing: 'antialiased',
fontSize: '16px',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#fa755a',
iconColor: '#fa755a'
}
};
// Create an instance of the card Element.
var card = elements.create('card', {style: style});
// Add an instance of the card Element into the `card-element` <div>.
// added an extra s for form control
card.mount('#card-elements');
// 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 {
// Send the token to your server.
stripeTokenHandler(result.token);
}
});
});
// Submit the form with the token ID.
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();
}
and this to collect the details, forgive me if you see any amateurish thing
<div class="container">
<h2 class="my-4 text-center">Service Payments</h2>
<form action="./charge.php" method="post" id="payment-form">
<div class="form-row">
<input type="text" name="first_name" class="form-control mb-3 StripeElement StripeElement--empty" placeholder="First Name" required>
<input type="text" name="last_name" class="form-control mb-3 StripeElement StripeElement--empty" placeholder="Last Name" required>
<!-- <label for="t2">What's your e-mail?</label> -->
<input type="email" name="email" id="t2" class="form-control mb-3 StripeElement StripeElement--empty" placeholder="Email Address" required>
<input type="amount" name="amount" class="form-control mb-3 StripeElement StripeElement--empty" placeholder="1000 translates to 10.00" required>
<!-- changed card element to elements with an s, form control is another possible option -->
<input id="cardholder-name" type="text">
<div id="card-elements" class="form-control">
<!-- / a Stripe Element will be inserted here. / -->
</div>
<!-- Used to display form errors -->
<div id="card-errors" role="alert"></div>
</div>
<button id="card-button" data-secret="<?= $intent->client_secret ?>">Submit Payment</button>
</form>
</div>
i keep getting the error: invalid payment intent status
Upvotes: 2
Views: 8628
Reputation: 5847
Looks like you might be working off older docs. You are getting "invalid payment intent status" because your code is looking for the status requires_source_action
, which doesn't exist: https://stripe.com/docs/payments/intents#intent-statuses
The actual status is probably requires_confirmation
, in which case you'll have to confirm the PaymentIntent on your server. Then depending on the status you either get the requires_action
status or succeeded
. Which one you get depends on whether the card in question requires 3DS or not.
Because your PaymentIntent is using the manual confirmation flow, it means you have to do several round trips between front and backend before a payment is actually completed. I recommend looking into using automatic confirmation instead. That way you have only 2 steps:
handleCardPayment
to complete the paymentMore info on that flow here: https://stripe.com/docs/payments/payment-intents/quickstart#automatic-confirmation-flow
Unless you have a good reason to use manual confirmation, I'd stick with automatic.
Upvotes: 2