Payment gateway
Introduction
vcita allows integrating your preferred 3rd party payment gateway in an easy and convenient way.
In order to integrate a payment gateway with vcita, you’ll need to build a middleware app that interacts with vcita on one hand, and on the other hand, with the 3rd party payment gateway.
Payment gateway integration is built upon the following building blocks:
- Connect/Disconnect - the process of connecting (or disconnecting) to the payment gateway
- Checkout - online payment
- Charge - the ability to charge via the back office
- Card On File - storing users' credit card information for future transactions
- Refund - Refunding payments
Connect is mandatory
checkout and Charge can be used independently
card on file and refund are optional features
Creating the middleware app
Step 1. Register your app on vcita
Registering your app in vcita is done using this API endpoint: https://developers.vcita.com/reference/token-management#post_apps
Step 2. Routes
Your app needs to have specific routes that vcita can interact with on each one of the events during the integration and payment processes.
GET /connect
GET /disconnect
POST /payment/settings
GET /charge
POST /charge
POST /customer
POST /customer/:token/attach
POST /customer/:token/detach
POST /refund
Step 3. Building the app components
Connect/Disconnect
The Connect process is the initial configuration of the payment gateway with a given vcita account.
This is a one-time operation that sets up the account with the payment gateway.
Connecting (or disconnecting ) to the payment gateway is done via Settings > Services > Payments.
Upon a Connect/Disconnect click event, we will open a dialog window and redirect to:
Redirect /connect?b_uid=BUSINESS_UID&redirect_url=REDIRECT_URL
Once the Connect/Disconnect process ends on your end, you’ll need to:
- Send a redirect request to the redirect_url we sent you at first.
To that redirect URL, you need to append an additional query param. This param should update the Connect button on the payments settings page with the updated connect state:
{redirect_url}?connect=true
{redirect_url}?disconnect=true
- Sending the following POST request, which lets vcita know the connection status, default payment app, and additional parameters, if relevant.
POST https://api.vcita.biz/platform/v1/payment/settings
Payload:
{
"payment_settings": {
"external_{APP_NAME}_connected": true,
"payments_gateway_type": "{APP_NAME}",
"external_{APP_NAME}_params": {
"merchant_id": "{MERCHANT_ID}"
}
}
}
- “external_{APP_NAME}_connected”: true/false - Is your payment gateway connected or not (true/false)?
- "payments_gateway_type": "APP-NAME" - Sets the payment gateway as the default payment app
- "merchant_id": "MERCHANT_ID" - The merchant ID received from the payment gateway. This ID will be populated on your OP.
Updating the UI
While the POST request updates the Connect status on the backend and the redirect URL updates the UI, it’ll still be needed to click the Save button on the payment settings page in order to also update the application state accordingly.
Checkout
Checkout is an online payment.
An online payment session can start in a variety of ways, like sending your clients a payment link that takes them to the payment checkout page, or by inviting them to the clients portal from where they can pay for invoices, etc.
A checkout session starts with the client landing on vcita’s checkout page, where he can place or view the payment value.
- The user lands on the online payment page and fills in the payment information (amount, notes, etc.).
It’s important to note that at that point the user is still interacting with vcita.

- By clicking the Continue button, vcita will redirect the user to your app’s redirect_uri along with two URL parameters: b_uid (pivot UID) and url_key.
GET {application_redirect_uri}/checkout/:business_uid/:url_key
- Next, your app sends vcita an API request using that URL key. As a response vcita returns the transaction details.
(you can use the business_uid value in case you have the business API token stored or generate it via OAuth instead of using your directory token)
(Request details here)
GET https://api.vcita.biz/platform/v1/payment/checkout/url_key
-
At that point, you want to redirect to your payment gateway page, where the user can place the credit card information.
Note - everything happening inside that window is handled entirely by the payment gateway.
vcita’s payment page will remain open in the background during that time and awaits a response from your app. -
Upon payment success (or alternately when the payment gateway accepts the payment request) redirect to:
https://vcita.application.domain/portal/business_id?
fromCheckout=true#/loader?
provider=external&
status=success&
key=url_key
- Upon payment failed redirect to:
https://vcita.application.domain/portal/business_id?
fromCheckout=true#/loader?
provider=external&
status=error&
key=url_key
- Send checkout update by webhook to:
(Request details here)
https://api.vcita.biz/platform/v1/payment/checkout/
- Once approved, we will redirect the user to the final Thank You page, and by that end the checkout session.

Charge
The charge flow is the ability to charge credit cards from the back office, by adding your application iFrame inside vcita’s UI where the business can enter the credit card information in a secure way.
- vcita embeds your iFrame inside the Charge window, by requesting the iFrame page from GET /charge

- Interacting with the iFrame via JavaScript postMessage
Once the user places all the required information inside the iFrame (card number, date, etc.) and clicks the Charge button, vcita will interact with the iFrame and send it a POST message (JavaScript postMessage) with the following object:
POST message object:
{
type: 'generic',
func: 'getToken',
params: {
amount: params.amount,
save_card: params.save_card,
pivot_id: params.thryv_id,
client_id: params.client_id
}
}
- In return, we are expecting a token:
{
token: TOKEN
}
This token will be used throughout the payment process for identifying the card and transaction.
- Once the token is received, vcita sends a POST request to your application (/charge), containing the transaction details:
POST /charge
body request
{
"amount": 10,
"currency": "USD",
"token": "addtkthQ16trAsldSar50v6sLfdmuQ",
"description": "30 minutes phone call",
"customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7"
}
customer_id
customer_id is optional and depends on the implementation of the “card on file” feature.
- Your app processes the payment with the payment gateway and responds with a charge_key value:
{
"charge_key": "DzlrBcilbnvBd48gca8um3AkNHoj85"
}
The Charge flow ends when we are successfully receiving the charge_key value.
charge_key
The charge_key can be later used for the refund process.
-
At that point, the payment dialog closes, and we will show a success page.
-
Upon transaction failure, you can send an error response (instead of ‘charge_key’) with the error message to be presented to the user.
{
"error": "ERROR MESSAGE"
}
Card on file
Card on file is the ability to save credit card information for future use, instead of users entering their credit card information repeatedly.
The credit card information itself should be stored on the payment gateway, and vcita will only save the following:
- last 4 digits
- card brand
- expiration month
- expiration year
- cardholder name
Listening to save card events
Some payment gateways require additional address-related information for saving cards that is not necessarily required otherwise when not saving clients' cards.
When processing the saved card with the payment gateway, the PGW generates a token for the saved card for future use. In order to generate that token, the payment app must pass along the client’s address information, otherwise, the save card process will fail.
In order for the payment app’s iFrame to know whether the “Save this card” checkbox in the charge dialog is selected or not, vcita created a new event that the iFrame will listen to, that indicates the “Save this card” checkbox value.
When clicking the "Save this card" checkbox, vcita triggers an event called "setSaveCard" that should include a "checked" param with a true/false value - indicating the checkbox state.
The payment app’s iFrame can listen to that event just as it’s currently listening to the other events we're triggering (like the "getToken" for example).
iFrame host-window indication
Since cards can be saved from either the charge dialog or via the client’s card by clicking the Add Card button, the app needs an indication for whether its iFrame is opened via the Charge or Add Card dialog.
When the iFrame is opened via Add Card - the app will know to save the card by default.
In order to accomplish that, vcita is passing another query param to the iFrame’s URL only when it’s being opened via the Add Card dialog:
"?save_card=true"
This way, the iFrame “knows” the host window is the Add Card and can automatically save the card.
Saving card-on-file on charge
The charge dialog contains a checkable input that allows users to select whether to save their card for future use when entering the credit card information in the iFrame.

- When checked, vcita will send your app a POST request with the user’s email and name.
POST /customer
body request
{
"email": "[email protected]",
"name": "John Doe"
}
- As a response, we expect a customer id value. The customer id is the identifier of the credit card.
{
"customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7"
}
- vcita sends the following POST request with the customer id that was received.
This is a one-time process for newly created/saved cards.
POST /customer/:token/attach
body request
{
"customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7"
}
- Expected response:
{
"card": {
"card_id": "addtkthQ16trAsldSar50v6sLfdmuQ",
"card_info": {
"card_brand": "hNO0G",
"last_4": 1217,
"exp_month": 10,
"exp_year": 2030,
"cardholder_name": "CwdvX"
}
},
"customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7"
}
- Removing saved cards is done by vcita sending a request to:
POST /customer/:token/detach
body request
{
"customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7"
}
Expected response:
{
"token": "addtkthQ16trAsldSar50v6sLfdmuQ"
}
Saving card-on-file on checkout
Get payment information from vcita (make sure that “allow_save_card” is true):
If allow_save_card is false, either the client already has 3 cards saved, or the “checkout_vaulting” feature flag is missing for that account.
Saving cards on checkout is done in two steps:
- Make sure that the save card feature is available at the account level.
When sending the GET request to /checkout/:url_key as part of the usual checkout flow, make sure that the value of the “allow_save_card” property is true.
GET /checkout/:url_key
{
"status": "OK",
"data": {
"amount": "33.0",
"currency": "USD",
"name": "something3",
"return_url": "https://clients.meet2know.com/portal/5e3c760d?fromCheckout=true#/loader",
"email": "[email protected]",
"client_id": "zlbsfegs493u9zmo",
"invoice_id": null,
"allow_save_card": true
}
}
- If “allow_save_card” is true, you can proceed with the checkout flow by appending the customer id and the card information when sending the payment checkout update request.
PUT https://api.vcita.biz/platform/v1/payment/checkout/
body request:
{
"url_key": "ijGghOYFKTFClDWJQZSNzkaZDZNQOiksktubFXpXfWmdovxuSz",
"card":{
"card_id": "15dsanida54",
"card_info": {
"exp_month": "01",
"exp_year": "2025",
"last_4": "6666",
"card_brand": "visa",
"cardholder_name": "myName"
}
},
"customer_id": "49v0ud9YhquOoYTczn0PkwdRn9QRb7",
"created": "2020-11-26",
"transaction_id": "12qw34rt56yu",
"type": "checkout.session.completed"
}
Expected response:
{
"status": "OK",
"data": {}
}
Refund
When the Refund button is clicked from the back office (located on the payment page), vcita will send the transaction’s charge key to your app.

This charge_key value is the same one that we received from your app when the initial transaction occurred, so you know the exact transaction ID that needs to be refunded.
POST /refund
body request
{
"charge_key": "DzlrBcilbnvBd48gca8um3AkNHoj85"
}
Expected response when the refund process completes on your payment gateway:
{
"success": "true",
"data": {
"refund_id": "uWND98GwGQlQyFo8tqFGbN1iDKKPho"
}
}
Updated 2 months ago