Build a working payment connector in under 10 minutes
This guide will walk you through creating a basic payment connector using the VTEX Payment Provider Framework. You’ll have a working connector that can authorize, cancel, and settle payments.
Create your payment connector by extending the PaymentProvider class:
node/connector.ts
import { AuthorizationRequest, AuthorizationResponse, CancellationRequest, CancellationResponse, Cancellations, PaymentProvider, RefundRequest, RefundResponse, Refunds, SettlementRequest, SettlementResponse, Settlements, Authorizations,} from '@vtex/payment-provider'import { randomString } from './utils'export default class MyPaymentConnector extends PaymentProvider { // Authorize a payment public async authorize( authorization: AuthorizationRequest ): Promise<AuthorizationResponse> { // Call your payment gateway to authorize the transaction // For this example, we'll approve all payments return Authorizations.approve(authorization, { authorizationId: randomString(), nsu: randomString(), tid: randomString(), }) } // Cancel a payment public async cancel( cancellation: CancellationRequest ): Promise<CancellationResponse> { // Call your payment gateway to cancel the transaction return Cancellations.approve(cancellation, { cancellationId: randomString(), }) } // Refund a payment public async refund(refund: RefundRequest): Promise<RefundResponse> { // Call your payment gateway to refund the transaction return Refunds.deny(refund) } // Settle (capture) a payment public async settle( settlement: SettlementRequest ): Promise<SettlementResponse> { // Call your payment gateway to capture the authorized amount return Settlements.approve(settlement, { settleId: randomString(), }) } // Inbound webhook handler (optional) public inbound: undefined}
Each method receives a typed request object and must return a typed response. The framework provides helper functions like Authorizations.approve() and Cancellations.deny() to construct valid responses.
Create the payment provider service in node/index.ts:
node/index.ts
import { PaymentProviderService } from '@vtex/payment-provider'import MyPaymentConnector from './connector'export default new PaymentProviderService({ connector: MyPaymentConnector,})
That’s it! The PaymentProviderService automatically sets up all required routes:
GET /manifest - Connector manifest and capabilities
GET /payment-methods - Supported payment methods
POST /payments - Payment authorization
POST /payments/:paymentId/cancellations - Payment cancellation
POST /payments/:paymentId/settlements - Payment settlement (capture)
POST /payments/:paymentId/refunds - Payment refund
POST /payments/:paymentId/inbound/hooks - Inbound webhooks
When processing card payments, you’ll receive card data in a secure format. Here’s how to handle different card types:
node/connector.ts
import { isCardAuthorization, isBankInvoiceAuthorization, isTokenizedCard, AuthorizationRequest, AuthorizationResponse, Authorizations,} from '@vtex/payment-provider'export default class MyPaymentConnector extends PaymentProvider { public async authorize( authorization: AuthorizationRequest ): Promise<AuthorizationResponse> { // Check if this is a card payment if (isCardAuthorization(authorization)) { const { card } = authorization // Check if card is tokenized or has raw data if (isTokenizedCard(card)) { // Use card.token for tokenized cards const cardToken = card.token } else { // Use card.number, card.csc for non-tokenized cards // These will be encrypted tokens when using Secure Proxy const cardNumber = card.numberToken const cvv = card.cscToken } } // Check if this is a bank invoice payment if (isBankInvoiceAuthorization(authorization)) { // Return a payment URL for the customer return Authorizations.pendingBankInvoice(authorization, { paymentUrl: 'https://payment-gateway.com/invoice/12345', delayToCancel: 600000, // 10 minutes tid: randomString(), }) } return Authorizations.approve(authorization, { authorizationId: randomString(), nsu: randomString(), tid: randomString(), }) }}
For payments that are processed asynchronously (like bank invoices or redirect flows), use the retry mechanism:
node/connector.ts
export default class MyPaymentConnector extends PaymentProvider { public async authorize( authorization: AuthorizationRequest ): Promise<AuthorizationResponse> { // For async payments, return pending status initially const response = Authorizations.pending(authorization, { delayToCancel: 300000, // 5 minutes tid: randomString(), }) // Later, when payment is confirmed, use callback to notify VTEX this.callback(authorization, Authorizations.approve(authorization, { authorizationId: 'gateway-auth-id', nsu: randomString(), tid: randomString(), })) return response }}
The callback() method tells VTEX Gateway to retry the authorization request. Your connector must return a consistent response (approved or denied) when called again with the same paymentId.
// Approve a paymentAuthorizations.approve(request, { authorizationId, nsu, tid })// Deny a paymentAuthorizations.deny(request, { tid })// Return pending statusAuthorizations.pending(request, { delayToCancel, tid })// Redirect to external pageAuthorizations.redirect(request, { redirectUrl, delayToCancel, tid })
You now have a fully functional payment connector! The example approves all payments, but you can replace the logic with actual API calls to your payment gateway.