Stripe Checkout - Subscription Issue with Recognized Stripe User - php

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.

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.

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 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.

Stripe Connect - Error Refunding Application Fee?

In my app I am creating a charge, like so:
$appFee = 100;
$depositCharge = 2000;
\Stripe\Stripe::setApiKey('sk_test_xxxxxx');
$charge = \Stripe\Charge::create(array(
"amount" => (int) $depositCharge,
"currency" => "usd",
"capture" => "true",
"destination" => $providerID,
"application_fee" => (int) $appFee,
"customer" => $customerID
));
Later on, I am trying to process a refund with the API, and also refund the application fee (so my connected account doesn't eat the fee)
$re = \Stripe\Refund::create(array(
"charge" => $chargeID,
"refund_application_fee" => "true"
));
But when I do this, I get the following error:
{
"error": {
"type": "invalid_request_error",
"message": "Attempting to refund_application_fee on charge ch_xxxxxx, but it has no application fee. To refund the application fee on the associated transfer, set reverse_transfer=true."
}
}
If I leave out the 'refund_application_fee' parameter, it works fine. Why is this parameter causing an error?
Basically you need to provide the Stripe Account Id of the Connected account which is I think $providerID in your case while creating the Refund.
I have not tested your case, but I was also getting same issue that when I set refund_application_fee the Refund gives error and leaving it out works fine.
After that I Provided Stripe Account Id of the Connected account against which Charge was being created and Refund was successful with refund_application_fee set to true.

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