Mosaic products documentation: Concepts, API Reference, Technical articles, How-to, Downloads and tools

Billing Service 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:

End-UserEnd-UserClient AppClient AppMosaic Billing Service APIMosaic Billing Service APIPayment Connector APIPayment Connector APIPayment Gateway API/WebPayment Gateway API/Weblist subscription plansget active subscriptionand payment planspurchase payment planinitiate subscription flowfinalize subscription flowpurchaseshow purchase resultwebhook calls for initialand future eventsregister subscriptionupdate subscriptionregister payments(update payments)Figure 1. High-level sequence flow
Figure 1. High-level sequence flow

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:

  1. 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 as paymentProviderReference. This value will be stored in the Mosaic subscription in the field paymentProviderReference and can later be queried.

  2. 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 PENDING_ACTIVATION.

ACTIVE

periodEndDate

ISO 8601 date (optional)

The date and time when the current period of the subscription will end. The default value is undefined.

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 XX.

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.

  • ACTIVE_PLANS: skip the check that ensures that a subscription can only be created for active payment and subscription plans.

  • COUNTRY_PRICE: skip the check that a price must be configured for the country of the user.

  • SINGLE_SUBSCRIPTION: skip the check that makes sure that a user can only have one active subscription.

[
“SINGLE_SUBSCRIPTION”,
”COUNTRY_PRICE”
]

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:

  1. 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.

  2. 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.

  3. 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 the PENDING_ACTIVATION state and set it to ACTIVE once the purchase flow is finished successfully.

    • lifecycleStatusChangeReason - If the lifecycleStatus is updated, a reason for the change must be provided. This will add an entry to the subscriptionStatusChanges 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 the createSubscription call or multiple minutes and in rare cases maybe even hours.

  • paymentProviderReference - the payment provider reference might not be known upfront when the createSubscription 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: a successful transaction with an totalPrice larger than zero

  • refund: a transaction for refunding money back to the purchaser. The totalPrice must be a negative number (smaller than zero).

  • failed payment: The totalPrice must always be zero.

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. Calling createSubscriptionTransaction 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 and description - 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.

End-UserEnd-UserClient AppClient AppBilling Service APIBilling Service APIBilling Service Management APIBilling Service Management APIPayment Connector APIPayment Connector APIPayment Gateway API/WebPayment Gateway API/Webopen page to see availablesubscription plansand payment plansquery subscriptionPlans(including payment plans, prices &payment provider plan references)select payment plan andcustom payment connectore.g. POST /start-checkout(paymentPlanId, JWT, ...)alt[Store mapping on Mosaic side]e.g. POST /subscription(providerPlanReference)returns identifier and redirect URLmutation createSubscription(paymentPlanId, identifier,paymentProviderKey, ...)[Store mapping on payment provider side]mutation createSubscription(paymentPlanId,paymentProviderKey, ...)returns subscriptionIde.g. POST /subscription(providerPlanReference,subscriptionId)returns redirect URL (and identifier)redirectfill in and submitpayment formalt[Check subscription during redirect]redirect success/cancel/errore.g. GET /subscription(identifier)returns subscription with statusmutation updateSubscription(subscriptionId, lifecycleStatus,periodEndDate, ...)redirect to success (subscriptionId, identifier) or cancel/error page[Redirect directly to client]redirect to success (subscriptionId, identifier) or cancel/error page[optional] WebSocket subscription to lifecylce status changessubscription subscriptionLifecycleStatusMutated (JWT)subscriptionId, old and new lifecycle statusWebhooks (no guaranteed order)subscription createdmutation updateSubscription(subscriptionId, activationDate, ...)HTTP 2xxsubscription updatedmutation updateSubscription(subscriptionId, lifecycleStatus,periodEndDate, ...)HTTP 2xxpayment successmutation createSubscriptionTransaction(transactionType, subscriptionId, price,currency, paymentProviderReference, ...)HTTP 2xxpayment errormutation createSubscriptionTransaction(transactionType, subscriptionId, description,currency, paymentProviderReference, ...)HTTP 2xxpayment refundmutation createSubscriptionTransaction(transactionType, subscriptionId, price,currency, paymentProviderReference, ...)HTTP 2xxPolling (if webhooks are not available)worker job poll subscription statuse.g. GET /subscription(identifier)returns subscription with statusmutation updateSubscription(subscriptionId, lifecycleStatus,periodEndDate, ...)Figure 2. Subscription process flow example
Figure 2. Subscription process flow example

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.