地址 https://developer.paypal.com/developer/applications/
1.点击进入 account,创建沙箱账号(选择最下面Create custom account 可以自定义邮箱,国家选择china)
2.创建app绑定沙箱邮箱,获取 clientID和secretID (沙箱的app name 和 正式名字最好设置不一样,设置一样有点奇怪的问题)
创建订单
开源地址 github.com/plutov/paypal
官方接口地址
func CreateOrderPayer(amount, orderID, user_idStr, queryPar string) (error, *paypal.Order) {
c, err := paypal.NewClient(viper.GetString("paypal.clientID"), viper.GetString("paypal.secretID"), GetPaypalUrl())
if err != nil {
return err, nil
}
_, err = c.GetAccessToken(context.TODO())
if err != nil {
return err, nil
}
purchaseUnits := make([]paypal.PurchaseUnitRequest, 1)
amount = "100"
purchaseUnits[0] = paypal.PurchaseUnitRequest{
Amount: &paypal.PurchaseUnitAmount{
Currency: "USD", //收款类型
Value: amount, //收款数量
},
InvoiceID: orderID,
ReferenceID: user_idStr,
Description: "优币充值",
}
payer := &paypal.CreateOrderPayer{
Name: &paypal.CreateOrderPayerName{
GivenName: user_idStr,
Surname: user_idStr,
},
}
appContext := &paypal.ApplicationContext{
ReturnURL: viper.GetString("paypal.ReturnURL") + queryPar, //回调链接
CancelURL: viper.GetString("paypal.CancelURL"), // 失败链接
}
order, err := c.CreateOrder(context.TODO(), paypal.OrderIntentCapture, purchaseUnits, payer, appContext)
if err != nil {
return err, nil
}
return nil, order
//(*order).Links[1].Href就是支付的链接
}
直接跳转到 (*order).Links[1].Href就是支付的链接,支付完成会自动跳转到 viper.GetString("paypal.ReturnURL") + queryPar
跳转回来是会带token字段,此时验签token
//回调(可以利用上面的回调链接实现) orderId 就是返回的token
func PaypalCallback(orderId string) error {
c, err := paypal.NewClient(viper.GetString("paypal.clientID"), viper.GetString("paypal.secretID"), GetPaypalUrl())
if err != nil {
return err
}
_, err = c.GetAccessToken(context.TODO())
if err != nil {
return err
}
//log.Info(accessToken.Token,orderId)
ctor := paypal.CaptureOrderRequest{}
order, err := c.CaptureOrder(context.TODO(), orderId, ctor)
if err != nil {
//log.Info(err,"打款失败")
return err
}
//查看回调完成后订单状态是否支付完成。
strByte, _ := json.Marshal(order)
glg.Info(string(strByte))
if (*order).Status != "COMPLETED" {
glg.Info(order.Status)
return errors.New("pay fail")
}
glg.Info("支付成功", order.Status, order.Address)
return nil
}
注意如果这里没有检测到,再根据webhook回调去监听,以防漏单
webhook回调的内容
{
"id":"WH-8CU97567X88541458-3NP925494U141233J",
"event_version":"1.0",
"create_time":"2021-08-23T11:36:06.833Z",
"resource_type":"capture",
"resource_version":"2.0",
"event_type":"PAYMENT.CAPTURE.COMPLETED",
"summary":"Payment completed for $ 6.0 USD",
"resource":{
"id":"0W1096515Y4268252",
"amount":{
"currency_code":"USD",
"value":"6.00"
},
"final_capture":true,
"seller_protection":{
"status":"ELIGIBLE",
"dispute_categories":[
"ITEM_NOT_RECEIVED",
"UNAUTHORIZED_TRANSACTION"
]
},
"invoice_id":"2021082319353654860",
"status":"PENDING",
"status_details":{
"reason":"PENDING_REVIEW"
},
"supplementary_data":{
"related_ids":{
"order_id":"1HN93431368009003"
}
},
"create_time":"2021-08-23T11:35:50Z",
"update_time":"2021-08-23T11:35:50Z",
"links":[
{
"href":"https:\/\/api.paypal.com\/v2\/payments\/captures\/0W1096515Y4268252",
"rel":"self",
"method":"GET"
},
{
"href":"https:\/\/api.paypal.com\/v2\/payments\/captures\/0W1096515Y4268252\/refund",
"rel":"refund",
"method":"POST"
},
{
"href":"https:\/\/api.paypal.com\/v2\/checkout\/orders\/1HN93431368009003",
"rel":"up",
"method":"GET"
}
]
},
"links":[
{
"href":"https:\/\/api.paypal.com\/v1\/notifications\/webhooks-events\/WH-8CU97567X88541458-3NP925494U141233J",
"rel":"self",
"method":"GET"
},
{
"href":"https:\/\/api.paypal.com\/v1\/notifications\/webhooks-events\/WH-8CU97567X88541458-3NP925494U141233J\/resend",
"rel":"resend",
"method":"POST"
}
]
}
“status”:“COMPLETED 或者 PENDING” 说明支付成功了
记录2022.1.21,目前跑了半年,没出现漏单情况
记录2022.4.1,目前跑了半年,没出现漏单情况
注意国内正式服是支付不了的
// 账号权限情况
https://www.paypal.com/restore/dashboard
// 原始开发文档
https://developer.paypal.com/api/orders/v2/#definition-order_application_context
// 沙箱登录
https://www.sandbox.paypal.com/
// 正式登录
https://www.paypal.com/mep/dashboard