Stripe checkout one-time payments php? - php

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

Related

Stripe : No card attached to customer after a checkout session payment

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.

Stripe accessing the metadata within a PHP script

I'm trying to retrieve a line of metadata (order_no) within Stripe's checkout.session.completed event but I don't know how to go about it. I'm using PHP. I don't know how to query the event to retrieve the checkout.session object from within a PHP script, so I can read the metadata. Could someone please show by example how to achieve that without installing addons such as Slim, etc. I have looked at multiple examples on this site but have not been able to understand them. Thanks in advance for any help you can give.
header('Content-Type: application/json');
$order = $mysqli->escape_string(md5(rand(0,20)));
$amt = '299';
$checkout_session = \Stripe\Checkout\Session::create(
[
'payment_intent_data'=>['description' =>'my purchases'],
'metadata' => [
'order_id' => $order
],
'line_items' => [
[
'name' => 'My Products',
'description' => 'My online products',
'currency' => 'gbp',
'amount' => $amt,
'quantity' => 1
]],
'success_url' => $MySite.'success.php',
'cancel_url' => $MySite.'cancel.html'
]);
header("HTTP/1.1 303 See Other");
header("Location: " . $checkout_session->url);
}

PHP Stripe: You can not pass `payment_intent_data` in `subscription` mode

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 :)

Stripe: handle multiple Webhooks

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

PayPal Order Summary Using REST API - - cURL or PHP

I am working with the PayPal RESTful API.
https://developer.paypal.com/webapps/developer/docs/api/
How can I pass my consumers order items and purchase description to PayPal, so when my user is redirected to PayPal to approve the order by logging in, their order summary will show up on the left.
.
.
ORDER SUMMARY ON THE LEFT
I have tried to passing in the transactions.item_list.items but that information isn't showing up in the order summary still.
Any help how to get an order summary to appear on the paypal approval page using the PayPal RESTful API?
I haven't been to pleased with their documentation as it is lacking some information and also has a few mistakes which wasted decent amount of my time to debug.
//
// prepare paypal data
$payment = array(
'intent' => 'sale',
'redirect_urls' => array(
'return_url' => $url_success,
'cancel_url' => $url_cancel,
),
'payer' => array(
'payment_method' => 'paypal'
)
);
//
// prepare basic payment details
$payment['transactions'][0] = array(
'amount' => array(
'total' => '0.03',
'currency' => 'USD',
'details' => array(
'subtotal' => '0.02',
'tax' => '0.00',
'shipping' => '0.01'
)
),
'description' => 'This is the payment transaction description 1.'
);
//
// prepare individual items
$payment['transactions'][0]['item_list']['items'][] = array(
'quantity' => '1',
'name' => 'Womens Large',
'price' => '0.01',
'currency' => 'USD',
'sku' => '31Wf'
);
$payment['transactions'][0]['item_list']['items'][] = array(
'quantity' => '1',
'name' => 'Womens Medium',
'price' => '0.01',
'currency' => 'USD',
'sku' => '31WfW'
);
//
//format payment array to pass to cURL
$CURL_POST = json_encode($payment);
your code is good. This is actually a bug that will be fixed very soon. Regarding documentation, can you share how we can make it better? I want to make sure your feedback gets passed to our documentation team.
I experienced the same issue while trying it out today. What I did was add the Items like below.
$item = new Item();
$item->setQuantity($item_quantity);
$item->setName($item_name);
$item->setPrice($item_price);
$item->setCurrency($item_currency);
$item_list = new ItemList();
$item_list->setItems(array($item));
The $item_list is a property of transaction so you should add it after.
$transaction = new Transaction();
$transaction->setItemList($item_list);
....
That should show on the Order summary pane on PayPal page.
You can also check the answer here.
Try using the sample shown here : http://htmlpreview.github.io/?https://raw.githubusercontent.com/paypal/PayPal-PHP-SDK/master/sample/doc/payments/CreatePaymentUsingPayPal.html
It is a sample that comes along with the PayPal REST API SDK. You can try those samples out yourselves, by following instructions on readme.
This is how it would look like, when you run that sample:

Categories