Stripe: change credit card number? - php

I'm using Stripe Payments and would like to give customers the possibility to change their credit card. Referring to https://stripe.com/docs/api#create_subscription -> source, I tried the following PHP-code:
$customer = \Stripe\Customer::retrieve($client_id);
$customer = \Stripe\Customer::create(array(
"source" => $token) //the token contains credit card details
);
This works, but unfortunately it unintentionally also creates a new customer ID:
The original customer ID was cus_6elZAJHMELXkKI and I would like to keep it.
Does anybody know the PHP-code that would update the card without creating a new customer?
Thank you very much in advance!
PS: Just in case you need it – this was the code that originally
created the customer and the subscription:
$customer = \Stripe\Customer::create(array(
"source" => $token,
"description" => "{$fn} {$ln}",
"email" => $e,
"plan" => "basic_plan_id")
);
\Stripe\Charge::create(array(
"amount" => 10000, # amount in cents, again
"currency" => "eur",
"customer" => $customer->id)
);

I've just found the answer, maybe it helps someone of you, too:
You can replace the old card with the new one like so:
$customer = \Stripe\Customer::retrieve($client_id);
$new_card = $customer->sources->create(array("source" => $token));
$customer->default_source = $new_card->id;
$customer->save();

The answer helped a bunch but commenter was correct that old card wasn't deleted.
Assuming you would only ever have one card for a customer you would do this instead:
//get customer
$customer = \Stripe\Customer::retrieve($client_id);
//get the only card's ID
$card_id=$customer->sources->data[0]->id;
//delete the card if it exists
if ($card_id) $customer->sources->retrieve($card_id)->delete();
//add new card
$new_card = $customer->sources->create(array("source" => $token));
$customer->default_source = $new_card->id;
$customer->save();

Related

Stripe : Add new card to already created customer

I have a stripe customer already added, I am figuring out to add new card to customer. I searched around but couldn't found anything confirmed to asnwer my following questions.
Do stripe have any form of their own to add new card ?
Is following is the correct way to add new card ?
$customer = \Stripe\Customer::retrieve(Auth::user()->stripe_key);
// Got the customer details successfully from the above call.
$card = $customer->cards->create(
array(
"card" =>
array(
"number"=> "4242424242424242",
"exp_month" => "12",
"exp_year" => "2016",
"cvc" => "123"
)
)
);
Stripe does not have a direct form specifically for adding a new card to a customer, however you can use Checkout or Elements to collect the customer's card details.
The process for adding a new card to a customer would be as follows:
Collect and tokenize the customer's card details using Checkout or Elements[0]. This will give you a Stripe token representing the card.
Send this token to your backend, where you can use something similar to the following code to save the card to the customer:
$token = $_POST['stripeToken']; #for example
$customer = \Stripe\Customer::retrieve(Auth::user()->stripe_key);
$customer->sources->create(array("source" => $token));
[0] - https://stripe.com/docs/checkout or https://stripe.com/docs/stripe-js/elements/quickstart
[1] - https://stripe.com/docs/api/php#create_card

Stripe Checkout - Subscription Issue with Recognized Stripe User

I have Stripe working great. Upon a customer's donation, a new Subscription is created, and it works great - except if Stripe recognizes the email and says, "Enter the verification code."
If the customer does that, for some reason, a new subscription is not created and the customer is not charged.
Here is my charge-monthly.php
<?php
require_once('init.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_**************");
// Get the credit card details submitted by the form
$token = $_POST['stripeToken'];
$email = $_POST['stripeEmail'];
$amount = $_POST['amount'];
$finalamount = $amount * 100;
$dollars = ".00";
$plan = "/month";
$dash = " - ";
$monthlyplan = $amount .$dollars .$plan .$dash .$email;
//Create monthly plan
$plan = \Stripe\Plan::create(array(
"name" => $monthlyplan,
"id" => $monthlyplan,
"interval" => "month",
"currency" => "usd",
"amount" => $finalamount,
));
// Create a Customer
$customer = \Stripe\Customer::create(array(
"source" => $token,
"description" => "MONTHLY DONATION",
"plan" => $monthlyplan,
"email" => $email, )
);
?>
Any ideas why when Stripe recognizes the user and he is "logged in" it does not allow me to create a subscription?
In the Stripe log, I receive this 400 error:
{
"error": {
"type": "invalid_request_error",
"message": "Plan already exists."
}
}
But there definitely isn't a plan created... ah!
The reason your request is failing is because if a user comes back with the same email address and wants to sign up for the same plan, you already have an existing plan with that name,
$monthlyplan = $amount .$dollars .$plan .$dash .$email;
so your call to \Stripe\Plan::create will return an error and cause the rest of your calls to fail here.
You could add something like a unique id or time to your plan id.
http://php.net/manual/en/function.time.php
http://php.net/manual/en/function.uniqid.php
Some other ways that folks typically handle this are:
Create a single plan for $1, and then adjust the quantity when creating your subscription. So a monthly plan for $1 with quantity of 100, would charge $100 month.
Store the amount that a customer will pay within your application. Subscribe your customers to a $0/month plan. Use webhooks to listen for invoice.created events. Have your webhook handler add an Invoice Item every month for the balance.

How to add multiple cards in same customer in stripe payment gateway using php

i was implementing stripe payment in testing mode.Here i got an error like Same token is used again. is there any different way to add multiple cards.
or i need to call retrive function in a separate page so that conflict of same token never come again.And how should i set a card default.
public function createToken($data)
{
$TokenResult=Token::create(array(
"card" => array(
"name" => $data['name'],
"number" => $data['card_number'],
"exp_month" => $data['month'],
"exp_year" => $data['year'],
"cvc" => $data['cvc']
)));
//echo "<pre>";;
//print_r($TokenResult);
$this->token=$TokenResult['id'];//store token id into token variable
$this->chargeCard($this->token); //call chargecard function via passing token id
}
/*
* function to create customer
*/
public function createCustomer($data,$token=null)//pass form data and token id
{
$customer=Customer::create(array(
"email"=>$data['email'],
"description" => $data['name'],
"source" => $token // obtained with Stripe.js
));
$customerId=$customer['id'];
$this->retriveCustomer($customerId,$token);
}
/*
* function to retrive current customers for adding multiple cards to same customers*/
public function retriveCustomer($customerid,$token)
{
echo $this->token;
//die('here');
$retriveResult=Customer::retrieve($customerid);
$retriveResult->sources->create(array("source" =>$this->token));
return $retriveResult;
}
First, please note that unless you are PCI certified and allowed to directly manipulate card data, you should never have access to card numbers in your server-side code.
Card tokens should be created client-side, via Checkout or Elements. Your server should only deal with client-side created card tokens and never with PCI-sensitive information (card numbers and CVCs). This will greatly decrease the burden of PCI compliance and make you eligible for PCI SAQ A.
In PHP, this is how you'd add a card to an existing customer object:
$customer = \Stripe\Customer::retrieve("cus_...");
$card = $customer->sources->create(array(
"source" => $token // token created by Checkout or Elements
));
I think you dont need to create a token in case of adding new card. It helps while you update certain card. So the flow of addition will be same as you created for first card.
I dont know which stripe version you are using, I am using bit old:
$card_array = array(
'card' => array(
'number' => $number,
'exp_month' => $exp_month,
'exp_year' => $exp_year,
'cvc' => $cvc,
'name' => $name
)
);
$card_obj = $this->setData("\Stripe\Customer", "retrieve", $customer_id, TRUE);
$card = $card_obj->sources->create($card_array);
Stripe's docs don't explain a lot of the more nuanced procedures so you have to do a lot of testing.
Assuming you have a customer object $cu, with the token you get from checkout or whatever you use:
$card = $cu->sources->create(['source'=>$token]);
will add a card to the customer. It just adds the card to the list; subsequent calls will add cards to the list. Note that it does not check for duplicates, so the same card can be on the list multiple times. It will also not set the new card to the active card. To make a card the default (or active), use
$cu->default_source = $card
$cu->save();
Using the older card interface:
$cu->card = $token;
$cu->save();
The new card will replace the default card. It will NOT make the previously default card inactive; it will delete the current default and make the new card the active default. The card interface is the easiest if you're just allowing 1 card to be attached to a customer at a time.

Stripe differentiation between charge deduction and Subscription assignment in webhook upon charge.succeeded

I am struggling for this for two days, I want to differentiate between subscription assignment and manually deducting the charge from Stripe. charge.succeeded webhook is called both times. In webhook call, I need to differentiate between Subscription assignment and Charge deduction for a particular amount.
Subscription Assignment is using below code.
$subscription = \Stripe\Subscription::create(array(
"customer" => $customer_id,
"plan" => $stripe_plan_id,
));
And charge deduction is using below code.
$charge = \Stripe\Charge::create(array(
'amount' => $price ,
'currency' => 'usd',
'customer' => $customer_id
)
);
If anyone has any idea please suggest the way. Thank you !!
Upon receiving the charge.succeeded event, you can extract the charge object and check the charge's invoice attribute:
// Retrieve the request's body and parse it as JSON
$input = #file_get_contents("php://input");
$event_json = json_decode($input);
if ($event_json->type == "charge.succeeded") {
$charge = $event_json->data->object;
if ($charge->invoice == null) {
// One-off charge
} else {
// Subscription charge
}
}
Note that technically, a charge can be linked to an invoice but not to a subscription, in case you created an invoice manually. If you need to distinguish in this case, you'll need to use the invoice's ID to retrieve the invoice, and check the invoice's subscription attribute to see if it's null or not.

Getting Last4 Digits of Card using Customer Object - Stripe API with PHP

I want to get the last 4 digits of a customers card using Stripe.
I have already stored the Customer using:
// Get the credit card details submitted by the form
$token = $_POST['stripeToken'];
// Create a Customer
$StripeCustomer = \Stripe\Customer::create(array(
"description" => "$username",
"card" => $token
));
Now I'd like to access and then store the card's last 4 digits. (For context, I want to show users which card they have stored using Stripe for future payments - this is not a subscription service).
I have searched for a solution but a lot of the posts are saving the last4 digits AFTER a charge, and pull the information from the charge like:
$last4 = null;
try {
$charge = Stripe_Charge::create(array(
"amount" => $grandTotal, // amount in cents, again
"currency" => "usd",
"card" => $token,
"description" => "Candy Kingdom Order")
);
$last4 = $charge->card->last4;
I would like to do the same BEFORE the charge , so I want to pull the last 4 from the Customer Object. The Stripe API documentation shows the attribute path for last4 from Customers,
customer->sources->data->last4
However, this does not seem to give me the correct last 4 digits.
$last4 = $StripeCustomer->sources->data->last4;
I think I am misunderstanding how to use attributes in the Stripe API. Could someone point me in the right direction?
$last4 = $StripeCustomer->sources->data[0]->last4;
sources->data is an array so you'd have to select the first card.
Side note: You're using the token twice, once to create the customer, and the second to create the charge, this will result in an error as the token can only be used once. You'd have to charge the customer instead of the token.
For any one else who lands here from search engines, here's a link to the Stripe docs on how to get the last 4 digits of a card saved to the customer https://stripe.com/docs/api/customers/object#customer_object-sources-data-last4
If you use Laravel Cashier, this code will be helpful for you.
$data = User::find(auth()->user()->id);
$payment = $data->defaultPaymentMethod();
$last4 = $payment->last4;
$brand = $payment->brand;
dd($payment);
You can get all information from this object.
This API has changed since this was first answered. For API version 2020-08-27 you need to use the ListPaymentsMethod API on the Customer object.
The path to access via JSON would look like this
$paymentMethods = $stripe->paymentMethods->all([
'customer' => 'cus_123',
'type' => 'card',
]);
$last4 = $paymentMethods->data[0]->card->last4

Categories