Node.js+paypal ServersSDK OrderV2
文档:https://developer.paypal.com/docs/api/orders/sdk/v2/
引入依赖
npm i @paypal/paypal-server-sdk创建客户端
client = new Client({
clientCredentialsAuthCredentials: {
oAuthClientId: '<填写自己的clientId>',
oAuthClientSecret: '<填写自己的Secret>'
},
timeout: 0,
environment: Environment.Sandbox, //Sandbox沙盒,调试用;Production,生产环境,上线时设置
logging: {
logLevel: LogLevel.Warn,
logRequest: {
logBody: false
},
logResponse: {
logHeaders: false
}
},
});
ordersController = new OrdersController(client);收款流程
后端创建订单->用户跳转到payer-action->用户在页面完成授权->webhook中收到APPROVED事件,后端SDK执行capture冻结资金->完成后WEBHOOK收到COMPLETED事件后更新数据库并完成发货
(注意需要到创建的应用中添加webhook为自己的域名和路由)
创建订单
const collect = {
body: {
intent: CheckoutPaymentIntent.Capture,
purchaseUnits: [
{
amount: {
currencyCode: 'TWD', //新台币,可以在文档中找到其它货币代码
value: '108.00', //金额
},
customId: '自定义字段,在后续capture和completed时会回传',
referenceId: customField,
}
],
paymentSource: {
paypal: {
experienceContext: {
shippingPreference: ShippingPreference.GetFromFile,
returnUrl: 'https://example.com/returnUrl', //可自定义,用户完成授权后会跳转到这里
cancelUrl: 'https://example.com/cancelUrl',
landingPage: PaypalExperienceLandingPage.Login,
userAction: PaypalExperienceUserAction.PayNow,
paymentMethodPreference: PayeePaymentMethodPreference.ImmediatePaymentRequired,
},
},
},
}
}
try {
const { result, ...httpResponse } = await ordersController.createOrder(collect);
// Get more response info...
// const { statusCode, headers } = httpResponse;
return result
} catch (error) {
console.log(error);
return false
if (error instanceof ApiError) {
const errors = error.result;
// const { statusCode, headers } = error;
}
}{
"id": "5O190127TN364715T",
"status": "PAYER_ACTION_REQUIRED",
"payment_source": {
"paypal": { }
},
"links": [
{
"href": "https://api-m.paypal.com/v2/checkout/orders/5O190127TN364715T",
"rel": "self",
"method": "GET"
},
{
"href": "https://www.paypal.com/checkoutnow?token=5O190127TN364715T",
"rel": "payer-action",
"method": "GET"
}
]
}如果成功,result中是这样的JSON,将payer-action对应的HREF在前端重定向让用户授权
webhook处理路由
app.post('/paypal-event', async function(req, res, next){
if(req.body.event_type == 'CHECKOUT.ORDER.APPROVED') {
await paypal.capture(req.body.resource.id)
console.log('paypal-event CHECKOUT.ORDER.APPROVED', req.body.resource.id);
}else if(req.body.event_type == 'PAYMENT.CAPTURE.COMPLETED') { //付款完成
console.log('paypal-event PAYMENT.CAPTURE.COMPLETED', req.body.resource.supplementary_data.related_ids.order_id);
let ret = await SQL.paypalCallback(req.body); //自行实现更新数据库的逻辑
if(ret == false) {
res.sendStatus(500)
}
}else { //未处理的类型
console.log('paypal-event no handler',req.body.event_type, JSON.stringify(req.body));
}
res.send('ok')
})//paypal.captrue实现
async function capture (id){
if(ordersController == null) {
return false
}
const collect = {
id
}
try {
const { result, ...httpResponse } = await ordersController.captureOrder(collect);
// Get more response info...
// const { statusCode, headers } = httpResponse;
return result
} catch (error) {
return false
if (error instanceof ApiError) {
const errors = error.result;
// const { statusCode, headers } = error;
}
}
}Sandbox调试环境
后端中创建paypal客户端时将environment设为Sandbox,创建的订单的二级域名则是sandbox,打开创建的订单需要登录,用沙盒的用户端账号,步骤:登录商家端控制台https://developer.paypal.com/dashboard/,点sandbox accounts,用Person类型的账号登录,控制台中可以设置余额。
注意控制台右上角有开关,沙盒和商家身份创建的应用不一样,设环境为沙盒后,要用沙盒身份创建的应用的clientId和secret