How to build a custom payments integration on the platform

Modified on Sun, 27 Oct at 5:29 AM

There are four major steps to integrating any payment gateway.

  1. Have an account on the platform to be able to create and launch marketplace Apps.

  2. Create a marketplace App in custom payment provider category.
  3. Create a service running in any cloud provider to handle all requests from the platform while payments are happening.
  4. Create publicly hosted pages for payment, authentication, and other features you want to offer to customers.
Once all above is ready, test out the integration in test mode on different payment channels in the platform. Then launch the app in marketplace.

How to create a marketplace App for payment provider

To create a marketplace App, login to the marketplace dashboard. Once logged in, create a new marketplace app with the following config.



Config for Settings page

Required scopes


  • payments/orders.readonly
  • payments/orders.write
  • payments/subscriptions.readonly
  • payments/transactions.readonly
  • payments/custom-provider.readonly
  • payments/custom-provider.write
  • products.readonly
  • products/prices.readonly


Redirect Url
This URL is used to complete the OAuth flow when your app is installed at any location. Once your app is installed at any location, the user is redirected to this given URL with a code in the query parameter. This code can be used to exchange it for an OAuth Access token which would be used for any API calls to the platform.
Example redirect URL: https://domain/path?code=0834cbd778dacf89c


OAuth Access token API


Client Keys
Store these client keys on your backend server in a secure manner. These keys will be required while making calls for OAuth flow.


Webhook URL
This URL will receive webhook events whenever an App is installed or uninstalled from a location.
Sample Uninstall webhook request


SSO Key
This SSO key should be securely stored. This will be used to decrypt the auth token received for Custom Pages (More on this later).


Payment Provider
Once the settings page config is done, let's move to creating a Payment provider. The payment provider basically ensures that the app is seen by the platform as a payments app. The config for payment provider is used to show payment provider details in App details page on marketplace. Below are the inputs required for payment Provider:

  • Name: Name of the payment provider
  • App description: App description for Payment provider
  • Payment provider type: Payment provider types specify to the platform what kind of payments are supported by your payment provider.
    • OneTime: This option indicates that one-time payments are supported by payment provider where only single-time fixed payment is collected without any kind of future payments possibility.
    • Recurring: This option indicates that the payment provider supports recurring payment where a fixed recurring charge can be created and started on payment provider. This type would mean you can support recurring products in payments, create and manage subscriptions on your end, as well as provide updates about all subscriptions to the platform via webhooks (more on this later). For example, if a subscription has a new payment, is canceled, or unpaid, so that these updates can reflect in the platform as well.
    • Off Session: This option indicates that the payment provider supports off-session payments, meaning a given customer can be charged any amount using an API not requiring any customer input/authorization. This typically works where you have the customer cards authorized on their profiles and can use those cards to charge the customer later in time.
  • Logo: Logo shown on the payment provider details.

Profile

Once all the above settings are done, we can move to the Profile section. The important bit here is to set the category to Third Party Provider. This will ensure your app shows up correctly in App Marketplace and is visible on the Payments > Integrations page for improved discoverability.


Custom Pages

To collect payment-related credentials from the user after the app is installed in a location, we recommend using a custom page. A Custom page is a public website that is loaded in an iframe inside the App details page once the app is installed on this location. For any payments app, after installation, this custom page will be opened directly, making it easier to discover for users. Also, when you go to Payments > Integrations, if your app is already installed, users are redirected to this Custom page in the App marketplace section if they click on Manage Integration in Payments > Integration > Details page.


This is all the config that is required for creating a marketplace App. Once this is done, let's move to authentication and app installation.


App Installation



Whenever your app is installed in a location, a new tab will open immediately with the OAuth code on the redirect URL provided earlier in the config.
Once the app is installed, the configured custom page is loaded.
In parallel, the software’s payments module expects an API call with some basic config for payment integration. This creates a basic config in the payments module for your payments app and starts showing the payment app as a payment option on the Integrations page. Users can manage the integration from there as well.

Create Public provider config

{ name: String, // Name of the integration shown in the software everywhere description: String, // A short description/tagline for payments app, shown in Payments > Integrations page imageUrl: String, // Public image URL for payment provider logo locationId: String, // Account ID where the app is installed queryUrl: String, // A URL receiving different requests for all queries related to payments. Ex. Verify, Refund, etc. paymentsUrl: String, // Public page URL loaded in an iframe for making payments on frontend }

Once the app is installed, the next step for users is to add relevant payment config (public keys, merchant ID, etc.) required for the configuration of this payment gateway. Two types of configs are needed for any payment provider: a test mode and a live mode config.

  • Test mode config: Used for testing payments where no real money is charged.
  • Live mode config: Used by customers for real payments where actual money is charged from valid cards/banks.
  1. When any user updates the live or test config in the App Custom Page, the platform’s payments module expects a test and live mode config update as well in the following format. The two main parameters required for test and live mode config are:

    • apiKey: This key will be used for verification in backend calls made from the software’s server to your server.
    • publishableKey: Public API key used for frontend verification while initiating payment.

  2. Connect config API

    Once the liveMode or testMode keys are added, that particular mode of payments can be used on the software’s payments module. The last step is to set your app as a default payment provider for that account. This can be done in Payments > Integrations > Your app > Set as Default.


    How the payment flow works

    The payment flow to collect any payment is outlined in the above diagram. The iframe events are defined below.Once the paymentUrl is loaded in an iframe, the software expects a ready event, which should ideally be dispatched once the iframe is loaded completely and is ready to receive payment data and process payment. Once the ready event is dispatched by the iframe, the platform dispatches a data event sending all the data needed for the iframe to process the payment.


    Ready event dispatched by payment iframe

    { type: 'custom_provider_ready', loaded: true }

    Payment data event dispatched by the software

    typescript
    Copy code
    { type: 'payment_initiate_props', publishableKey: String, // Publishable key sent while connecting integration API amount: Number, // Amount in decimal currency with max 2 decimal places currency: String, // Standard 3-letter notation for currencies ex. USD, INR mode: String, // Payment mode: subscription/payment productDetails: {productId: string, priceId: string}, // productId and priceId for recurring products. More details can be fetched using the public API for Products/Prices contact?: { // Customer details for customer placing the order id: String, // Customer id in the software name: String, // Full name of the customer email: String, contact: String, // Contact Number of customer with country code }, orderId: String, // Software's internal orderId for given order transactionId: String, // Software's internal transactionId for the given transaction subscriptionId: String, // Software's internal subscriptionId passed in case of a recurring product locationId: String, // Account id for which the given order is created. }

    Once the payment data event is dispatched, the iframe should start the payment process. After the payment is completed, the platform expects the following events for different outcomes:

    Payment is successful

    rust
    Copy code
    { type: 'custom_element_success_response', chargeId: String, // Payment gateway chargeId for given transaction }

    Payment failed

    go
    Copy code
    { type: 'custom_element_error_response', error: { description: String, // Error message to be shown to the user } }

    Payment canceled: emitted if user cancels the payment while going through the payment process

    bash
    Copy code
    { type: 'custom_element_close_response' }

    If the payment is successful, a backend API call is made to the queryUrl for verifying if the payment succeeded. If successful, it reflects on the frontend, and an appropriate action is taken, such as redirecting the user to the next


If the payment is successful, a backend API call is made to the queryUrl to verify the payment. If verified, the successful payment reflects on the frontend, and an appropriate action is taken, like redirecting the user to the next page, similar to other payment gateways.

Verify API call is sent with the following payload:

bash
Copy code
curl --location '${queryUrl}' \ --header 'Content-Type: application/json' \ --data '{ "type": "verify", "transactionId": "platform_transaction_id", "apiKey": "661d4d5a2a0167fb235f99ae", "chargeId": "demo_charge_id", "subscriptionId":"platform_subscription_id" }'

Other events/actions

Some additional events need to be supported for the payment flow. This list may expand in the future depending on requirements.


Refund event

json
Copy code
{ "type": "refund", "amount": Number, "transactionId": "Internal transaction ID against which refund is issued." }

Refund transactions can be partial, and a single transaction can have multiple refund requests with a sum of amounts less than or equal to the total transaction amount.


Webhook events

Webhook events are supported for updates to subscriptions, orders, transactions, refunds, and other actions. Currently, a few events are supported, and more will be added over time. The list of events and supported payloads will keep expanding.

Events supported by webhooks:


Was this article helpful?

That’s Great!

Thank you for your feedback

Sorry! We couldn't be helpful

Thank you for your feedback

Let us know how can we improve this article!

Select at least one of the reasons
CAPTCHA verification is required.

Feedback sent

We appreciate your effort and will try to fix the article