The PaymentProviderService class is responsible for registering your payment provider connector with the VTEX IO runtime. It handles HTTP routing, request validation, and connects your PaymentProvider implementation to the VTEX Payment Gateway.
The service is typically instantiated in your node/index.ts file:
node/index.ts
import { PaymentProviderService } from '@vtex/payment-provider'import TestSuiteApprover from './connector'export default new PaymentProviderService({ connector: TestSuiteApprover,})
Pass the class itself (constructor), not an instance. The service will instantiate your connector for each request.
import { PaymentProviderService } from '@vtex/payment-provider'import TestSuiteApprover from './connector'export default new PaymentProviderService({ connector: TestSuiteApprover,})
node/connector.ts
import { AuthorizationRequest, AuthorizationResponse, CancellationRequest, CancellationResponse, PaymentProvider, RefundRequest, RefundResponse, SettlementRequest, SettlementResponse, Cancellations, Refunds, Settlements,} from '@vtex/payment-provider'import { executeAuthorization } from './flow'import { randomString } from './utils'export default class TestSuiteApprover extends PaymentProvider { public async authorize( authorization: AuthorizationRequest ): Promise<AuthorizationResponse> { if (this.isTestSuite) { return executeAuthorization(authorization, response => this.callback(authorization, response) ) } throw new Error('Not implemented') } public async cancel( cancellation: CancellationRequest ): Promise<CancellationResponse> { if (this.isTestSuite) { return Cancellations.approve(cancellation, { cancellationId: randomString(), }) } throw new Error('Not implemented') } public async refund( refund: RefundRequest ): Promise<RefundResponse> { if (this.isTestSuite) { return Refunds.deny(refund) } throw new Error('Not implemented') } public async settle( settlement: SettlementRequest ): Promise<SettlementResponse> { if (this.isTestSuite) { return Settlements.deny(settlement) } throw new Error('Not implemented') } public inbound: undefined}
// If your connector takes too longpublic async authorize( authorization: AuthorizationRequest): Promise<AuthorizationResponse> { // This operation takes 20 seconds but timeout is 10 seconds await longRunningOperation() // Service will return timeout error to VTEX Gateway}
Solution: Use asynchronous flows for long-running operations:
public async authorize( authorization: AuthorizationRequest): Promise<AuthorizationResponse> { // Start async operation this.startAsyncOperation(authorization) // Return pending immediately return Authorizations.pending(authorization, { delayToCancel: 300000, tid: 'transaction-id', })}private async startAsyncOperation(auth: AuthorizationRequest) { // Process in background const result = await longRunningOperation() // Send result via callback this.callback(auth, Authorizations.approve(auth, result))}
The service integrates with VTEX’s test suite. Use the isTestSuite property to enable test-specific behavior:
node/connector.ts
export default class TestSuiteApprover extends PaymentProvider { public async authorize( authorization: AuthorizationRequest ): Promise<AuthorizationResponse> { if (this.isTestSuite) { // Test suite specific logic return executeAuthorization(authorization, response => this.callback(authorization, response) ) } // Production logic throw new Error('Not implemented') }}
The test suite validates that your connector implements the Payment Provider Protocol correctly. Passing the test suite is required before your connector can be used in production.