Payment Connectors
General Concept
The Mosaic monetization solution comes with pre-integrated payment providers like PayPal. You can use those directly from your frontend applications without writing any backend code. If you would like to integrate payment providers that are currently not directly supported you can do so by creating a custom payment connector. This setup is often called “bring your own payment provider”.
You can develop a payment connector that acts as a proxy solution between the Mosaic Billing Service and a payment provider like Stripe or Adyen. The Mosaic service offers APIs that can be called by your payment connector in order to create new subscriptions, register recurring payments and transactions, and update existing subscriptions. This way you can seamlessly combine existing Mosaic payment providers and new ones.
The following diagram shows the high-level overview of payment provider integrations:
The end user opens the client application and navigates to the section where the subscription options are shown. The app asks the Mosaic Billing Service for a list of all active subscription plans with their payment plans and prices. The end user selects a payment plan and a payment connector to pay for the subscription.
If the end user selects a custom payment connector, the client app calls the custom payment connector API with the ID of the desired payment plan. The payment connector calls the payment gateway (e.g. the Stripe or Adyen API) to register/start the payment flow. The end user is then redirected to a web page on the payment provider (or a self-hosted page) to finish the payment flow. The user is then redirected back to the client app.
The payment gateway informs the payment connector via webhooks that the subscription is created and activated. The payment connector can now register the subscription in the Mosaic Billing Service and add the received payment information.
Subscription renewals and other updates are then handled in a similar way where the payment gateway calls a webhook on the payment connector. The payment connector calls then the Mosaic Billing Service to adjust the subscription (e.g. a new billing end date) and register transactions.
Payment connector
A payment connector is a custom backend service that acts as a proxy between the desired payment gateway and the Mosaic Billing Service. This payment connector receives webhook events from the payment gateway and/or calls the API of the payment gateway. It will then call the Mosaic Billing Service GraphQL API to store the subscriptions and transactions.
The Mosaic Billing Service offers the two GraphQL APIs. The normal Billing Service API is used for the end user integration to list available subscription plans and purchase them. The management API endpoint of the Billing Service is used by payment connectors through authorized service accounts. This API allows to list and manage all subscriptions and transactions for custom payment providers.
The corresponding mutations are described in this section. All the create and update mutations can only be used with a custom payment connector. Subscriptions and transactions from Mosaic managed payment providers cannot be created/changed via the GraphQL API.
Subscription initial purchase
Once an end user selects a payment plan that he wants to purchase, the initial subscription purchase flow can start. The client application will call your custom payment connector with the selected payment plan and other required details. The payment connector should then prepare a subscription in the Mosaic Billing Service and most often call the payment gateway API to prepare the purchase flow.
Mutation: createSubscription
The createSubscription
GraphQL mutation is used to create the initial
subscription.
During this and all later flows the payment connector must have a way to match the subscription in the Mosaic Billing Service to the subscription on the payment provider side. There are mainly two ways to create this mapping:
- Call the payment gateway first to prepare a subscription and get the
gateway subscription ID (or any similar identifier/reference). Then call
the Mosaic Billing Service
createSubscription
mutation and provide this identifier aspaymentProviderReference
. This value will be stored in the Mosaic subscription in the fieldpaymentProviderReference
and can later be queried. - Call the Mosaic Billing Service
createSubscription
mutation first and get the Mosaic subscription ID. Store this Mosaic subscription ID in the payment gateway as part of the subscription there (or any similar purchase flow object).
Calling the createSubscription
operation takes the following input
parameters:
Parameter |
Type |
Description |
Example |
---|---|---|---|
paymentProviderKey |
string |
The identifier of your/one of your custom payment connectors. The prefix is always “CPC_” for custom payment connectors. |
CPC_STRIPE |
paymentPlanId |
UUID |
The unique identifier of the selected payment plan. |
b8d3611f-8a1c-49d2-b9fb-192b7d8bd712 |
endUserId |
UUID |
The unique identifier of the end user (taken from the JWT). |
8b7e45b8-ae8e-4a7b-b5f2-05d55d9e3cab |
subscriptionId |
UUID (optional) |
A client provided UUID which should be used as the ID of the subscription. |
cb84e074-0616-4087-960f-4fbf278f019b |
paymentProviderReference |
string (optional) |
The reference to the subscription/purchase object in the payment provider system. |
sub_1KxWxRIAN5unBbs0svaibw87 |
lifecycleStatus |
enum (optional) |
The subscription lifecycle status for this subscription. The default value is
|
ACTIVE |
periodEndDate |
ISO 8601 date (optional) |
The date and time when the current period of the subscription will end. The
default value is |
2022-05-06T05:52:12.71219+00:00 |
country |
ISO 3166-1 alpha-2 (optional) |
The (current) country of the user. Default is the unknown country |
DE |
skipValidations |
enum array: [ACTIVE_PLANS, COUNTRY_PRICE, SINGLE_SUBSCRIPTION] (optional) |
When creating a subscription the mutation checks some prerequisites. By providing some of the enum values, certain checks can be skipped. Default is to do all checks.
|
[ |
This operation makes sure that the selected payment plan and its subscription
plan are active if a country (other than “XX“) is provided, that there is a
price for it and that the end user does not have a currently active
subscription. By providing enum values in the skipValidations
parameter those
checks can be skipped. This is especially useful for migrating existing
subscriptions. If all the checks pass, the mutation creates a new Mosaic Billing
Service subscription in the desired lifecycle state. The details of this
subscription can be returned in the response.
The end user is then sent to the payment provider to follow and finish the subscription purchase process. This is most of the time done by redirecting the browser to the hosted payment page or opening a browser popup. Once the user finishes the purchase flow, his browser is redirected back to the client app (optionally via the payment connector).
Mutation updateSubscription
Purchasing a subscription is often a multi-step process. The initial
step is to call the createSubscription
mutation and most often to set
the lifecycle status to PENDING_ACTIVATION
. Once the purchase process
is finished, your payment connector must somehow get to know about it
and update the subscription in the Mosaic Billing Service via the
updateSubscription
mutation. The logic of how your payment connector
gets such notifications depends on the payment provider and the purchase
flow they offer. Most often one or multiple of the following flows are
provided:
- The payment provider is using webhook events. Whenever something related to subscriptions and payments happens in their system, they call a URL on your payment connector. Most payment providers use retries in case some error/outage happens in your webhook implementation in the payment connector. If a payment provider offers this option, it should always be used as this is a very reliable way to receive all the notifications.
- During the redirect flow, the end user is first redirected to the payment connector to follow and finish the purchase flow. Once this is done, he is redirected back to your payment connector and from there to the client app. This redirect URL often includes the subscription reference ID or some token. The payment connector can use those details to call the payment gateway API to check if the subscription got activated and payment-related details. This option has the risk, that the redirect may not work and your payment connector will not be notified of the subscription change. But in combination with webhooks, this is a very good option. The client app will know immediately if the subscription was successfully activated.
- The third option is polling. Your payment connector can create a
background worker job to verify with the payment gateway API if the
subscription purchase is finished. Your client app can use the Mosaic
Billing Service GraphQL WebSocket endpoint
subscriptionLifecycleStatusMutated
to receive an update when the lifecycle status of the subscription changes.
The mutation updateSubscription
can be used to update details of an
existing subscription. The following fields can be updated:
lifecycleStatus
- this defines which status the subscription is in. Please refer to the Billing Service technical documentation for all the available values and their meaning. The main use case is to create a subscription in thePENDING_ACTIVATION
state and set it toACTIVE
once the purchase flow is finished successfully.lifecycleStatusChangeReason
- If thelifecycleStatus
is updated, a reason for the change must be provided. This will add an entry to thesubscriptionStatusChanges
set of the subscription.
periodEndDate
- a subscription can be used until this date and time. Once that point is reached, another recurring payment would be expected to arrive. This might happen a bit before that point but can also happen afterward.activationDate
- the date and time when the subscription got actually activated. This can happen seconds after thecreateSubscription
call or multiple minutes and in rare cases maybe even hours.paymentProviderReference
- the payment provider reference might not be known upfront when thecreateSubscription
mutation was used. This allows setting this reference at a later point.country
- this value defines in which (or for which) country the subscription was purchased. If your business rules allow it, you can change the country of an end user also at a later point in time.
Mutation createSubscriptionTransaction
In addition to the subscription details, all the successful and failed
payments should also be added to the Mosaic Billing Service. There will
be a createSubscriptionTransaction
mutation that takes the following
parameters:
Parameter |
Type |
Description |
Example |
---|---|---|---|
transactionType |
enum (PAYMENT, REFUND, PAYMENT_FAILED) |
The type of the transaction:
|
PAYMENT |
subscriptionId |
UUID |
The ID of the subscription to which this transaction belongs |
f1501830-8c7d-4fb6-ae3b-4b2b7dc1d8df |
paymentProviderKey |
string |
The identifier of your/one of your custom payment connectors. The prefix is always “CPC_” for custom payment connectors. |
CPC_STRIPE |
paymentProviderReference |
string (optional) |
The reference to the transaction/invoice in the payment provider system. |
in_1KxXcGIAN5unBbs0jhKrdTqJ |
totalPrice |
decimal (optional) |
The amount that was paid in the selected currency. Up to 5 decimal places are supported. It must be a number greater or equal to zero. |
9.99 |
currency |
ISO 4217 currency (optional) |
The currency that was used. |
EUR |
transactionDate |
ISO 8601 date (optional) |
The date and time when the transaction took place. The default is “now”. |
2022-05-06T05:52:12.71219+00:00 |
periodEndDate |
ISO 8601 date (optional) |
The period end date and time for which this transaction paid for. This is just for informational purposes. |
2022-05-06T05:52:12.71219+00:00 |
method |
string (optional) |
The actual payment method that was used. |
SEPA |
description |
string (optional) |
A description of the payment to describe to the user some details. |
Payment completed for 9.99 EUR. |
Notes:
- The price and currency are optional. Some payment providers do not
report any price or currency information while others provide only the
price but not the currency.
- If both the price and the currency are missing or if the price is missing then both are taken from the configured payment plan. If the price is provided but the currency is missing only the currency is taken from the configured payment plan but the submitted value for the price is used. This is a “best-effort” kind of mapping which means that the actually paid money might differ.
- If a country is set on the end user subscription, it will take the values for this country from the payment plan.
- If no country was set for the subscription plan or if there is no price in the system for that country it will try to take the values from the unknown country (XX) if one is defined.
- Otherwise, it will take the first available price from the payment plan that it can find. As a hard fallback, it will use 1 as the price and “XXX” as the currency. Please check such cases by requesting the inserted currency and log cases where the currency is “XXX“ and resolve them.
- The
paymentProviderReference
is used as an idempotency key. This key must be unique per payment provider. CallingcreateSubscriptionTransaction
while there is already a subscription with this reference in the system will silently ignore the create operation and only return the requested data. - The end user ID is taken from the subscription (found via subscriptionId). Therefore the end user ID is not needed as an input parameter.
Mutation updateSubscriptionTransaction
Transactions can be created and updated - but their type, price, and currency are unchangeable. This is basically also the meaning of the term “transaction”. If a transaction was wrongly added a transaction of the opposite type should be done to even them out. For example, if there was a PAYMENT transaction of 4.99 EUR but it should have been 9.90 EUR a REFUND transaction can be sent for -4.99 EUR stating in the description that this is a reversal of the 4.99 EUR one. Then the actual transaction of 9.99 EUR should be sent.
Changes can only be done for informational fields. The following fields can be updated:
paymentProviderReference
- the payment provider reference might not be known upfront when e.g. an invoice was created.transactionDate
- that might initially be the date of the invoice but can later be updated to the date and time when the money actually arrived.periodEndDate
- payment providers report the period end date often in other events than the transaction events. This gives the option to update this date.method
anddescription
- those fields can be updated as well.
Subscription recurring payments
A subscription is usable until the periodEndDate
is reached. A new
payment must be made to extend the duration for another period. There
are generally two approaches for receiving new payments from payment
providers. Some payment providers handle those recurring payments on
their own. When the end date is (almost) reached they trigger a new
payment and try to get the money from the end user. Other payment
providers offer an API that the custom payment connector can call to
initiate the recurring payment process.
Once the payment is done (successfully or failed) a new transaction
should be added to the Mosaic Billing Service via the
createSubscriptionTransaction
mutation.
And the payment connector should update the subscription to reflect the
new periodEndDate
via the updateSubscription
mutation.
Subscription cancellation
A subscription will automatically recur after the billing end date is
reached. If an end user does not want to continue with his subscription
anymore he can cancel it. The subscription will be fully usable until
the periodEndDate
is reached. But the payment connector will not
collect money anymore.
The process how to cancel a subscription is payment gateway specific:
- Some payment providers offer an API that can be called by your payment connector to cancel a subscription.
- Some payment providers allow the user to go into his profile on the payment provider side and cancel the subscription manually.
- Some of the payment providers offer also both options.
How the payment connector knows about cancelled subscriptions:
- In many cases, the payment providers are using webhooks. They call a webhook endpoint of your custom payment connector to let you know that some subscription was cancelled.
- In other cases, the payment providers offer APIs to check if
subscriptions are cancelled. You would need to use some job scheduler to
regularly check if subscriptions were cancelled. Especially at the end
of the subscription
periodEndDate
. - If your payment connector called the payment provider API to cancel a subscription you obviously know that the subscription was cancelled.
Once the payment connector knows that the subscription is cancelled it
must update the subscription in the Mosaic Billing Services. It should
use the updateSubscription
mutation, set the lifecycleStatus
to
CANCELLED
, and provide a reason for the change via
lifecycleStatusChangeReason
(e.g. “Cancelled by customer” or
“Cancelled by a support agent”). The period end date should normally be
left untouched.
If a subscription should be ended immediately, this can again be
achieved using the updateSubscription
mutation. The lifecycleStatus
should then be set to ENDED
. A reason for the change has to be
provided via lifecycleStatusChangeReason
(e.g. “Fraud” or
“Chargeback”). The period end can be set to “now”.
Process implementation example
The following diagram shows the potential flows for creating a subscription via a custom payment connector, how recurring payments are handled, and how subscription cancellation is done.
The “alt” boxes show alternative ways on how the flow can work which were described above.
Setup custom payment connector
The Billing Service has a list of managed payment providers and offers a GraphQL API to enable them per environment. Custom payment connectors need to be registered in the Billing Service so they can be selected in subscription plans and payment plans.
The mutations createPaymentProvider
, updatePaymentProvider
, and
deletePaymentProvider
can be used to register custom payment connectors (and
managed payment providers).
You can use the following GraphQL mutation to register Stripe as a custom payment connector. All custom payment connector keys must start with the prefix “CPC_”. Every custom payment connector can be added only once (same as managed payment providers).
mutation registerPaymentProvider {
createPaymentProvider(
input: { paymentProvider: { key: "CPC_STRIPE", title: "Stripe" } }
) {
paymentProvider {
key
title
}
}
}
You can register custom payment providers also from the Mosaic admin portal.