XF 2.3 Introducing Stripe Checkout, PayPal's REST API and more!

Brand new in XenForo 2.3.0 Beta 2 is support for a few long overdue enhancements related to our payment and purchasable system. Let's look at each of these below!

Stripe Checkout​


Stripe Checkout is Stripe's native and hosted checkout page which not only brings with it some powerful customisability, it also makes accepting new payment methods completely trivial and available in an instant. Allow user upgrades and other purchasables to be purchased with options for "Buy Now Pay Later" (e.g. Klarna, ClearPay), popular region-specific bank redirects (such as iDEAL and Sofort), and popular online wallets (such as Alipay and Revolut). You can even accept payments through PayPal! Through Stripe! 😲

You can enable and configure as many payment methods as you like, and you do this directly through your Stripe Dashboard with zero additional code or configuration required in XenForo. Stripe intelligently and dynamically displays the enabled payment methods they feel will most likely lead to a conversion based on the customer's previous purchases, their geographic location and currency.

This new purchase experience is a drop in replacement for the existing implementation and requires no additional setup or configuration and is available automatically.

PayPal (REST API)​


Our existing PayPal implementation - while absolutely functional - is at least 2-3 generations behind so today is the day we make available a new implementation based on PayPal's current REST API. While functionally this will still be the same as the existing implementation, it is the right time to support PayPal's latest development experience which will continue to receive new functionality and enhancements long in to the future, as well as being more secure and actively maintained by PayPal.

We have implemented this as a brand new payment provider and marked the existing one as deprecated. We are not aware of any immediate plans for PayPal to sunset the legacy Checkout/IPN system we have been using for a long time, so you are free to continue using it. There is no known migration path to move existing customers (particularly recurring payments) to the new APIs but you can enable the new one for new purchases at any time.

The PayPal REST API being available in XenForo should allow developers to implement new, advanced functionality that previously wasn't available.

Ability to update payment details for subscriptions​

Starting with Stripe only, initially, we've added the ability for purchasables and payment providers to be able to "Change payment" for existing recurring payments. In the case of Stripe, clicking "Change payment" takes you to a Stripe Checkout session which allows you to update your payment method.

b7cbwt8dnt.sharedwithexpose.com_account_upgrades.webp


This is a potentially frequently needed piece of functionality which will allow users to, for example, change their payment card after changing banks or having received new card details due to expiry of the previous card. Previously it was not possible for users to update their card details, and usually required the subscription to be cancelled before signing up with new card details.

This is an asynchronous process so once the user provides updated payment details, they will later receive an email confirmation once the new payment details have been applied.

Improved experience for cancelling subscriptions​

It has always been possible for a user to be able to cancel their recurring payment but we didn't do the best job of reflecting that change in the UI. The cancel button would still be displayed after cancellation, and would simply error if you tried to use it again. We now track the cancellation state within the purchasable record and adjust the UI accordingly:

23x.test_account_upgrades.webp


This should hopefully be a much less confusing experience.


That's it for new features in Beta 2. We've got more to come very soon! Thank you to everyone who has helped identify issues and provide feedback for XenForo 2.3 so far.
 
Great! Hopefully some of the PayPal REST functionality will trickle down to other areas. For example you can schedule a subscription to start on a future date (up to 10 years out). Could be useful when a user has paid for 6 months of user upgrade, but wants to change to a 12 month plan without having to wait until the 6 month is expired (just start it on their existing end date).

Could also offer something like 5 day free trial for something (effectively just start billing of a user upgrade x days in the future beyond when they sign up for it). Can also utilize subscription "setup fees" for something similar. Like first year is $xx.xx, then subsequent years are something else (first year is a setup fee and follow up years is a normal subscription that doesn't start until a year out).

See this post:

 
Ooooohhhh i'm sure my mate @BIG LLC will love this. (He told me to tag him if there is something he is interested in)
Whilst we're waiting for the full version to come out it's going to look very nice.
 
Great! Hopefully some of the PayPal REST functionality will trickle down to other areas. For example you can schedule a subscription to start on a future date (up to 10 years out). Could be useful when a user has paid for 6 months of user upgrade, but wants to change to a 12 month plan without having to wait until the 6 month is expired (just start it on their existing end date).

Could also offer something like 5 day free trial for something (effectively just start billing of a user upgrade x days in the future beyond when they sign up for it). Can also utilize subscription "setup fees" for something similar. Like first year is $xx.xx, then subsequent years are something else (first year is a setup fee and follow up years is a normal subscription that doesn't start until a year out).

See this post:


I can't say I particularly enjoyed my experience working with the PayPal REST API so I'm not personally promising anything, but I'm sure the very fact that it is now available as an option should allow people to build upon it in future for add-ons.

Side note on the cancellation side of things, I ran out of time so I didn't actually add cancellation support for the PayPal REST handler yet, but we'll try and get that into Beta 3 once I've gotten over the initial trauma of working with PayPal.
 
I can't say I particularly enjoyed my experience working with the PayPal REST API so I'm not personally promising anything, but I'm sure the very fact that it is now available as an option should allow people to build upon it in future for add-ons.

Side note on the cancellation side of things, I ran out of time so I didn't actually add cancellation support for the PayPal REST handler yet, but we'll try and get that into Beta 3 once I've gotten over the initial trauma of working with PayPal.
I feel you... I've been down the road myself (I already have a PayPal REST API payment handler for XF2). There are so many stupid things internally with it I can barely stand it. It definitely feels like I had to get it working in spite of PayPal. Besides the API having general stupidity/inconsistency, this is one of my favorites... where you can get notified of a transaction via webhook, but when you validate the transaction via REST, it's not there yet (there is a lag on their side).

PHP:
$count = 0;
while($count < 5)
{
    sleep(2); // takes a couple seconds for the transactions to show up via API
    $transactions = $this->repository('DigitalPoint\Marketplace:PayPal')->getSubscriptionTransactions($order['id']);

    if (!empty($transactions['transactions'][0]['id']))
    {
        break;
    }

    $count++;
}

I feel like I could write a book on how inconsistent things are on the backend.
 
I feel you... I've been down the road myself (I already have a PayPal REST API payment handler for XF2). There are so many stupid things internally with it I can barely stand it. It definitely feels like I had to get it working in spite of PayPal. Besides the API having general stupidity/inconsistency, this is one of my favorites... where you can get notified of a transaction via webhook, but when you validate the transaction via REST, it's not there yet (there is a lag on their side).

PHP:
$count = 0;
while($count < 5)
{
    sleep(2); // takes a couple seconds for the transactions to show up via API
    $transactions = $this->repository('DigitalPoint\Marketplace:PayPal')->getSubscriptionTransactions($order['id']);

    if (!empty($transactions['transactions'][0]['id']))
    {
        break;
    }

    $count++;
}

I feel like I could write a book on how inconsistent things are on the backend.
Oh no. I didn't run into that so I guess we'll get bug reports of webhooks not being validated in due course.

Great Job Reaction GIF


Here's a couple of my "favourites":

PHP:
        $state->requestKey = $state->resource['purchase_units'][0]['custom_id']
            ?? $state->resource['disputed_transactions'][0]['custom']
            ?? $state->resource['custom']
            ?? $state->resource['custom_id']
            ?? null;
Dude, I just want to get the "custom" field we passed in. Why are you like this?

PHP:
case 'PAYMENT.SALE.REFUNDED':
case 'PAYMENT.CAPTURE.REFUNDED':
    $status = $state->resource['state'] ?? $state->resource['status'];
    if (strtoupper($status) === 'COMPLETED')
When is a status not a status? When it's a state? Two basically identical webhooks (though one for a straight sale, one for a recurring payment), but two different names for the "status".

ryan reynolds hd GIF
 
Oh no. I didn't run into that so I guess we'll get bug reports of webhooks not being validated in due course.

Great Job Reaction GIF


Here's a couple of my "favourites":

PHP:
        $state->requestKey = $state->resource['purchase_units'][0]['custom_id']
            ?? $state->resource['disputed_transactions'][0]['custom']
            ?? $state->resource['custom']
            ?? $state->resource['custom_id']
            ?? null;
Dude, I just want to get the "custom" field we passed in. Why are you like this?

PHP:
case 'PAYMENT.SALE.REFUNDED':
case 'PAYMENT.CAPTURE.REFUNDED':
    $status = $state->resource['state'] ?? $state->resource['status'];
    if (strtoupper($status) === 'COMPLETED')
When is a status not a status? When it's a state? Two basically identical webhooks (though one for a straight sale, one for a recurring payment), but two different names for the "status".

ryan reynolds hd GIF
Yep... gets even crazier if you deal with other "types". The platform API calls (when you are making API calls on behalf of a different PayPal account for things like allowing users to sell via marketplace, but with their own PayPal account are also completely different). I ended up just having a make a whole system just to normalize transaction data so I can manage the stupidity in one place.

It's not even just the REST API... PayPal APIs have always been idiotic internally. Whoever architected PayPal APIs needs to be fired... or move them to a non-technical position in the company.
 
So pleased to see these changes, thank you!

One thing which I'm not sure if it's possible or not, as I've not tested stripe checkout much, but do you think it's possible to switch subscriptions?

For example, if we have 4 subscriptions, a user can only have one active sub at any given time. When active, the ability to purchase a separate one is disabled. It would be quite cool if it were possible for a user to switch their subscription without the need to contact an admin to get a pro-rated refund or wait until the end of their current subscription.
 
For example, if we have 4 subscriptions, a user can only have one active sub at any given time.
I don't think there's a limit on subscriptions. (At least with Stripe)

It's possible to have a monthly and a yearly at the same time. People on my site have done it. (By mistake)
 
Top Bottom