PHP - Retrieve existing stripe customer and their cards? - php

I'm successfully able to create a new customer in Stripe via my PHP backend. That being said, when my user wants to view their existing cards, the PHP below just creates another new user and ephemeral key. If I already have a customer ID, how can I change my below code to make it so that if I'm providing the customer ID, existing cards are returned? Help is greatly appreciated!
if (!isset($_POST['api_version']))
{
header('HTTP/1.1 400 Bad Request');
}
//USER DETAILS
$email = $_POST['email'];
$customer = \Stripe\Customer::create(array(
'email' => $email,
));
try {
$key = \Stripe\EphemeralKey::create(
["customer" => $customer->id],
["stripe_version" => $_POST['api_version']]
);
header('Content-Type: application/json');
exit(json_encode($key));
} catch (Exception $e) {
header('HTTP/1.1 500 Internal Server Error');
}

You need to store the customer id you get back from stripe the first time you create a customer and then you can retrieve the user with:
\Stripe\Customer::retrieve($customer_id);
Something like this:
$customer_id = $_POST['customer_id']; //get this id from somewhere a database table, post parameter, etc.
// if the customer id doesn't exist create the customer
if ($customer_id !== null) {
// create the customer as you are now
} else {
$cards = \Stripe\Customer::retrieve($customer_id)->sources->all()
// return the cards
}

Related

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/PHP: Handling Customer object succeeds but charging fails (4000000000000341)

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.

How to use westpac PAYWAY API

hi i am using stripe api for payment using this tutorial
http://code.tutsplus.com/tutorials/so-you-want-to-accept-credit-cards-online--net-25457
But i am getting this error
pay.php 500 (Internal Server Error)
here it is pay.php code
<?php
// Helper Function: used to post an error message back to our caller
function returnErrorWithMessage($message)
{
$a = array('result' => 1, 'errorMessage' => $message);
echo json_encode($a);
}
// Credit Card Billing
require_once('Stripe.php'); // change this path to wherever you put the Stripe PHP library!
$trialAPIKey = ""; // These are the SECRET keys!
$liveAPIKey = "";
Stripe::setApiKey($trialAPIKey); // Switch to change between live and test environments
// Get all the values from the form
$token = $_POST['stripeToken'];
$email = $_POST['email'];
$firstName = $_POST['firstName'];
$lastName = $_POST['lastName'];
$price = $_POST['price'];
$priceInCents = $price * 100; // Stripe requires the amount to be expressed in cents
try
{
// We must have all of this information to proceed. If it's missing, balk.
if (!isset($token)) throw new Exception("Website Error: The Stripe token was not generated correctly or passed to the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
if (!isset($email)) throw new Exception("Website Error: The email address was NULL in the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
if (!isset($firstName)) throw new Exception("Website Error: FirstName was NULL in the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
if (!isset($lastName)) throw new Exception("Website Error: LastName was NULL in the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
if (!isset($priceInCents)) throw new Exception("Website Error: Price was NULL in the payment handler script. Your credit card was NOT charged. Please report this problem to the webmaster.");
try
{
// create the charge on Stripe's servers. THIS WILL CHARGE THE CARD!
$charge = Stripe_Charge::create(array(
"amount" => $priceInCents,
"currency" => "usd",
"card" => $token,
"description" => $email)
);
// If no exception was thrown, the charge was successful!
// Here, you might record the user's info in a database, email a receipt, etc.
// Return a result code of '0' and whatever other information you'd like.
// This is accessible to the jQuery Ajax call return-handler in "buy-controller.js"
$array = array('result' => 0, 'email' => $email, 'price' => $price, 'message' => 'Thank you; your transaction was successful!');
echo json_encode($array);
}
catch (Stripe_Error $e)
{
// The charge failed for some reason. Stripe's message will explain why.
$message = $e->getMessage();
returnErrorWithMessage($message);
}
}
catch (Exception $e)
{
// One or more variables was NULL
$message = $e->getMessage();
returnErrorWithMessage($message);
}
?>
even i can't access strip's php files.
Please any idea?
Thanks

stripe api checking for existing card

I'm sure I'm missing something obvious here, but I can't get my head around how to check for an existing card against a customer.
I'm using the stripe connect api within an laravel app to manage payments on behalf of others, and the basic process is as follows:
a stripe token is created via stripe.js and submitted with the payment form
if the customer exists in the local database, I grab their stripe_id, otherwise a new customer is created using the token as the source/card
a charge is then created using the retrieved or new customer stripe_id
Currently, if the customer returns and uses a different card, as the charge only includes a customer, not source, it'll be charged against their default card regardless.
What I'd like to do is:
create a stripe token
check customer against local database etc
check card fingerprint against customer's cards
if necessary, create new card on customer's record
create charge using both customer and card ids
Simply put: I can't see where in the process a persistent card_id is generated; both those used in the stripe.js response, and when created in the stripe dashboard, appear to be unique, meaning every charge creates a brand-new card object in stripe.
I know I can retrieve a list of cards stored against a customer's account - but where do I get the initial card_id from to search against?
I've seen a question that touches on this here - Can I check whether stripe a card is already existed before going to create new one? - but I don't know Ruby, so can't make head nor tail of it.
EDIT:
Simpler version - is there a way to get the fingerprint as described in the stripe docs here - https://stripe.com/docs/api/php#card_object - without having to first create a card object ?
So the idea here would be to use the fingerprint on the Card object or the Token object and not the id itself as those would be different if you add the same card multiple times.
When you get a new card token you can retrieve it through the Retrieve Token API and look for the fingerprint in the card hash.
You would keep a list of known fingerprints in your database associated with a specific customer and/or card so that you can detect duplicate cards.
NOTE: make sure you are using the secret keys to get those information. otherwise if you are using the publishable key, you might not get the fingerprint value.
I created a function to do this:
$customer is the stripe customer object
$stripe_account is either your account's stripe ID or the connected account's stripe ID
$token comes from stripe.js elements
$check_exp allows you to decide if you want to check the card's expiration date as well, because the fingerprint does not change if the card's number is the same
stripe PHP API 7.0.0
function check_duplicate_card($customer, $stripe_account, $token, $check_exp) {
$loc = "check_duplicate_card >> ";
$debug = true;
if ($debug) {
// see here for an explanation for logging: http://php.net/set_error_handler >> Examples
trigger_error("$loc started", E_USER_NOTICE);
}
try
{
// get token data
$response = \Stripe\Token::retrieve(
$token,
["stripe_account" => $stripe_account]
);
$token_fingerprint = $response->card->fingerprint;
$token_exp_month = $response->card->exp_month;
$token_exp_year = $response->card->exp_year;
if ($debug) {
trigger_error("$loc token_fingerprint = $token_fingerprint; token_exp_month = $token_exp_month; token_exp_year = $token_exp_year", E_USER_NOTICE);
}
// check for duplicate source
if ($debug) {
trigger_error("$loc customer sources = " . json_encode($customer->sources), E_USER_NOTICE);
}
$duplicate_found = false;
foreach ($customer->sources->data as &$value) {
// get data
$fingerprint = $value->fingerprint;
$exp_month = $value->exp_month;
$exp_year = $value->exp_year;
if ($fingerprint == $token_fingerprint) {
if ($check_exp) {
if (($exp_month == $token_exp_month) && ($exp_year == $token_exp_year)) {
$duplicate_found = true;
break;
}
} else {
$duplicate_found = true;
break;
}
}
}
if ($debug) {
trigger_error("$loc duplicate_found = " . json_encode($duplicate_found), E_USER_NOTICE);
}
} catch (Exception $e) {
if ($e instanceof \Stripe\Exception\ApiErrorException) {
$return_array = [
"status" => $e->getHttpStatus(),
"type" => $e->getError()->type,
"code" => $e->getError()->code,
"param" => $e->getError()->param,
"message" => $e->getError()->message,
];
$return_str = json_encode($return_array);
trigger_error("$loc $return_str", E_USER_WARNING);
http_response_code($e->getHttpStatus());
echo $return_str;
} else {
$return_array = [
"message" => $e->getMessage(),
];
$return_str = json_encode($return_array);
trigger_error("$loc $return_str", E_USER_ERROR);
http_response_code(500); // Internal Server Error
echo $return_str;
}
}
if ($debug) {
trigger_error("$loc ended", E_USER_NOTICE);
}
return $duplicate_found;
}

Stripe making multiple customers with same email address

I have stripe check out with php. It creates customers and charges them. I want to create a donation form where if same customer comes back and gives with same email address that Stripe doesn't create another customer but charges the existing customer with additional payments. Is this possible? Or does the checkout always create new customer with new customer id?
Here is my charge.php
<?php
require_once('config.php');
$token = $_POST['stripeToken'];
if($_POST) {
$error = NULL;
try{
if(!isset($_POST['stripeToken']))
throw new Exception("The Stripe Token was not generated correctly");
$customer = Stripe_Customer::create(array(
'card' => $token,
'email' => $_POST['stripeEmail'],
'description' => 'Thrive General Donor'
));
$charge = Stripe_Charge::create(array(
'customer' => $customer->id,
'amount' => $_POST['donationAmount'] * 100,
'currency' => 'usd'
));
}
catch(Exception $e) {
$eror = $e->getMessage();
}
}
?>
You will need to store the relationship between email address and Stripe customer ID in a database. I've determined this by looking at Stripe's API on Customers.
First, when creating a new customer every field is optional. This leads me to believe that every single time you POST to /v1/customers, it will "[create] a new customer object."
Also, when retrieving a customer the only field available is the id. This leads me to believe that you cannot retrieve a customer based on an email address or other field.
If you can't store this information in a database, you can always list all the customers with GET /v1/customers. This will require you to paginate through and check all customer objects until you find one with a matching email address. You can see how this would be quite inefficient if done every time you tried to create a customer.
You can list all users for a given email address.
https://stripe.com/docs/api#list_customers
In JavaScript you could do this:
const customerAlreadyExists = (email)=>{
return doGet(email)
.then(response => response.data.length > 0);
}
const doGet = (url: string)=>{
return fetch('https://api.stripe.com/v1/customers' + '?email=' + email, {
method: 'GET',
headers: {
Accept: 'application/json',
Authorization: 'Bearer ' + STRIPE_API_KEY
}
}).then(function (response) {
return response.json();
}).catch(function (error) {
console.error('Error:', error);
});
}

Categories