How-to Implement The PayPal Purchase Flow
Introduction
With the Mosaic Monetization and Billing Service you can integrate subscription purchases via PayPal to your frontend application.
For a full description of the PayPal integration see the PayPal Integration and the Manage PayPal Subscriptions how-to guide.
PayPal offers a purchase flow where the browser redirects the end-user to the PayPal website. And a popup based approach where the PayPal payment flow opens in a browser popup.
Prerequisites
This guide assumes that you have a frontend application that can authenticate end-users with the Mosaic User Service. You can use basic browser fetch logic or the Apollo Client if you use a React app: https://www.apollographql.com/docs/react/
You followed the integration guide PayPal Integration to enable PayPal as a payment provider in the Admin Portal and configured all the required PayPal settings. Then you created at least one subscription plan with a payment plan that has PayPal enabled and configured for this plan. The plan was successfully published from the Monetization Service and is now available in the Billing Service.
Show available subscription plans
First, you need to call the Billing Service GraphQL API to get a list of all available subscription plans with their details. The following is an example query which returns all (active) subscription plans. The response data includes the id, title, description, and the absolute URL path to the cover image.
The subscription plans include also all the associated active payment plans.
Every payment plan has an ID, title, and description. The periodUnit
field
defines the type of unit (e.g. MONTH
) and the quantity (e.g. 1
) for a
monthly recurring subscription.
The prices are in general country specific and you should select the price for the current country of the user. But as PayPal does not support country specific price differences this filter might not be needed in your project.
query Plans {
subscriptionPlans(filter: {isActive: {equalTo: true}}) {
nodes {
id
title
description
coverImagePath
paymentPlans(filter: {isActive: {equalTo: true}}) {
nodes {
id
title
description
periodUnit
periodQuantity
prices(filter: {country: {equalTo: "DE"}}) {
nodes {
price
currency
}
}
providerConfigs {
nodes {
paymentProvider {
key
title
}
}
}
}
}
}
}
}
You need to provide the end-user JWT from the Mosaic User Service in every
request to the Billing Service GraphQL API as an HTTP header ("Authorization": "Bearer eyJYSJ9lYZOVr7s..."
). Please check the corresponding User Service
documentation on how to register and log in end-users.
PayPal integration via redirects
In the redirect based purchase process, the end-user starts on your website and selects the payment plan that he wants to purchase. The end-user is then redirected in the browser to the PayPal website where he can follow the purchase flow. Once everything is fine, PayPal redirects the end-user to our Mosaic Billing Service. From there the end-user is then redirected back to the success (or error/cancel URL) that you configured in the Billing Service settings.
The following steps describe, which GraphQL API calls, redirects, etc. you should make in order to implement the PayPal subscription flow.
When the end-user selects one of the payment plans, you can call the
paypalSubscribe
mutation to start the purchase process. Use the ID of the
selected payment plan for the paymentPlanId
and for the purchase flow
purchaseFlow
parameter select the value REDIRECT
. You can optionally provide
a ISO 3166-1 alpha-2 country code via the country
parameter (e.g. US
for the
United States of America or DE
for Germany). The Billing Service will store
this country code for the created subscription and will validate, that a price
is configured for the given country.
mutation subscribe {
paypalSubscribe(
input: {
paymentPlanId: "58e11028-4a70-45a2-9690-9fc92a7f6d1a"
purchaseFlow: REDIRECT
country: DE
}
) {
approveUrl
subscriptionId
}
}
This query can be done from the client side or from the backend of your website.
Once you acquired the approveUrl
, redirect the user to that given URL. The
end-user can then follow the PayPal purchase flowto subscribe to the selected
payment and subscription plan.
PayPal will then redirect the end-user to the Billing Service API with some parameters about the purchase process. The Billing Service will then validate the subscription details with the PayPal API. Finally, the Billing Service will redirect the end-user to your configured success (or cancel) URL. In success case the Billing Service appends a GET parameter to your URL that contains the UUID of the created subscription as subscriptionId parameter:
https://www.example.com/success?subscriptionId=960f5cd7-968c-4f68-bbf6-85ed9ae48eec
Your application can now request information about the subscription and display this information. The query could request information about the lifecycle status, the end date of the current billing period, information about the used payment provider and the title and description of the subscription plan and payment plan:
query sub {
subscription(id: "960f5cd7-968c-4f68-bbf6-85ed9ae48eec") {
lifecycleStatus
activationDate
periodEndDate
paymentProvider {
title
}
subscriptionPlan {
title
description
}
paymentPlan {
title
description
}
}
}
PayPal integration via popups
The second option that is offered by PayPal is to use the popup-based subscribe workflow. This process uses the PayPal JavaScript SDK to render a PayPal subscribe button on your application.
When the end-user selects one of the payment plans, you can call the
paypalSubscribe
mutation to get the required parameters to start the
popup-based purchase process. Use the ID of the selected payment plan for the
paymentPlanId
and for the purchase flow purchaseFlow
parameter select the
value POPUP
. You can optionally provide a ISO 3166-1 alpha-2 country code via
the country
parameter (e.g. US
for the United States of America or DE
for
Germany). The Billing Service will store this country code for the created
subscription and will validate, that a price is configured for the given
country.
mutation subscribe {
paypalSubscribe(
input: {
paymentPlanId: "58e11028-4a70-45a2-9690-9fc92a7f6d1a"
purchaseFlow: POPUP
country: DE
}
) {
subscriptionId
paypalPlanId
customId
}
}
This will compose a customId that you have to provide to the PayPal button code.
The following code is a sample on how you can integrate the button into your application. Please confirm with your used PayPal SDK version to make sure the example works for your version.
First, you need to include the PayPal SDK into your application. you have to replace the text {{your-client-ID}} with the client ID of the PayPal REST API application that you configured in the Monetization Service.
<script
src="https://www.paypal.com/sdk/js?client-id={{your-client-ID}}&vault=true&intent=subscription"
data-sdk-integration-source="button-factory"
></script>
Add a DIV element into your website where the button should appear:
<div id="paypal-button-container"></div>
Then you need to configure the button and render it. Please consult the https://developer.paypal.com/docs/subscriptions/integrate/#link-createpaymentbutton[PayPal documentation] for a description on all the available configuration options and callbacks.
The example below shows a simplified implementation using the basic fetch functionality. For a production-grade implementation, you may consider using more sophisticated libraries like Apollo Client and correctly handle error scenarios.
paypal
.Buttons({
style: {
shape: "rect",
color: "blue",
layout: "vertical",
label: "subscribe",
},
createSubscription: function (data, actions) {
return fetch('https://billing.service.eu.axinom.net/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{end-user-JWT}}'
},
body: JSON.stringify({
query: `
mutation sub($input: PaypalSubscribeInput!) {
paypalSubscribe(input: $input) {
paypalPlanId
customId
}
}
`,
variables: {
"input": {
"paymentPlanId": "{{payment-plan-id}}",
"purchaseFlow": "POPUP"
}
},
}),
})
.then((res) => res.json())
.then((result) => {
return actions.subscription.create({
plan_id: result.data.paypalSubscribe.paypalPlanId,
custom_id: result.data.paypalSubscribe.customId,
});
})
},
onApprove: function (data, actions) {
return fetch('https://billing.service.eu.axinom.net/graphql', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer {{end-user-JWT}}'
},
body: JSON.stringify({
query: `
mutation activate($input: PaypalActivateSubscriptionInput!) {
paypalActivateSubscription(input: $input) {
subscription {
id
lifecycleStatus
}
}
}
`,
variables: {
"input": {
"paypalSubscriptionId": data.subscriptionID
}
},
}),
})
.then((res) => res.json())
.then((result) => {
alert('The subscription with ID ' +
result.data.paypalActivateSubscription.subscription.id +
' is now in the ' +
result.data.paypalActivateSubscription.subscription.lifecycleStatus +
' state.');
})
},
})
.render("#paypal-button-container");
You can use the style
property to define the look and feel of the PayPal
button. The PayPal
https://developer.paypal.com/docs/checkout/standard/customize/buttons-style-guide/[Buttons
style guide] describes the available settings.
In the createSubscription
callback you need to return the
actions.subscription.create
call. As parameters, you need to provide the
PayPal plan ID. The Mosaic Billing Service needs to match the PayPal
subscription to your end-user and your environment instance. Therefor you have
to set a custom ID so the Mosaic Billing Service can match the PayPal
subscription to the Billing Service subscription.
The Billing Service GraphQL mutation paypalSubscribe
provides you with both
parameters. The above example uses the fetch call with promises to get this
information. You need to replace the text {{end-user-JWT}}
with the actual JWT
of the end-user. And you need to replace {{payment-plan-id}}
with the ID of
the desired Billing Service payment plan.
If the end-user clicks on the rendered PayPal button a popup appears that is loaded from the PayPal website. The end-user can follow the process and complete the payment process.
Once the process is done, the popup closes and the onApprove
callback from the
above code is executed. Withink that callback you can call the
paypalActivateSubscription
mutation on the Billing Service GraphQL API to
activate the subscription. The data
parameter contains a property
subscriptionID
which refers to the PayPal subscription in their system. You
have to set this as an input parameter to the paypalActivateSubscription
mutation. When this GraphQL mutation is executed, the Billing Service will
verify via the PayPal API that the subscription was correctly activated. In the
above example, the response includes the Billing Service subscription ID and the
lifecycle status of the subscription. You can then show the result to the
end-user. In the example above this is simply done as an alert
.