I'm trying to create a subscription for the merchant's users but facing "You can not pass payment_intent_data in subscription mode" error. With regular payments, it works well, but subscriptions aren't working.
Here is an example of what I want to do: John has an e-commerce shop based on recurring billing. Matthew is John's customer and wants to purchase a subscription from John. How can I easily take fees and transfer money to John's connect account while using "Stripe Checkout"?
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price' => $priceIntent->id,
'quantity' => 1,
]],
'customer' => Auth::User() -> stripe_code,
'mode' => 'subscription',
'payment_intent_data' => [
'application_fee_amount' => $total_fees,
'transfer_data' => [
'destination' => $merchantId,
],
],
'success_url' => env('APP_URL') . '/order/success/{CHECKOUT_SESSION_ID}',
'cancel_url' => env('APP_URL') . '/order/cancel/',
]);
Thanks!
Basically, you can't use payment_intent_data on a Checkout Session in subscription mode, since the subscription creates invoices instead of PaymentIntents.
To do this, you need to use the subscription_data hash: https://stripe.com/docs/api/checkout/sessions/create?lang=php#create_checkout_session-subscription_data-application_fee_percent and specify the merchant account.
Example of the API call with merchant details:
$session = \Stripe\Checkout\Session::create([
'subscription_data' => [
'application_fee_percent' => $fees_percent,
],
],array("stripe_account" => "acct_xxxxxxxxx"));
Also, don't forget to pass all the other required variables in the call.
Cheers :)
Related
I'm using Stripe with PHP, I want to create subscription to customer after a payment made with Stripe Checkout Session.
But, the problem is that when we do a one shot payment with Stripe Checkout Session, Stripe does not attach the source (Credit card) to the customer, and when I try to subscribe this customer to a plan, Stripe return me the error :
This customer has no attached payment source or default payment method.
I don't understand why Stripe don't attach the card to the customer with one shot payment because Stripe do it when we use a Checkout Session with Subscription.
How I create checkout session :
$checkout_session = Session::create([
'payment_method_types' => ['card'],
'mode' => 'payment',
'customer' => 'cus_xxxxxxxx',
'line_items' => [[
'price' => 'price_xxxxx', // Oneshot payment
'quantity' => 1,
]]
]);
How I try to subscribe customer (After successful payment) :
$subscription = Subscription::create([
'customer' => 'cus_xxxxxxxx',
'items' => [
['price' => 'price_XXXXXXX'] // Recurrent payment
],
'trial_from_plan' => true,
]);
Thank you for your help
When accepting a one-time payment with Checkout, it won't create a Customer or save card details by default. What you have to do is configure Checkout to do this for you during the payment. This is covered in their documentation here.
What you need to do is set the payment_intent_data[setup_future_usage] parameter like this:
$checkout_session = Session::create([
'payment_method_types' => ['card'],
'mode' => 'payment',
'customer' => 'cus_xxxxxxxx',
'line_items' => [[
'price' => 'price_xxxxx', // Oneshot payment
'quantity' => 1,
]],
'payment_intent_data' => [
'setup_future_usage' => 'off_session',
]
]);
After that, you will have a Customer cus_123 and a PaymentMethod pm_123 that you can re-use. That PaymentMethod will not be the default one though so you need to make sure that you pass its id in the default_payment_method parameter when you create the Subscription like this:
$subscription = Subscription::create([
'customer' => 'cus_xxxxxxxx',
'items' => [
['price' => 'price_XXXXXXX'] // Recurrent payment
],
'trial_from_plan' => true,
'default_payment_method' => 'pm_12345',
]);
Also note that you can start a Subscription directly from Checkout as documented here.
I'm creating successfully a subscription for a customer with the redirectToCheckout mehtod.
I'm creating the Stripe Session as following
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'locale' => 'de',
'line_items' => [[
'price' => env('STRIPE_PRICE'),
'quantity' => 1,
]],
'mode' => 'subscription',
'success_url' => $success_url,
'cancel_url' => $cancel_url,
]);
But I have two problems. This method is creating a new customer for me, unfortunately I need to set the language for the customer to German (not happening currently). Furthermore I need to define the tax for the line_items but didn't succeeded as suggested on the stripe docs for creating a Session Object.
In order to use a specific Customer (rather than have Checkout create one for you), you need to create it [0] before the CheckoutSession. Then you pass the Customer's id as CheckoutSession.customer [1].
For taxes, you can specify the TaxRates in CheckoutSession.subscription_data.default_tax_rates[2].
(pardon the dot notation, as this isn't PHP-specific and thus can be applied to any of Stripe's API libraries)
[0] https://stripe.com/docs/api/customers/create
[1] https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-customer
[2] https://stripe.com/docs/api/checkout/sessions/create#create_checkout_session-subscription_data-default_tax_rates
I'm working on a project which has two types of products: subscriptions and event registration.
I'm using Stripe Checkout Session for both. As their process is different, I'm using two webhooks; one for each.
e.g:
http://example.com/payment/subscription_webhooks.php
http://example.com/payment/event_webhooks.php
The problem is that once a checkout session is completed, whatever if it's for subscriptions or event registration, both webhooks are triggered.
I'm looking for a solution to define which webhook should be triggered.
Have 1 end point for both session.complete triggers, but send metadata to the endpoint and throw an IF statement into your listener so you can see which session you're listening for.
Here is some code I wrote up.
Checkout Session A:
$checkout_session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price_data' => [
'currency' => 'gbp',
'unit_amount' => '1000',
'product_data' => [
'name' => 'Example Product',
],
],
'quantity' => 1,
]],
'metadata' => ["session" => "session_a"],
'mode' => 'payment',
'success_url' => "https://www.example.co.uk/success",
'cancel_url' => "https://www.example.co.uk/cancel",
]);
Checkout Session B:
$checkout_session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price_data' => [
'currency' => 'gbp',
'unit_amount' => '1000',
'product_data' => [
'name' => 'Example Product',
],
],
'quantity' => 1,
]],
'metadata' => ["session" => "session_b"],
'mode' => 'payment',
'success_url' => "https://www.example.co.uk/success",
'cancel_url' => "https://www.example.co.uk/cancel",
]);
Take note that the metadata is different in the 2 above examples.
Now, use SWITCH and CASE to find which one you're listening for.
Webhook
$payload = #file_get_contents('php://input');
$event = null;
try {
$event = \Stripe\Event::constructFrom(json_decode($payload, true));
} catch(\UnexpectedValueException $e) {
http_response_code(400);
exit();
}
switch($event->data->object->metadata['package']) {
case 'session_a':
// Do your Session A stuff, SQL etc
break;
case 'session_b':
// Do your Session B stuff, SQL etc
}
Some useful tips:
You can pass the session ID from your checkout.session start through to your success page or hook, then grab data...
Checkout session page
'success_url' => "https://www.example.co.uk/success?session_id={CHECKOUT_SESSION_ID}",
session_id={CHECKOUT_SESSION_ID} is exactly as I've written it, you don't actually need to enter the checkout session ID, just literally copy it exactly like its written.
Hook page or Success page
if($_GET['session_id']){
$session_id = $_GET['session_id'];
}
$stripe = new \Stripe\StripeClient('API key');
$session_data = $stripe->checkout->sessions->retrieve($session_id,[]);
$payment_status = $session_data->payment_status;
$payment_address0 = $session_data->shipping->name;
$payment_address1 = $session_data->shipping->address->line1;
$payment_address2 = $session_data->shipping->address->line2;
$payment_address3 = $session_data->shipping->address->city;
$payment_address4 = $session_data->shipping->address->country;
$payment_address5 = $session_data->shipping->address->postal_code;
$payment_buyer_email = $session_data->customer_details->email;
$payment_metadata = $session_data->metadata->user_id;
You can grab data, just checkout the Stripe docs for the JSON response.
Anyone learning Stripe, all seems real confusing, but keep trying, testing, var_dump your results etc and you'll soon see what's happening.
You only need 1 webhook endpoint, then you handle switch case (or if else) for each event of these subscription (subscriptions and event registration in your case).
And i as you, i don't know how to distinguish what event for subscriptions, and what for event registration.
You can create a webhook endpoint on Stripe through the dashboard or through the API [1] and when doing so specify which types of events you want to be notified about.
You'll likely want to remove one of those webhook endpoints and use only one for all checkout.session.completed events.
[1] https://stripe.com/docs/api/webhook_endpoints/create
I am trying to set Stripe checkout for my website.
I created and verified my Stripe account, and now I need to set up the checkout page. I downloaded from Github the PHP stripe library (I have PHP 5.6.4, so compatibility is OK). Then I went in the Stripe documentation and found this page.
I created a new page for the checkout, included the init.php from the Stripe library and pasted in the page the code found in the documentation page. When I open it, it gives back an empty page but I don't know why.
I don't know if this is the right procedure, but I searched online for like 2 hours finding nothing, and the documentation doesn't seem clear to me. Can someone help me?
I checked and the page doesn't generate errors. The code of the page is this:
<?php
require_once('assets/stripe/init.php');
\Stripe\Stripe::setApiKey('sk_test_OW6K5e96gNXbAhEvPo15IB3C');
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'name' => 'T-shirt',
'description' => 'Comfortable cotton t-shirt',
'images' => ['https://example.com/t-shirt.png'],
'amount' => 500,
'currency' => 'eur',
'quantity' => 1,
]],
'success_url' => 'https://example.com/success?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => 'https://example.com/cancel',
]);
?>
This is what I copied in the page, still don't know if there's something to change or some other things to add.
<?php
require_once 'shared.php';
$domain_url = $config['domain'];
$base_price = $config['base_price'];
$currency = $config['currency'];
$quantity = $body->quantity;
// Create new Checkout Session for the order
// Other optional params include:
// [billing_address_collection] - to display billing address details on the page
// [customer] - if you have an existing Stripe Customer ID
// [payment_intent_data] - lets capture the payment later
// [customer_email] - lets you prefill the email input in the form
// For full details see https://stripe.com/docs/api/checkout/sessions/create
// ?session_id={CHECKOUT_SESSION_ID} means the redirect will have the session ID set as a query param
$checkout_session = \Stripe\Checkout\Session::create([
'success_url' => $domain_url . '/success.html?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => $domain_url . '/canceled.html',
'payment_method_types' => ['card'],
'line_items' => [[
'name' => 'Pasha photo',
'images' => ["https://picsum.photos/300/300?random=4"],
'quantity' => $quantity,
'amount' => $base_price,
'currency' => $currency
]]
]);
echo json_encode(['sessionId' => $checkout_session['id']]);
for more details and demo code :
https://github.com/stripe-samples/checkout-one-time-payments/tree/master/client-and-server/server/php/public
HI I am using braintree(braintree/braintree_php": "4.5.0) . I have implemented the 3dsecure in the web.It working fine. I need to auto renew the payment with paymentMethodToken. Below code i have used for auto renewal.
$trans = [
'amount' => "14.63",
'merchantAccountId' => "Vo**ID",
'paymentMethodToken' =>"token",
'transactionSource' => "recurring",
'customFields' => [
'client_id' => "id",
'service_id' => "id",
'invoice_id' => "id",
'action' => "autorenew",
'slots' => "15",
],
'options' => [
'submitForSettlement' => true,
'storeInVaultOnSuccess' => true,
'paypal' => [
'description' =>"Renew server",
]
]
];
$transaction = $gateway->transaction()->sale($trans);
When run this code i get below error
Authorization in Util.php line 59:
The above code is working when the user enter the credit card information to pay.This only gives error when i do payment with paymentMethodToken to auto renew the payments.Any help?
reference : https://developers.braintreepayments.com/guides/paypal/server-side/php
As per I understood your requirement. You need to do auto payment.
For that, Braintree provide the best way to do this called Subscription.
Let me know, If you need any more help.