PayPal Orders API使用SET_PROVIDED_ADDRESS时出现MISSING_SHIPPING_ADDRESS错误
问题概述
开发WordPress插件添加PayPal按钮时,点击按钮后弹窗尝试弹出但立即消失。通过浏览器Network面板查看接口返回,发现UNPROCESSABLE_ENTITY错误,具体提示为:
{"name":"UNPROCESSABLE_ENTITY","details":[{"field":"/purchase_units/@reference_id=='d9f80740-38f0-11e8-b467-0ed5f89f718b'/shipping/address","issue":"MISSING_SHIPPING_ADDRESS","description":"The shipping address is required when
shipping_preference=SET_PROVIDED_ADDRESS."}],"message":"The requested action could not be performed, semantically incorrect, or failed business validation.","debug_id":"c41ec50f69e7d"}
同时,PHP接口代码存在额外输出,导致前端JSON解析失败,这也是弹窗消失的直接诱因。
核心错误原因
- 收货地址缺失:当
experience_context里的shipping_preference设为SET_PROVIDED_ADDRESS时,PayPal API强制要求在purchase_units中提供完整的收货地址信息,当前请求未包含该字段,触发验证错误。 - 接口输出格式错误:PHP代码中
print_r( $access_token );会在返回的订单JSON前额外输出access_token字符串,导致响应内容不是有效的JSON格式,前端response.json()解析失败,中断PayPal按钮流程。
修复方案
方案1:修改shipping_preference(无需提供地址)
如果你的商品是虚拟物品(无需发货),可以将shipping_preference改为NO_SHIPPING,或者改为GET_FROM_FILE(使用买家PayPal账户中保存的地址):
NO_SHIPPING:完全跳过收货地址收集步骤GET_FROM_FILE:自动获取买家PayPal账户内的默认收货地址
修改PHP代码中experience_context部分:
"experience_context": { "payment_method_preference": "IMMEDIATE_PAYMENT_REQUIRED", "payment_method_selected": "PAYPAL", "brand_name": "EXAMPLE INC", "locale": "en-US", "landing_page": "LOGIN", "shipping_preference": "NO_SHIPPING", // 或改为GET_FROM_FILE "user_action": "PAY_NOW", "return_url": "https://example.com/returnUrl", "cancel_url": "https://example.com/cancelUrl" }
方案2:添加收货地址信息
如果需要指定收货地址,在purchase_units数组的对应对象中添加shipping字段,包含完整的地址信息:
"purchase_units": [{ "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b", "amount": { "currency_code": "USD", "value": "10.00" }, "shipping": { "name": { "full_name": "John Doe" }, "address": { "address_line_1": "123 Main St", "address_line_2": "Apt 4B", "admin_area_2": "San Jose", "admin_area_1": "CA", "postal_code": "95131", "country_code": "US" } } }]
必须修正的输出错误
删除PHP代码中的print_r( $access_token );语句,确保接口仅返回订单的JSON数据,避免破坏响应格式:
// 移除这行代码 // print_r( $access_token );
完整修改后的PHP示例片段
// ...获取access_token的代码部分(已移除print_r) $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, 'https://api-m.sandbox.paypal.com/v2/checkout/orders'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, '{ "intent": "CAPTURE", "purchase_units": [{ "reference_id": "d9f80740-38f0-11e8-b467-0ed5f89f718b", "amount": { "currency_code": "USD", "value": "10.00" }, "shipping": { "name": { "full_name": "John Doe" }, "address": { "address_line_1": "123 Main St", "admin_area_2": "San Jose", "admin_area_1": "CA", "postal_code": "95131", "country_code": "US" } } }], "payment_source": { "paypal": { "experience_context": { "payment_method_preference": "IMMEDIATE_PAYMENT_REQUIRED", "payment_method_selected": "PAYPAL", "brand_name": "EXAMPLE INC", "locale": "en-US", "landing_page": "LOGIN", "shipping_preference": "SET_PROVIDED_ADDRESS", "user_action": "PAY_NOW", "return_url": "https://example.com/returnUrl", "cancel_url": "https://example.com/cancelUrl" } } } }'); // ...后续curl请求代码
内容的提问来源于stack exchange,提问作者dig

