This is a feature in BETA stage, which means it's on a testing phase. In case there is a new scenario that PPF is not ready, our team will take some time to perform an investigation. If it's a case that need the development of anything new, this will enter the process of prioritization of the product team. This can take some time, so we don't recommend the use of this Beta version of PPF for connectors related to stores with rollout date close (less than 3 months).
If you're starting a brand new project, we recommend you clone the example repository, as it already has all the basic configuration setup.
Your first step should be to run the following command on your node folder:
yarn add @vtex/payment-provider
Afterwards, go to your package.json and make sure it has been added as a dependency with the correct version:
"@vtex/payment-provider": "1.x",
Also check in the package.json is the version of vtex/api, which should be listed in the devDependencies as follows:
"@vtex/api": "6.x",
(When linking your app, this version might get updated to a later 6.x version, which is fine.)
In case it's not listed as a devDependency, run the following command on your node folder:
yarn add -D @vtex/api
ℹ️ Info: If you get any type errors or conflicts in your project related to @vtex/api, follow these steps to resolve the problem: delete the node_modules folder and the yarn.lock file from both your project root and your project's node folder, then run the command yarn install -f in both folders.
Lastly, in your manifest.json, you should check the builders section, in which you must include the paymentProvider in it's current version:
"builders": {
"node": "6.x",
"paymentProvider": "1.x"
}
ℹ️ Info: This will add policies to callback the Payment Gateway APIs and also expose Payment Provider protocol routes.
Now, in order to create your service, you must implement your payment provider connector and the service itself. To help you with them, keep reading the next sections.
This is an abstract class with the signatures of the routes functions required in your connector, according to the protocol.
You must create a new class extending the PaymentProvider
, which must implement a function for each route. The functions will receive the request body (when there is one) as a parameter and the response must be returned as an object, such as the example shown below:
import {
PaymentProvider,
// ...
} from '@vtex/payment-provider'
class YourPaymentConnector extends PaymentProvider {
// ... implementation of the other routes functions
}
Typescript should automatically check for typing errors, but if you need, you can check the requests and responses signatures here.
In order to specify which payment methods the connector will accept to process, you need to create a folder named paymentProvider using the following folder structure
node
paymentProvider
manifest.json
Then, inside paymentProvider folder you must create a file named configuration.json
node
paymentProvider
|--configuration.json
manifest.json
Next, declare the accepted payment methods, for instance:
{
"name": "MyConnector",
"paymentMethods": [
{
"name": "Visa",
"allowsSplit": "onCapture"
},
{
"name": "American Express",
"allowsSplit": "onCapture"
},
{
"name": "Diners",
"allowsSplit": "onCapture"
},
{
"name": "Elo",
"allowsSplit": "onCapture"
},
{
"name": "Hipercard",
"allowsSplit": "onCapture"
},
{
"name": "Mastercard",
"allowsSplit": "onCapture"
},
{
"name": "BankInvoice",
"allowsSplit": "onAuthorize"
}
]
}
By doing this you don't need to declare /manifest or /payment-methods route, it will be implemented automatically by the builder.
You can also override the default generated routes by redeclaring it on service.json
{
"memory": 256,
"ttl": 10,
"timeout": 10,
"minReplicas": 2,
"maxReplicas": 3,
"routes": {
"authorize": {
"path": "/_v/api/my-connector/payments",
"public": true
},
"cancel": {
"path": "/_v/api/my-connector/payments/:paymentId/cancellations",
"public": true
},
"settle": {
"path": "/_v/api/my-connector/payments/:paymentId/settlements",
"public": true
},
"refund": {
"path": "/_v/api/my-connector/payments/:paymentId/refunds",
"public": true
},
"inbound": {
"path": "/_v/api/my-connector/payments/:paymentId/inbound/hooks",
"public": true
}
}
}
Then you must specify which is the new serviceUrl
on paymentProvider/configuration.json
{
"name": "MyConnector",
"serviceUrl": "/_v/api/my-connector",
"paymentMethods": [
{
"name": "Visa",
"allowsSplit": "onCapture"
},
{
"name": "American Express",
"allowsSplit": "onCapture"
},
{
"name": "Diners",
"allowsSplit": "onCapture"
},
{
"name": "Elo",
"allowsSplit": "onCapture"
},
{
"name": "Hipercard",
"allowsSplit": "onCapture"
},
{
"name": "Mastercard",
"allowsSplit": "onCapture"
},
{
"name": "BankInvoice",
"allowsSplit": "onAuthorize"
}
]
}
⚠️ Important: Prefer using default generated routes!
The manifest route is special, it is automatically generated by the builder, our payment gateway exposes it as a proxy of your app.
Generally speaking, the manifest route makes no difference at runtime, and if you have a use case to override the default route tell us.
But, if you want to override it anyway you have to add special parameters on it:
{
"memory": 256,
"ttl": 10,
"timeout": 10,
"minReplicas": 2,
"maxReplicas": 3,
"routes": {
"manifest": {
"path": "/_v/api/my-connector/manifest",
"handler": "[email protected]/providerManifest",
"headers": {
"x-provider-app": "$appVendor.$appName@$appVersion"
},
"public": true
}
}
}
Pay attention on x-provider-app
. It should be updated every time that your major changes. Example:
[email protected]
should be[email protected]
The same applies to payment-methods route.
You can also omit the handler
and headers
parameters, by doing it you will need to implement it by your own
Along with manifest fields (paymentMethods
and customFields
) there are another configurable options:
serviceUrl
(required, default: auto-generated for IO Connectors)- A valid url (can include relative paths)
implementsOAuth
(default: false)- true - The provider implements the configuration flow supporting OAuth.
- false - The provider dosnt implements the configuration flow
implementsSplit
(default: false)- true - The provider implements can receive recipients on payment flow (capture or authorization)
- false - The provider doesn't implements the split flow
usesProviderHeadersName
(default: true, for IOConnectors it should be true)- true - The provider will reiceve appKey and appToken headers as
"x-provider-api-appKey"
&"x-provider-api-appToken"
- false - The provider will reiceve appKey and appToken headers as
"x-vtex-api-appKey"
&"x-vtex-api-appToken"
- true - The provider will reiceve appKey and appToken headers as
usesAntifraud
(default: false)- true - The provider can be used along antifrauds.
- false - The provider can't be used along antifrauds
usesBankInvoiceEnglishName
(default: false)name
(required)- The connector name
usesSecureProxy
(default: true)- true - The provider can process payment without being PCI-Certified, the connector will receive a secureProxyUrl on createPayment flow, and the card encrypted data.
- false - The provider MUST be a PCI-Certified entity, and we should receive the AoC containing the provided serviceUrl. Apps implemented within VTEX IO cannot have the secureProxy disabled, this option only works for a configuration app.
requiresDocument
(default: false)- true - The customer must include the card holder document on checkout. A new field will appear on checkout form.
- false - The customer doesn't need to include card holder document.
acceptSplitPartialRefund
(default: false)- true - Partial refund will be sent when payment split occurs.
- false - The connector couldn't process partial refund when payment split occurs.
usesAutoSettleOptions
(default: false)- true - The client will be able to choose the behaviour of the auto settlement in the VTEX admin configurations of the provider. The options available are the following: Use behavior recommended by the payment processor, Automatic capture immediately after payment authorization, Automatic capture immediately after anti-fraud analysis, Deactivated: Not automatically captured.
- false - The connector won't have this dropdown configuration field for auto settlement.
A retry is required in order to develop your connector according to the protocol, so we built a function, which can be invoked like shown below:
this.retry(request)
Callback flow is replaced by retry flow. Payment Providers implemented using VTEX IO are not able to callback the Payment Gateway with the Payment status updated. Instead, the retry flow allow the connector to ask the Payment Gateway to call create payment route again. The connector should be able to respond approved/denied consistently.
This is a class that extends the Service from @vtex/api
. You must invoke it passing the developed connector as a property of the first parameter and it will automatically setup the required routes for you.
import {
PaymentProviderService,
} from '@vtex/payment-provider'
new PaymentProviderService({
connector: YourPaymentConnector,
})
By default, the Payment Provider Service declares the following routes:
- /payment-methods
- /manifest
- /payments
- /settlements
- /refunds
- /cancellations
- /inbounds
If your service requires any extra routes, you must declare them separately and use them as parameters:
new PaymentProviderService({
routes: newRoutes,
connector: YourPaymentConnector,
})
If your connector requires any extra clients, you must also pass them in the parameters along with the connector:
new PaymentProviderService({
clients: NewClients,
connector: YourPaymentConnector,
})
Those who aren't PCI-certified, could use Secure Proxy to make calls to a PCI-Certified endpoint.
⚠️ Important: The endpoint must be allowed by VTEX Secure Proxy by sending the AOC with the wanted endpoint.
⚠️ Important: Currently we only accept two Content-Types:application/json
orapplication/x-www-form-urlencoded
. Any other Content-Type will not be supported by the Secure Proxy.
In order to make calls over our Secure Proxy, you must:
-
Extend
SecureExternalClient
abstract class. In the code example below, it means that VTEX allowshttp://my-pci-certified-domain.com
as one of the trusted destinations by receiving its AOC.import { SecureExternalClient } from '@vtex/payment-provider' import type { InstanceOptions, IOContext } from '@vtex/api' export class MyPCICertifiedClient extends SecureExternalClient { constructor(protected context: IOContext, options?: InstanceOptions) { super('http://my-pci-certified-domain.com', context, options) } // ... }
-
Set secure proxy URL on the request that you want to be proxied:
import { SecureExternalClient, CardAuthorization } from '@vtex/payment-provider' import type { InstanceOptions, IOContext, RequestConfig, } from '@vtex/api' export class MyPCICertifiedClient extends SecureExternalClient { constructor(protected context: IOContext, options?: InstanceOptions) { super('http://my-pci-certified-domain.com', context, options) } public myPCIEndpoint = (cardRequest: CardAuthorization) => { return this.http.post( 'my-pci-endpoint', { holder: cardRequest.holderToken, number: cardRequest.numberToken, expiration: cardRequest.expiration, csc: cardRequest.cscToken }, { headers: { Authorization: 'my-pci-endpoint-authorization', }, secureProxy: cardRequest.secureProxyUrl, } as RequestConfig ) } }
ℹ️ Info: SecureProxyURL is received on createPayment flow
Now that we have a new connector ready to be use, we can test it entirely in the production flow
using your store's checkout. To submit a request to add an account to test IO connectors, you can use the workflow "Allow Account to test"
in the #provider-review
slack channel.
❗Attention: The account MUST BE ALLOWED to use IO Connectors!
❗Attention: For processing NEW payment methods, their creation must be requested!
A prerequisite for this step is to have products for sale at your store for testing
-
Launch a beta version of your connector, e.g.
[email protected]
-
Install the beta version on
master
workspace (wait ~1 hour) -
Go to
https://${account}.myvtex.com/admin/pci-gateway/#/affiliations/vtex-payment-provider-test-v0/
The format is:
${vendor}-${appName}-${appMajor}
-
Change the toggle configuration to
Test
-
Click save and refresh page
-
Enter again in the saved configuration and you will notice that a new field appears, called
workspace
-
Set the
workspace
as you wish (you can leave it asmaster
) -
Configure a payment condition with your newly created connector and wait 10 minutes to appear on checkout!
⚠️ Important: If you want to make your connector available to all accounts, make sure to have the billing options field in your manifest
The publication process is made via app store, more info on how to do that here:
Submitting your app in the VTEX app store
After the homolog step is complete, your app needs to be installed in the account that wants to use it, and after that, a new affiliation will be available to configure it.
The app should be available at apps.vtex.com
.