Stripe/PHP: Handling Customer object succeeds but charging fails (4000000000000341) - php

In Stripe, the test number 4000 0000 0000 0341 simulates, per the Stripe Testing page, a situation where "Attaching this card to a Customer object succeeds, but attempts to charge the customer fail." In my case, I want to treat this situation like an error and send it to the error handler rather than report to the customer that the charge succeeded.
I'm doing this in PHP, so I'm not getting the JSON object from the API but rather a PHP object for the customer. I'm new to the Stripe API so I don't know what else I should be doing here. I tried searching for info about this situation and couldn't find anything helpful. And it doesn't look like this case was handled by existing SO questions.
The excerpt from the code is below. I need to set $charge_failed to true if the customer was not charged.
\Stripe\Stripe::setApiKey(STRIPE_SECRET_KEY);
// Create a customer.
try {
$customer = \Stripe\Customer::create(array( "source" => $my_token, 'email' => $customers_email, "description" => $my_description ));
$charge_failed = false; //TODO Set this boolean according to whether the charge passed or failed.
if ($charge_failed) {
//TODO Report to the user that the charge failed and they need to resubmit.
die();
}
}
catch(\Stripe\Error\Card $e) {
// Card was declined. Report the card declined to the user.
die();
}
catch (\Stripe\Error\RateLimit $e) {
// Report the error appropriately.
die();
} catch (\Stripe\Error\InvalidRequest $e) {
// Report the error appropriately.
die();
} catch (\Stripe\Error\Authentication $e) {
// Report the error appropriately.
die();
} catch (\Stripe\Error\ApiConnection $e) {
// Report the error appropriately.
die();
} catch (\Stripe\Error\Base $e) {
// Report the error appropriately.
die();
} catch (Exception $e) {
// Report the error appropriately.
die();
}

Before some days I implemented stripe successfully. Check below hope this will help.
if ($params['testmode'] == "on") {
\Stripe\Stripe::setApiKey($params['private_test_key']);
$pubkey = $params['public_test_key'];
} else {
\Stripe\Stripe::setApiKey($params['private_live_key']);
$pubkey = $params['public_live_key'];
}
include_once 'Stripe/init.php';
include_once 'Stripe/lib/Stripe.php';
//Set Stripe keys
$params = array(
"testmode" => "off",
"private_live_key" => "sk_live_",
"public_live_key" => "pk_live_",
"private_test_key" => "sk_test_",
"public_test_key" => "pk_test_"
);
if ($params['testmode'] == "on") {
\Stripe\Stripe::setApiKey($params['private_test_key']);
$pubkey = $params['public_test_key'];
} else {
\Stripe\Stripe::setApiKey($params['private_live_key']);
$pubkey = $params['public_live_key'];
}
if (isset($_POST['stripeToken'])) {
try {
$customer = \Stripe\Customer::create(array(
'email' => $varUserEmail,
'source' => $_POST['stripeToken']
));
$charge = \Stripe\Charge::create(array(
'customer' => $customer->id,
'amount' => $price,
'currency' => 'usd',
'description' => $description,
));
$result = "success";
//Save information in the database and send an email with status
//Ends here
} catch (\Stripe\Error\Card $e) {
$error = $e->getMessage();
$result = "declined";
//Save information in the database and send an email with status
}

I could be wrong but I believe that this situation occurs only if you already have an existing customer object and you are attempting to update their payment method. Your token you are using to create a customer will be invalid prior to attempting the customer creation and customer creation will fail. If this is an initial charge, the javascript method will return a failure.

Related

Why is my Stripe Charge suddenly not working?

Has Stripe changed something? I have used this code snippet before and now suddenly there is error (Exception $e)? This error is appearing suddenly have fought with in for an hour now
try {
//Charge the Card
$charge = \Stripe\Charge::create(array(
"customer" => $stripe_account,
"amount" => 450,
"currency" => "eur",
'capture' => true),
);
$chargeID = $charge->id;
} catch (\Stripe\Error\InvalidRequest $e) {
//Send User to Error Page
echo json_encode(array("statusCode"=>205));
exit();
} catch (\Stripe\Error\Base $e) {
//Send User to Error Page
echo json_encode(array("statusCode"=>205));
exit();
} catch(\Stripe\Error\Card $e) {
// Since it's a decline, \Stripe\Error\Card will be caught
echo json_encode(array("statusCode"=>205));
//Send User to Error Page
exit();
} catch (Exception $e) {
//Send User to Error Page
echo json_encode(array("statusCode"=>205));
//Send User to Error Page
exit();
}
This issues was fixed by changing the API key. Which makes no sense i've been in contact with Stripe which is now researching this. But it works now.

Slim 3 - Multiple request issue

I am setting up a small Slim 3 application which will be the middleman for processing Web based Stripe payment form. The Slim application will handle the business logic of reaching out to Stripe and conducting the payment, as well as sending the payment data off to some third-party CRM / Applications.
My issue during testing is that when i make a test payment through the StripeJS payment form the slim application is actually logging 3 duplicate requests 1-second apart. Here's what the logging looks like:
test#gmail.com Attempting to make payment 2020-04-27 05:34:39
test#gmail.com Attempting to make payment 2020-04-27 05:34:40
test#gmail.com Attempting to make payment 2020-04-27 05:34:41
test#gmail.com Payment success 2020-04-27 05:34:44
test#gmail.com Payment success 2020-04-27 05:34:45
test#gmail.com Payment success 2020-04-27 05:34:47
This is all from an individual "payment" using the Stripe Test credentials.
The Slim layout is fairly straightforward in terms of the route passing the request directly to my StripeController class. The StripeController class ( in development ) will take the values of the request and pass it to the Stripe API to conduct the payment.
The route layout:
$this->post('/stripe-payment', 'StripeController:stripePayment');
The controller (stripped to essentials for privacy ):
class StripeController extends Controller
{
private $privateKey;
private $httpClient;
public function __construct() {
$this->privateKey = getenv('STRIPE_KEY');
$this->httpClient = new Client();
\Stripe\Stripe::setApiKey($this->privateKey);
}
//
public function stripePayment($request, $response)
{
// Get the request body
$r = (object)$request->getParsedBody();
// Initial Logging
$log = new LogController($r->email_address, 'Attempting to make payment');
$log->saveLog();
// Attempt to find an existing user
$user = User::where('email', $r->email_address)->first();
if($user !== null) {
// If user exists, use their StripeID
$invoice = $this->stripeInvoice($r, $user->stripe_id);
// Log the transaction
$this->savePayment( $user->id, 'stripe-invoice', $invoice->id, $invoice->amount_paid );
// Third party application push
$this->pushUser($r, $invoice->amount_paid);
// Return with success
return $response->withRedirect('example.com/payment-success/');
} else {
// Same as above, just create a user then push.
}
}
public function stripeInvoice(object $r, string $stripe_id)
{
// Try to create the invoice in stripe
try {
\Stripe\InvoiceItem::create([
'customer' => $stripe_id,
'amount' => (int)$r->product,
'currency' => 'USD',
'description' => $plan_desc
]);
} catch ( Exception $e ) {
error_log('STRIPE_INVOICE_EXCEPTION: '.$e->getMessage());
}
// Try to charge the customer the invoice we just created
try {
$invoice = \Stripe\Invoice::create([
'customer' => $stripe_id
]);
$_get_invoice = \Stripe\Invoice::retrieve($invoice->id);
$_get_invoice->pay();
$success = 1;
// Use Stripe's library to make requests...
} catch(\Stripe\Exception\CardException $e) {
$error = $e->getMessage();
// Since it's a decline, \Stripe\Exception\CardException will be caught
} catch (\Stripe\Exception\RateLimitException $e) {
$error = $e->getMessage();
// Too many requests made to the API too quickly
} catch (\Stripe\Exception\InvalidRequestException $e) {
$error = $e->getMessage();
// Invalid parameters were supplied to Stripe's API
} catch (\Stripe\Exception\AuthenticationException $e) {
$error = $e->getMessage();
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
} catch (\Stripe\Exception\ApiConnectionException $e) {
$error = $e->getMessage();
// Network communication with Stripe failed
} catch (\Stripe\Exception\ApiErrorException $e) {
$error = $e->getMessage();
// Display a very generic error to the user, and maybe send
// yourself an email
} catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
$error = $e->getMessage();
}
if($success != 1) {
return $response->withRedirect('example.com&error='.$error);
} else {
return $_get_invoice;
}
}
}
Is there anything that Slim is doing in the background, like an origin check, that could be causing the duplication issue ?

stripe, multiple requests using idempotency keys return errors

Need assistance with Stripe error response.
Everything seems to work according to stripe dashboard logs when creating a Customer and then enrolling them into a Subscription therefore generating a Charge, in the event where there are multiple requests made with idempotency keys in place.
How ever in this event I get this stripe error response (capture of the exception $error6) which opens up as a page (charge.php) where the code runs, instead of sending to success page.
charge.php
\Stripe\Stripe::setApiKey('sk_live_xxxxxxxxxxx');
$POST = filter_var_array($_POST, FILTER_SANITIZE_STRING);
$email = $POST['email'];
$token = $POST['stripeToken'];
$membership_type = $POST['membership_type'];
$user_id = $POST['user_id'];
$success = 0;
try {
// Create customer in Stripe
$customer = \Stripe\Customer::create([
"email" => $email,
"source" => $token,
],[
"idempotency_key" => $_SESSION['sid2'],
]);
$success = 1;
} catch(Stripe_CardError $e) {
$error1 = $e->getMessage();
} catch (Stripe_InvalidRequestError $e) {
// Invalid parameters were supplied to Stripe's API
$error2 = $e->getMessage();
} catch (Stripe_AuthenticationError $e) {
// Authentication with Stripe's API failed
$error3 = $e->getMessage();
} catch (Stripe_ApiConnectionError $e) {
// Network communication with Stripe failed
$error4 = $e->getMessage();
} catch (Stripe_Error $e) {
// Display a very generic error to the user, and maybe send
// yourself an email
$error5 = $e->getMessage();
} catch (Exception $e) {
// Something else happened, completely unrelated to Stripe
$error6 = $e->getMessage();
}
if ($success!=1)
{
$_SESSION['error1'] = $error1;
$_SESSION['error2'] = $error2;
$_SESSION['error3'] = $error3;
$_SESSION['error4'] = $error4;
$_SESSION['error5'] = $error5;
$_SESSION['error6'] = $error6;
print_r($_SESSION);
}
// Add Customer to a Subscription in Stripe
$subscription = \Stripe\Subscription::create([
'customer' => $customer->id,
'items' => [['plan' => $membership_type]]
],[
"idempotency_key" => $_SESSION['sid'],
]);
//adding all relevent info into data base...
//send user to success page
header('Location: ../success.php?id='.$user_id.'&product='.$subscription->plan->nickname);
Could this be because each time the Stripe JS $token parameter changes? is this normal or am I doing something wrong? (I got a similar error when running idempotency only on Subscribing a Customer but then stripe creates multiple customers with the same email and payment cards but different customer->id)
Can anyone kindly suggest how can I resolve this error page?
Could this be because each time the Stripe JS $token parameter changes?
Yes, I suspect what's happening here is that you are reusing $_SESSION['sid2'] for two separate requests with different source parameters to create a Customer. And this error in response is the expected behavior!
You should be able to see this in your Dashboard logs: Assuming this is a test mode request, https://dashboard.stripe.com/test/logs/iar_IgylJRGpbLyVb6 should tell you where the same key was originally used.
best option i could find is disabling the button after the Stripe JS event listener
var form = document.getElementById('payment-form');
form.addEventListener('submit', function(event) {
event.preventDefault();
$('.button').attr("disabled", true);
stripe.createToken(card).then(function(result) {...........

Stripe cannot make new subscriptions after canceling a subscription

Ok... I have customer bob. His user id is 1.
Bob is already a customer in Stripe and he already has a subscription.
I want to cancel his subscription so I do this:
$sub = \Stripe\Subscription::retrieve($subscriptionId);
$sub->cancel();
that works.
now I want to resubscribe him to a plan (doesn't matter which plan, any paid plan)... I put it in a try catch: so I do this:
try {
$subscription = \Stripe\Subscription::create(array(
"customer" => $customerId, // bob's id is 1
"plan" => "premium-plan"
));
} catch (\Stripe\Error\ApiConnection $e) {
} catch (\Stripe\Error\InvalidRequest $e) {
// Error is here
} catch (\Stripe\Error\Api $e) {
} catch (\Stripe\Error\Card $e) {
}
the error I get is here: \Stripe\Error\InvalidRequest $e
what could be wrong?

stripe connect Error of Uncaught exception 'Stripe\Error\Authentication' with message 'The provided key 'sk_test_' does not have access to account

\Stripe\Stripe::setApiKey("sk_test_someString");
$charge = \Stripe\Charge::create(
array(
"amount" => 5000, // amount in cents
"currency" => "usd",
"source" => $token,
"description" => "Example charge",
"application_fee" => 123 // amount in cents
),
array("stripe_account" => CONNECTED_STRIPE_ACCOUNT_ID)
);
} catch(\Stripe\Error\Card $e) {
// The card has been declined
}
catch (\Stripe\Error\ApiConnection $e) {
// Network problem, perhaps try again.
} catch (\Stripe\Error\InvalidRequest $e) {
// You screwed up in your programming. Shouldn't happen!
} catch (\Stripe\Error\Api $e) {
// Stripe's servers are down!
} catch (\Stripe\Error\Card $e) {
// Card was declined.
}
Everything I have done so far:
Create a custom form add all the necessary coding provided by stripe
add the latest php stripe dependency
Add the localhost url to my stripe connect
The problem is after I connect by clicking the connect with stripe button
Then use the demo card and post a request such error comes back an also no
charge occur. In the logs I see the post but no Parsed Request Query Parameters. Can some one tell me what am I doing wrong

Categories