payment-provider-protocol
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePPP Endpoint Implementation
PPP端点实现
When this skill applies
适用场景
Use this skill when:
- Building a new payment connector middleware that integrates a PSP with the VTEX Payment Gateway
- Implementing, debugging, or extending any of the 9 PPP endpoints
- Preparing a connector for VTEX Payment Provider Test Suite homologation
Do not use this skill for:
- Idempotency and duplicate prevention logic — use
payment-idempotency - Async payment flows and callback URLs — use
payment-async-flow - PCI compliance and Secure Proxy card handling — use
payment-pci-security
本内容适用于以下场景:
- 构建将支付服务提供商(PSP)与VTEX支付网关集成的全新支付连接器中间件
- 实现、调试或扩展9个PPP端点中的任意一个
- 为VTEX支付提供商测试套件认证准备连接器
以下场景请勿使用本内容:
- 幂等性与重复请求预防逻辑 — 请使用
payment-idempotency - 异步支付流程与回调URL — 请使用
payment-async-flow - PCI合规与安全代理卡片处理 — 请使用
payment-pci-security
Decision rules
决策规则
- The connector MUST implement all 6 payment-flow endpoints: Manifest, Create Payment, Cancel, Capture/Settle, Refund, Inbound Request.
- The configuration flow (3 endpoints: Create Auth Token, Provider Auth Redirect, Get Credentials) is optional but recommended for merchant onboarding.
- All endpoints must be served over HTTPS on port 443 with TLS 1.2.
- The connector must respond in under 5 seconds during homologation tests and under 20 seconds in production.
- The provider must be PCI-DSS certified or use Secure Proxy for card payments.
- The Gateway initiates all calls. The middleware never calls the Gateway except via (async notifications) and Secure Proxy (card data forwarding).
callbackUrl
- 连接器必须实现全部6个支付流程端点:Manifest、创建支付、取消支付、捕获/结算、退款、入站请求。
- 配置流程的3个端点(创建授权令牌、提供商授权重定向、获取凭证)为可选,但建议用于商家入驻流程。
- 所有端点必须通过HTTPS在443端口提供服务,且使用TLS 1.2协议。
- 在认证测试期间,连接器的响应时间必须在5秒以内;生产环境下响应时间需在20秒以内。
- 支付提供商必须获得PCI-DSS认证,或使用安全代理处理卡片支付。
- 所有调用均由网关发起。中间件仅可通过(异步通知)和安全代理(卡片数据转发)调用网关。
callbackUrl
Hard constraints
硬性约束
Constraint: Implement all required payment flow endpoints
约束:实现所有必填支付流程端点
The connector MUST implement all six payment-flow endpoints: GET , POST , POST , POST , POST , and POST .
/manifest/payments/payments/{paymentId}/cancellations/payments/{paymentId}/settlements/payments/{paymentId}/refunds/payments/{paymentId}/inbound-request/{action}Why this matters
The VTEX Payment Provider Test Suite validates every endpoint during homologation. Missing endpoints cause test failures and the connector will not be approved. At runtime, the Gateway expects all endpoints — a missing cancel endpoint means payments cannot be voided.
Detection
If the connector router/handler file does not define handlers for all 6 payment-flow paths, STOP and add the missing endpoints before proceeding.
Correct
typescript
import { Router } from "express";
const router = Router();
// All 6 payment-flow endpoints implemented
router.get("/manifest", manifestHandler);
router.post("/payments", createPaymentHandler);
router.post("/payments/:paymentId/cancellations", cancelPaymentHandler);
router.post("/payments/:paymentId/settlements", capturePaymentHandler);
router.post("/payments/:paymentId/refunds", refundPaymentHandler);
router.post("/payments/:paymentId/inbound-request/:action", inboundRequestHandler);
export default router;Wrong
typescript
import { Router } from "express";
const router = Router();
// Missing manifest, inbound-request, and refund endpoints
// This will fail homologation and break runtime operations
router.post("/payments", createPaymentHandler);
router.post("/payments/:paymentId/cancellations", cancelPaymentHandler);
router.post("/payments/:paymentId/settlements", capturePaymentHandler);
export default router;连接器必须实现全部6个支付流程端点:GET 、POST 、POST 、POST 、POST 以及 POST 。
/manifest/payments/payments/{paymentId}/cancellations/payments/{paymentId}/settlements/payments/{paymentId}/refunds/payments/{paymentId}/inbound-request/{action}重要性
VTEX支付提供商测试套件在认证过程中会验证每个端点。缺失端点会导致测试失败,连接器将无法通过审批。在运行时,网关会期望所有端点可用——若缺失取消端点,将无法作废支付订单。
检测方式
如果连接器的路由/处理文件未为所有6个支付流程路径定义处理函数,请立即停止并添加缺失的端点后再继续。
正确示例
typescript
import { Router } from "express";
const router = Router();
// 实现了全部6个支付流程端点
router.get("/manifest", manifestHandler);
router.post("/payments", createPaymentHandler);
router.post("/payments/:paymentId/cancellations", cancelPaymentHandler);
router.post("/payments/:paymentId/settlements", capturePaymentHandler);
router.post("/payments/:paymentId/refunds", refundPaymentHandler);
router.post("/payments/:paymentId/inbound-request/:action", inboundRequestHandler);
export default router;错误示例
typescript
import { Router } from "express";
const router = Router();
// 缺失Manifest、入站请求和退款端点
// 这将导致认证失败并破坏运行时操作
router.post("/payments", createPaymentHandler);
router.post("/payments/:paymentId/cancellations", cancelPaymentHandler);
router.post("/payments/:paymentId/settlements", capturePaymentHandler);
export default router;Constraint: Return correct HTTP status codes and response shapes
约束:返回正确的HTTP状态码和响应格式
Each endpoint MUST return the exact response shape documented in the PPP API. Create Payment MUST return , , , , , , , , , , and . Cancel MUST return , , , , . Capture MUST return , , , , , . Refund MUST return , , , , , .
paymentIdstatusauthorizationIdtidnsuacquirercodemessagedelayToAutoSettledelayToAutoSettleAfterAntifrauddelayToCancelpaymentIdcancellationIdcodemessagerequestIdpaymentIdsettleIdvaluecodemessagerequestIdpaymentIdrefundIdvaluecodemessagerequestIdWhy this matters
The Gateway parses these fields programmatically. Missing fields cause deserialization errors and the Gateway treats the payment as failed. Incorrect values cause payments to auto-cancel or auto-capture at wrong times.
delayToAutoSettleDetection
If a response object is missing any of the required fields for its endpoint, STOP and add the missing fields.
Correct
typescript
interface CreatePaymentResponse {
paymentId: string;
status: "approved" | "denied" | "undefined";
authorizationId: string | null;
nsu: string | null;
tid: string | null;
acquirer: string | null;
code: string | null;
message: string | null;
delayToAutoSettle: number;
delayToAutoSettleAfterAntifraud: number;
delayToCancel: number;
paymentUrl?: string;
}
async function createPaymentHandler(req: Request, res: Response): Promise<void> {
const { paymentId, value, currency, paymentMethod, card, callbackUrl } = req.body;
const result = await processPaymentWithAcquirer(req.body);
const response: CreatePaymentResponse = {
paymentId,
status: result.status,
authorizationId: result.authorizationId ?? null,
nsu: result.nsu ?? null,
tid: result.tid ?? null,
acquirer: "MyAcquirer",
code: result.code ?? null,
message: result.message ?? null,
delayToAutoSettle: 21600, // 6 hours in seconds
delayToAutoSettleAfterAntifraud: 1800, // 30 minutes in seconds
delayToCancel: 21600, // 6 hours in seconds
};
res.status(200).json(response);
}Wrong
typescript
// Missing required fields — Gateway will reject this response
async function createPaymentHandler(req: Request, res: Response): Promise<void> {
const result = await processPaymentWithAcquirer(req.body);
// Missing: authorizationId, nsu, tid, acquirer, code, message,
// delayToAutoSettle, delayToAutoSettleAfterAntifraud, delayToCancel
res.status(200).json({
paymentId: req.body.paymentId,
status: result.status,
});
}每个端点必须返回PPP API文档中规定的精确响应格式。创建支付端点必须返回、、、、、、、、、和。取消支付端点必须返回、、、、。捕获支付端点必须返回、、、、、。退款支付端点必须返回、、、、、。
paymentIdstatusauthorizationIdtidnsuacquirercodemessagedelayToAutoSettledelayToAutoSettleAfterAntifrauddelayToCancelpaymentIdcancellationIdcodemessagerequestIdpaymentIdsettleIdvaluecodemessagerequestIdpaymentIdrefundIdvaluecodemessagerequestId重要性
网关会以编程方式解析这些字段。缺失字段会导致反序列化错误,网关会将该支付标记为失败。值不正确会导致支付订单在错误的时间自动取消或自动捕获。
delayToAutoSettle检测方式
如果响应对象缺失对应端点的任何必填字段,请立即停止并添加缺失的字段。
正确示例
typescript
interface CreatePaymentResponse {
paymentId: string;
status: "approved" | "denied" | "undefined";
authorizationId: string | null;
nsu: string | null;
tid: string | null;
acquirer: string | null;
code: string | null;
message: string | null;
delayToAutoSettle: number;
delayToAutoSettleAfterAntifraud: number;
delayToCancel: number;
paymentUrl?: string;
}
async function createPaymentHandler(req: Request, res: Response): Promise<void> {
const { paymentId, value, currency, paymentMethod, card, callbackUrl } = req.body;
const result = await processPaymentWithAcquirer(req.body);
const response: CreatePaymentResponse = {
paymentId,
status: result.status,
authorizationId: result.authorizationId ?? null,
nsu: result.nsu ?? null,
tid: result.tid ?? null,
acquirer: "MyAcquirer",
code: result.code ?? null,
message: result.message ?? null,
delayToAutoSettle: 21600, // 6小时(秒)
delayToAutoSettleAfterAntifraud: 1800, // 30分钟(秒)
delayToCancel: 21600, // 6小时(秒)
};
res.status(200).json(response);
}错误示例
typescript
// 缺失必填字段 — 网关会拒绝该响应
async function createPaymentHandler(req: Request, res: Response): Promise<void> {
const result = await processPaymentWithAcquirer(req.body);
// 缺失:authorizationId、nsu、tid、acquirer、code、message、
// delayToAutoSettle、delayToAutoSettleAfterAntifraud、delayToCancel
res.status(200).json({
paymentId: req.body.paymentId,
status: result.status,
});
}Constraint: Manifest must declare all supported payment methods
约束:Manifest必须声明所有支持的支付方式
The GET endpoint MUST return a array listing every payment method the connector supports, with the correct and configuration for each.
/manifestpaymentMethodsnameallowsSplitWhy this matters
The Gateway reads the manifest to determine which payment methods are available. If a method is missing, merchants cannot configure it in the VTEX Admin. An incorrect value causes split payment failures.
allowsSplitDetection
If the manifest handler returns an empty array or hardcodes methods the provider does not actually support, STOP and fix the manifest.
paymentMethodsCorrect
typescript
async function manifestHandler(_req: Request, res: Response): Promise<void> {
const manifest = {
paymentMethods: [
{ name: "Visa", allowsSplit: "onCapture" },
{ name: "Mastercard", allowsSplit: "onCapture" },
{ name: "American Express", allowsSplit: "onCapture" },
{ name: "BankInvoice", allowsSplit: "onAuthorize" },
{ name: "Pix", allowsSplit: "disabled" },
],
};
res.status(200).json(manifest);
}Wrong
typescript
// Empty manifest — no payment methods will appear in the Admin
async function manifestHandler(_req: Request, res: Response): Promise<void> {
res.status(200).json({ paymentMethods: [] });
}GET 端点必须返回数组,列出连接器支持的所有支付方式,且每个支付方式需包含正确的和配置。
/manifestpaymentMethodsnameallowsSplit重要性
网关会读取Manifest来确定可用的支付方式。若缺失某一支付方式,商家将无法在VTEX管理后台配置该方式。值不正确会导致分账支付失败。
allowsSplit检测方式
如果Manifest处理函数返回空的数组,或硬编码了提供商实际不支持的支付方式,请立即停止并修复Manifest。
paymentMethods正确示例
typescript
async function manifestHandler(_req: Request, res: Response): Promise<void> {
const manifest = {
paymentMethods: [
{ name: "Visa", allowsSplit: "onCapture" },
{ name: "Mastercard", allowsSplit: "onCapture" },
{ name: "American Express", allowsSplit: "onCapture" },
{ name: "BankInvoice", allowsSplit: "onAuthorize" },
{ name: "Pix", allowsSplit: "disabled" },
],
};
res.status(200).json(manifest);
}错误示例
typescript
// 空Manifest — 管理后台不会显示任何支付方式
async function manifestHandler(_req: Request, res: Response): Promise<void> {
res.status(200).json({ paymentMethods: [] });
}Preferred pattern
推荐模式
Architecture overview:
text
Shopper → VTEX Checkout → VTEX Payment Gateway → [Your Connector Middleware] → Acquirer/PSP
↕
Configuration Flow (Admin)Recommended TypeScript interfaces for all endpoint contracts:
typescript
// --- Manifest ---
interface ManifestResponse {
paymentMethods: Array<{
name: string;
allowsSplit: "onCapture" | "onAuthorize" | "disabled";
}>;
}
// --- Create Payment ---
interface CreatePaymentRequest {
reference: string;
orderId: string;
transactionId: string;
paymentId: string;
paymentMethod: string;
value: number;
currency: string;
installments: number;
card?: {
holder: string;
number: string;
csc: string;
expiration: { month: string; year: string };
};
miniCart: Record<string, unknown>;
callbackUrl: string;
returnUrl?: string;
}
interface CreatePaymentResponse {
paymentId: string;
status: "approved" | "denied" | "undefined";
authorizationId: string | null;
nsu: string | null;
tid: string | null;
acquirer: string | null;
code: string | null;
message: string | null;
delayToAutoSettle: number;
delayToAutoSettleAfterAntifraud: number;
delayToCancel: number;
paymentUrl?: string;
}
// --- Cancel Payment ---
interface CancelPaymentResponse {
paymentId: string;
cancellationId: string | null;
code: string | null;
message: string | null;
requestId: string;
}
// --- Capture/Settle Payment ---
interface CapturePaymentResponse {
paymentId: string;
settleId: string | null;
value: number;
code: string | null;
message: string | null;
requestId: string;
}
// --- Refund Payment ---
interface RefundPaymentResponse {
paymentId: string;
refundId: string | null;
value: number;
code: string | null;
message: string | null;
requestId: string;
}
// --- Inbound Request ---
interface InboundResponse {
requestId: string;
paymentId: string;
responseData: {
statusCode: number;
contentType: string;
content: string;
};
}Complete payment flow router with all 6 endpoints:
typescript
import { Router, Request, Response } from "express";
const router = Router();
router.get("/manifest", async (_req: Request, res: Response) => {
res.status(200).json({
paymentMethods: [
{ name: "Visa", allowsSplit: "onCapture" },
{ name: "Mastercard", allowsSplit: "onCapture" },
{ name: "Pix", allowsSplit: "disabled" },
],
});
});
router.post("/payments", async (req: Request, res: Response) => {
const body: CreatePaymentRequest = req.body;
const result = await processWithAcquirer(body);
const response: CreatePaymentResponse = {
paymentId: body.paymentId,
status: result.status,
authorizationId: result.authorizationId ?? null,
nsu: result.nsu ?? null,
tid: result.tid ?? null,
acquirer: "MyProvider",
code: result.code ?? null,
message: result.message ?? null,
delayToAutoSettle: 21600,
delayToAutoSettleAfterAntifraud: 1800,
delayToCancel: 21600,
};
res.status(200).json(response);
});
router.post("/payments/:paymentId/cancellations", async (req: Request, res: Response) => {
const { paymentId } = req.params;
const { requestId } = req.body;
const result = await cancelWithAcquirer(paymentId);
res.status(200).json({
paymentId,
cancellationId: result.cancellationId ?? null,
code: result.code ?? null,
message: result.message ?? "Successfully cancelled",
requestId,
});
});
router.post("/payments/:paymentId/settlements", async (req: Request, res: Response) => {
const body = req.body;
const result = await captureWithAcquirer(body.paymentId, body.value);
res.status(200).json({
paymentId: body.paymentId,
settleId: result.settleId ?? null,
value: result.capturedValue ?? body.value,
code: result.code ?? null,
message: result.message ?? null,
requestId: body.requestId,
});
});
router.post("/payments/:paymentId/refunds", async (req: Request, res: Response) => {
const body = req.body;
const result = await refundWithAcquirer(body.paymentId, body.value);
res.status(200).json({
paymentId: body.paymentId,
refundId: result.refundId ?? null,
value: result.refundedValue ?? body.value,
code: result.code ?? null,
message: result.message ?? null,
requestId: body.requestId,
});
});
router.post("/payments/:paymentId/inbound-request/:action", async (req: Request, res: Response) => {
const body = req.body;
const result = await handleInbound(body);
res.status(200).json({
requestId: body.requestId,
paymentId: body.paymentId,
responseData: {
statusCode: 200,
contentType: "application/json",
content: JSON.stringify(result),
},
});
});
export default router;Configuration flow endpoints (optional, for merchant onboarding):
typescript
import { Router, Request, Response } from "express";
const configRouter = Router();
// 1. POST /authorization/token
configRouter.post("/authorization/token", async (req: Request, res: Response) => {
const { applicationId, returnUrl } = req.body;
const token = await generateAuthorizationToken(applicationId, returnUrl);
res.status(200).json({ applicationId, token });
});
// 2. GET /authorization/redirect
configRouter.get("/authorization/redirect", async (req: Request, res: Response) => {
const { token } = req.query;
const providerLoginUrl = buildProviderLoginUrl(token as string);
res.redirect(302, providerLoginUrl);
});
// 3. GET /authorization/credentials
configRouter.get("/authorization/credentials", async (req: Request, res: Response) => {
const { authorizationCode } = req.query;
const credentials = await exchangeCodeForCredentials(authorizationCode as string);
res.status(200).json({
applicationId: "vtex",
appKey: credentials.appKey,
appToken: credentials.appToken,
});
});
export default configRouter;架构概述:
text
购物者 → VTEX结账系统 → VTEX支付网关 → [你的连接器中间件] → 收单机构/支付服务提供商(PSP)
↕
配置流程(管理后台)所有端点契约推荐使用TypeScript接口:
typescript
// --- Manifest ---
interface ManifestResponse {
paymentMethods: Array<{
name: string;
allowsSplit: "onCapture" | "onAuthorize" | "disabled";
}>;
}
// --- 创建支付 ---
interface CreatePaymentRequest {
reference: string;
orderId: string;
transactionId: string;
paymentId: string;
paymentMethod: string;
value: number;
currency: string;
installments: number;
card?: {
holder: string;
number: string;
csc: string;
expiration: { month: string; year: string };
};
miniCart: Record<string, unknown>;
callbackUrl: string;
returnUrl?: string;
}
interface CreatePaymentResponse {
paymentId: string;
status: "approved" | "denied" | "undefined";
authorizationId: string | null;
nsu: string | null;
tid: string | null;
acquirer: string | null;
code: string | null;
message: string | null;
delayToAutoSettle: number;
delayToAutoSettleAfterAntifraud: number;
delayToCancel: number;
paymentUrl?: string;
}
// --- 取消支付 ---
interface CancelPaymentResponse {
paymentId: string;
cancellationId: string | null;
code: string | null;
message: string | null;
requestId: string;
}
// --- 捕获/结算支付 ---
interface CapturePaymentResponse {
paymentId: string;
settleId: string | null;
value: number;
code: string | null;
message: string | null;
requestId: string;
}
// --- 退款支付 ---
interface RefundPaymentResponse {
paymentId: string;
refundId: string | null;
value: number;
code: string | null;
message: string | null;
requestId: string;
}
// --- 入站请求 ---
interface InboundResponse {
requestId: string;
paymentId: string;
responseData: {
statusCode: number;
contentType: string;
content: string;
};
}包含全部6个端点的完整支付流程路由:
typescript
import { Router, Request, Response } from "express";
const router = Router();
router.get("/manifest", async (_req: Request, res: Response) => {
res.status(200).json({
paymentMethods: [
{ name: "Visa", allowsSplit: "onCapture" },
{ name: "Mastercard", allowsSplit: "onCapture" },
{ name: "Pix", allowsSplit: "disabled" },
],
});
});
router.post("/payments", async (req: Request, res: Response) => {
const body: CreatePaymentRequest = req.body;
const result = await processWithAcquirer(body);
const response: CreatePaymentResponse = {
paymentId: body.paymentId,
status: result.status,
authorizationId: result.authorizationId ?? null,
nsu: result.nsu ?? null,
tid: result.tid ?? null,
acquirer: "MyProvider",
code: result.code ?? null,
message: result.message ?? null,
delayToAutoSettle: 21600,
delayToAutoSettleAfterAntifraud: 1800,
delayToCancel: 21600,
};
res.status(200).json(response);
});
router.post("/payments/:paymentId/cancellations", async (req: Request, res: Response) => {
const { paymentId } = req.params;
const { requestId } = req.body;
const result = await cancelWithAcquirer(paymentId);
res.status(200).json({
paymentId,
cancellationId: result.cancellationId ?? null,
code: result.code ?? null,
message: result.message ?? "取消成功",
requestId,
});
});
router.post("/payments/:paymentId/settlements", async (req: Request, res: Response) => {
const body = req.body;
const result = await captureWithAcquirer(body.paymentId, body.value);
res.status(200).json({
paymentId: body.paymentId,
settleId: result.settleId ?? null,
value: result.capturedValue ?? body.value,
code: result.code ?? null,
message: result.message ?? null,
requestId: body.requestId,
});
});
router.post("/payments/:paymentId/refunds", async (req: Request, res: Response) => {
const body = req.body;
const result = await refundWithAcquirer(body.paymentId, body.value);
res.status(200).json({
paymentId: body.paymentId,
refundId: result.refundId ?? null,
value: result.refundedValue ?? body.value,
code: result.code ?? null,
message: result.message ?? null,
requestId: body.requestId,
});
});
router.post("/payments/:paymentId/inbound-request/:action", async (req: Request, res: Response) => {
const body = req.body;
const result = await handleInbound(body);
res.status(200).json({
requestId: body.requestId,
paymentId: body.paymentId,
responseData: {
statusCode: 200,
contentType: "application/json",
content: JSON.stringify(result),
},
});
});
export default router;配置流程端点(可选,用于商家入驻):
typescript
import { Router, Request, Response } from "express";
const configRouter = Router();
// 1. POST /authorization/token
configRouter.post("/authorization/token", async (req: Request, res: Response) => {
const { applicationId, returnUrl } = req.body;
const token = await generateAuthorizationToken(applicationId, returnUrl);
res.status(200).json({ applicationId, token });
});
// 2. GET /authorization/redirect
configRouter.get("/authorization/redirect", async (req: Request, res: Response) => {
const { token } = req.query;
const providerLoginUrl = buildProviderLoginUrl(token as string);
res.redirect(302, providerLoginUrl);
});
// 3. GET /authorization/credentials
configRouter.get("/authorization/credentials", async (req: Request, res: Response) => {
const { authorizationCode } = req.query;
const credentials = await exchangeCodeForCredentials(authorizationCode as string);
res.status(200).json({
applicationId: "vtex",
appKey: credentials.appKey,
appToken: credentials.appToken,
});
});
export default configRouter;Common failure modes
常见失败模式
- Partial endpoint implementation — Implementing only Create Payment and Capture while skipping Manifest, Cancel, Refund, and Inbound Request. The Test Suite tests all endpoints and will fail homologation. At runtime, the Gateway cannot cancel or refund payments.
- Incorrect HTTP methods — Using POST for the Manifest endpoint or GET for Create Payment. The Gateway sends specific HTTP methods; mismatched handlers return 404 or 405.
- Missing or zero delay values — Omitting ,
delayToAutoSettle, ordelayToAutoSettleAfterAntifraudfrom the Create Payment response, or setting them to zero. This causes immediate auto-capture or auto-cancel, leading to premature settlement or lost payments.delayToCancel - Incomplete response shapes — Returning only and
paymentIdwithoutstatus,authorizationId,tid,nsu, etc. The Gateway deserializes all fields and treats missing ones as failures.acquirer
- 端点部分实现 — 仅实现创建支付和捕获端点,跳过Manifest、取消、退款和入站请求端点。测试套件会测试所有端点,这种情况会导致认证失败。在运行时,网关无法取消或退款支付订单。
- HTTP方法错误 — 对Manifest端点使用POST方法,或对创建支付端点使用GET方法。网关会发送特定的HTTP方法;方法不匹配会返回404或405错误。
- 延迟值缺失或为零 — 在创建支付响应中省略、
delayToAutoSettle或delayToAutoSettleAfterAntifraud,或将其设置为零。这会导致支付订单立即自动捕获或自动取消,从而导致提前结算或订单丢失。delayToCancel - 响应格式不完整 — 仅返回和
paymentId,缺失status、authorizationId、tid、nsu等字段。网关会反序列化所有字段,缺失字段会被视为失败。acquirer
Review checklist
审核清单
- Are all 6 payment-flow endpoints implemented (Manifest, Create Payment, Cancel, Capture, Refund, Inbound Request)?
- Does each endpoint return the complete response shape with all required fields?
- Does the Manifest declare all payment methods the provider actually supports?
- Are the correct HTTP methods used (GET for Manifest, POST for everything else)?
- Are ,
delayToAutoSettle, anddelayToAutoSettleAfterAntifraudset to sensible non-zero values?delayToCancel - Is the connector served over HTTPS on port 443 with TLS 1.2?
- Does the connector respond within 5 seconds for test suite and 20 seconds in production?
- Are configuration flow endpoints implemented if merchant self-onboarding is needed?
- 是否实现了全部6个支付流程端点(Manifest、创建支付、取消支付、捕获、退款、入站请求)?
- 每个端点是否返回包含所有必填字段的完整响应格式?
- Manifest是否声明了提供商实际支持的所有支付方式?
- 是否使用了正确的HTTP方法(Manifest用GET,其他用POST)?
- 、
delayToAutoSettle和delayToAutoSettleAfterAntifraud是否设置了合理的非零值?delayToCancel - 连接器是否通过HTTPS在443端口提供服务,且使用TLS 1.2协议?
- 连接器在测试套件中的响应时间是否在5秒以内,生产环境是否在20秒以内?
- 若需要商家自助入驻,是否实现了配置流程端点?
Related skills
相关技能
- — Idempotency keys (
payment-idempotency,paymentId) and state machine for duplicate preventionrequestId - — Async payment methods,
payment-async-flow, and the 7-day retry windowcallbackUrl - — PCI compliance, Secure Proxy, and card data handling
payment-pci-security
- — 幂等性密钥(
payment-idempotency、paymentId)和重复请求预防状态机requestId - — 异步支付方式、
payment-async-flow和7天重试窗口callbackUrl - — PCI合规、安全代理和卡片数据处理
payment-pci-security
Reference
参考资料
- Payment Provider Protocol Overview — API overview with endpoint requirements, common parameters, and test suite info
- Implementing a Payment Provider — Step-by-step guide covering all 9 endpoints with request/response examples
- Payment Provider Protocol (Help Center) — High-level protocol explanation including payment flow diagrams and callback URL usage
- Purchase Flows — Authorization, capture, and cancellation flow details
- Payment Provider Protocol API Reference — Full OpenAPI specification for all PPP endpoints
- Integrating a New Payment Provider on VTEX — End-to-end integration guide from development to homologation
- Payment Provider Protocol概述 — API概述,包含端点要求、通用参数和测试套件信息
- 实现支付提供商 — 分步指南,涵盖所有9个端点及请求/响应示例
- Payment Provider Protocol(帮助中心) — 协议高层说明,包含支付流程图和回调URL用法
- 购买流程 — 授权、捕获和取消流程详情
- Payment Provider Protocol API参考 — 所有PPP端点的完整OpenAPI规范
- 在VTEX上集成新的支付提供商 — 从开发到认证的端到端集成指南