how to create customer and charge subscription at same time? - php

I'm using stripe and had all my subscriptions working properly before.
Just recently I am trying to move the same code to a different stripe account and I am receiving errors when trying to charge a subscription.
<?php
require_once('../stripe-php-master/init.php');
// (switch to the live key later)
\Stripe\Stripe::setApiKey("sk_test_hlQNSE1fy1cGmsqDSbR9LfDF");
try
{
$customer = \Stripe\Customer::create(array(
'email' => $_POST['stripeEmail'],
'source' => $_POST['stripeToken'],
'plan' => 'basic_annually'
));
header('Location: ../../subscription-success.html');
exit;
}
catch(Exception $e)
{
header('Location:oops.html');
error_log("unable to sign up customer:" . $_POST['stripeEmail'].
", error:" . $e->getMessage());
}
this is returning the following error
unable to sign up customer: 'test#example.com', error:No such plan: basic_monthly; one exists with a name of basic_monthly, but its ID is 504102373103330.

Plan objects have both an id and a name attribute. id is the plan's unique identifier while name is its display name.
When creating a customer or a subscription, the value of the plan parameter must be set to a valid plan ID, not to a plan's name.
In your case, the error message explicitly tells you that there is plan with "basic_monthly" as its name, but the plan's id is 504102373103330, so that's the value you'd need to pass in the plan parameter to create a subscription to that plan.

you must change secret and test api keys

Related

Stripe shows no such token: tok_xxxxxxx for destination charge

I am trying to create a destination charge from my customer to one of the connected account.
\Stripe\Stripe::setApiKey(STRIPE_SECRET_KEY); //Origin Stripe Secret Key
try {
$connectd_account_id = 'acct_XXXXXXX';
$customer_id = 'cus_XXXXXXX'
// sharing my customer with connected account and creating a token.
$token = \Stripe\Token::create(
["customer" => $customer_id], //doctor stripe customer id
["stripe_account" => $connectd_account_id]); //Lab Stripe Account
// I am receiving response ** No such token: tok_xxxxxxx **
$charge = \Stripe\Charge::create(array(
"amount" => 10000,
"currency" => 'USD',
"source" => $token->id,
"application_fee_amount" => 2000,
"transfer_data" => [
"destination" => $connectd_account_id,
],
)
);
} catch (Exception $e) {
$error = $e->getMessage();
}
everytime I receive
No such token: tok_xxxxxxx
What's my mistake here I can't locate. Please help.
If you're creating a destination charge, the card token and customer and related objects should all be created on your platform account. Your platform account is the one interacting with the cardholder and processing the payment, there is then just a transfer of funds within Stripe to the destination account.
Your code appears to be attempting to clone saved card details from your platform to the destination account, which is not what you would do for a Destination charge(you'd only do this if you were using Direct charges where the payment is processed on the connected account and thus need to copy payment information there).
In short, you should omit the code for creating a token, and instead when creating the charge, pass something like "source" => $customer_id, to charge the customer details on your platform.

Not able to get transaction id in subscription plan

I am working with Stripe payment option for my project. I have a recurring option and that's why I have created plans in subscription page.
After creating plans I have defined my plan when a new stripe customer register.
try {
$customer = \Stripe\Customer::create([
'source' => $token,
'email' => $email,
'plan' => '20-39-R',
'metadata' => [
"First Name" => $first_name,
"Last Name" => $last_name
]
]);
} catch (\Stripe\Error\Card $e) {
return redirect()->route('order')
->withErrors($e->getMessage())
->withInput();
}
When I have dump($customer) variable I am not getting transaction id.
Any idea why I am not getting transaction id during customer creation?
The customer object doesn't store a list of transaction ids which I think is what you'd call the id of the charge made on that customer's card right? The customer holds information about the sources (used to pay) and subscriptions that are created after a customer is subscribed to a plan.
Here you can see a sub_XXXXX in subscriptions[data][0][id] which corresponds to the id of the subscription that was created on that customer for your plan 20-39-R.
If you want the charge id, ch_XXXXX you would use the List ChargesAPI and pass the customer id, cus_XXXXX, in the `customer parameter to limit the charges to the ones created on that customer. The first one in the list would be the latest charge and likely the one corresponding to your subscription. You could confirm this by checking the invoice associated with the charge and confirming that it's for your subscription.

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.

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

Using Coupon Codes with Stripe

I have a site that is using Stripe to process a subscription payments. There is only one type of subscription.
I followed this tutorial on NetTuts to do the initial setup.
Had a form working fine processing subscriptions and everything worked. Client requested a coupon code. Stripe supports this so I set out trying to add a coupon code to the existing form.
I set up coupon codes in Stripe, set my testing keys and switched to test mode in stripe.
I'm performing a couple of checks in my code:
Check to see whether a coupon was entered, if not create a new customer object without a coupon option
Check to see whether the Coupon is valid, if not return an error
If there has been a coupon entered and it is valid, then pass the matching Stripe coupon object as an option when creating a new customer.
if(isset($couponCode) && strlen($couponCode) > 0) {
$using_discount = true;
try {
$coupon = Stripe_Coupon::retrieve($couponCode);
if($coupon !== NULL) {
$cCode = $coupon;
}
// if we got here, the coupon is valid
} catch (Exception $e) {
// an exception was caught, so the code is invalid
$message = $e->getMessage();
returnErrorWithMessage($message);
}
}
try
{
if($using_discount == true) {
$customer = Stripe_Customer::create(array(
"card" => $token,
"plan" => "basic_plan",
"email" => $email,
"coupon" => $cCode
));
}
else {
$customer = Stripe_Customer::create(array(
"card" => $token,
"plan" => "basic_plan",
"email" => $email
));
}
$couponCode is populated with the form field correctly the same way all other fields are populated, I've triple checked that it is being pulled correctly.
When I try to submit the form without a coupon code, it charges the full amount and passes through Stripe correctly.
However if I enter either a valid OR invalid coupon code, it does not pass a coupon object with the customer object when creating a new customer object and charges the full amount when passing through Stripe.
I've looked at the code for hours and can't seem to figure out why it is always failing to recognize the discount code and pass the matching coupon object to Stripe.
This is probably a little out dated and you found a solution for your code. But it would seem all you need to do is pass through your original $couponCode as the array value for Coupon. As stated by codasaurus you are just getting an array back from stripe of the coupon, which you don't need unless you did $cCode->id and pass the ID back to your array to create a customer.
I changed when you set the $using_discount to true, as this would trigger to send a coupon code if the coupon was valid or not.
Once the coupon is actually valid we then send the coupon. You only need the value of your submitted state so $coupon is the reference to the discount in there system. Or you could use the $coupon->id if you wanted to create it that way.
Here is my take on a solution based on your code, it could be better, but I hope it helps others looking for a solution like me.
if($coupon!='' && strlen($coupon) > 0) {
try {
$coupon = Stripe_Coupon::retrieve($coupon); //check coupon exists
if($coupon !== NULL) {
$using_discount = true; //set to true our coupon exists or take the coupon id if you wanted to.
}
// if we got here, the coupon is valid
} catch (Exception $e) {
// an exception was caught, so the code is invalid
$message = $e->getMessage();
returnErrorWithMessage($message);
}
}
if($using_discount==true)
{
$customer = Stripe_Customer::create(array(
"card" => $token,
"plan" => $plan,
"email" => $id,
"coupon"=>$coupon) //original value input example: "75OFFMEMBER" stripe should be doing the rest.
);
}
else
{
$customer = Stripe_Customer::create(array(
"card" => $token,
"plan" => $plan,
"email" => $id)
);
}
Looking at the documentation https://stripe.com/docs/api#create_customer, the Stripe_Customer::create() call is looking for just the coupon code. It looks like you're passing in the entire coupon object.
Unless your first try catch fails, $couponCode already has your coupon code. Also, there are several other checks you need to perform to determine if the coupon is valid. For example, if the coupon->times_redeemed < coupon->max_redemptions, or if the coupon->redeem_by has passed, etc. You might also want to check if the customer is already using the coupon by checking the customer discount object.
If any of these checks fail, just set your $using_discount = false;

Categories