Paypal 支付 REST 接口介绍
Paypal 支付提供了两种风格的 API 接口(如下图),一种是 NVP/SOAP 风格的经典接口,另一种是比较新的、 RESTful 风格的接口。NVP 风格目前已经被视为遗留接口,官方推荐使用 RESTful 接口访问。但目前网络上流传的资料还是以 NVP 居多,介绍 REST 接口的比较罕见。
本文是对目前使用 Paypal 支付接口的一个总结,也供有类似需求的朋友参考。
注册和访问
要使用 Paypal 接口,首先你应该有一个 Paypal 账户,并登录 开发者后台。需要说明的是:
- 如果你在大陆访问速度很慢,请考虑 Cross over the wall;
- 为了保证安全,Paypal 后台会话时间很短,如果你离开一会,再回去的话可能就会发现用户已经注销或者页面不正常了。这种情况下请重新点击右上角的 Login to dashboard再次登录。
接口文档
一般来说,我们需要了解的 Paypal 文档包括这几部分:
Docs Paypal 文档的总目录,包括多种接口和业务的访问链接; APIs 描述 API 接口的使用细节;
上述链接可以直接从 Dashboard 的顶部链接访问。
从 API 部分我们可以看到,Paypal 接口支持相当广泛的内容,我们这里只介绍 Payment(支付) API 相关部分。所有接口的访问方法都是类似的,一旦你掌握了其中之一,其他的完全可以举一反三。
API 文档中各个接口的具体使用方法值得仔细阅读。页面中间部分是接口参数和返回内容的说明,右边则列出了示例代码,如果你有 curl 工具并且已经得到访问接口的 Access Token(后面代码部分会说到如何获取 Access Token),你甚至可以把示例代码直接拷到终端窗口去测试。
Github 包含各种语言的 Paypal SDK 源码和下载资源。我们这里使用 C#,因此你可以在 Paypal .Net SDK 页面找到 SDK 的下载链接。如果你使用其他编程语言的话,可以从上述主页找到相应语言的访问地址。(Paypal 接口使用简单的 RESTful 风格,所以纯手工构造也不是特别麻烦。但为了简化工作和避免潜在的 bug,我还是推荐你在条件运行的情况下尽可能使用官方 SDK)。
创建 REST App
为了调用 REST 接口,首先我们需要创建一个 REST App。
回到 Dashboard 主页,在左边导航栏确保 My Apps & Credentials 是选中的。然后在右边内容向下查找 REST API Apps,点击其中的 Create App。
创建 App 要填写的内容很少。你要填写一个唯一的 App 名称(建议使用纯英文字母),并关联一个用户帐号(如果想精细化管理,可以去 Accounts 页面创建用户帐号) 。
当 REST App 创建完毕后,浏览器会跳转到其详情页面,其中有一些重要的内容需要关注。
-
首先看到右上角有 Sandbox/Live 的字样。当一个 App 创建后,默认是在沙箱模式(Sandbox)下,这时所有的支付请求并不会真正从你的信用卡上扣钱,而是从一个模拟的余额中扣减(你可以在账户信息页面看到这个余额)。当然这是为了方便你测试程序的。当测试正常以后,你可以切换到 Live 模式,这时候可就是真金白银的交易了,所以测试一定要仔细啊。
-
Sandbox account 就是你的支付用户,我们后面支付阶段会用到。
-
下面的配置信息包含 Client ID 和 Client Secret,其中 Secret 默认是隐藏的,点击才能查看。这两个值是非常重要的配置,调用接口的时候必须包含,所以请找个安全的地方记录下来,但千万不要放到公开的地方!特别是不要无意中把它们签入到源代码仓库。另外,Sandbox 和 Live 环境的 Cilent ID/Secret 是分开的,当你切换环境以后别忘了配置也要跟着修改。
接下来还有一个 WebHook 的配置,什么是 WebHook?就是当有特定的事件发生(比如用户付款完成)时,Paypal 会向你的网站发送一条 HTTP 请求,告诉你这个事件发生了。当然,为了使用 WebHook,你的网站必须有公共网络地址(最好是域名),部署在局域网是不行的。
对于 WebHook 还有一个很有意思的页面(如下图)。当你的网站部署好以后,你可以在这里要求 Paypal 模拟发送一条信息,以验证你的 WebHook 是不是正常工作了。当然,这里生成的信息是随机生成的(比如支付单号在你的系统里可能根本没有),所以你处理 Web Hook 的时候要做好异常处理,不要让网站因为随机的数据而跨掉。
Paypal 支付流程
好了,上述配置工具准备就绪,我们可以准备编写代码了。不过别忙,首先我们还是搞清楚 Paypal 的支付流程是什么样的:
- 当用户开始支付时,你需要向 Paypal 发送一个请求(Paypal Create),告诉 Paypal 支付要开始了。这个请求中比较重要的内容包括支付商品(要支付的目标)名称、支付金额、货币代码(USD/RMB)等。另外,还有两个地址要指定:return url(支付成功后跳转返回的地址)和 cancel url(用户取消支付的情况下返回的地址)。你也可以把两个地址设置为相同的,但是后续处理就要做好区分。
- Paypal 接受到你的请求后,如果请求数据没有问题,会返回给你一个支付地址的页面,你需要引导用户的浏览器转向这个页面;
- 支付页面如下图所示。用户要完成支付需要首先登录 Paypal。注意在沙箱环境下,只能用你在 REST App 中关联的用户来完成支付;在 Live 环境下所有 Paypal 用户都可以支付。
- 用户在这里可以选择 Continue(继续支付)或 Cancel(取消支付)。如果用户选择取消,则页面会跳转回你在上一步指定的 Cancel url;如果选 Continue,则返回 return url 页面。
- 如果页面来到你指定的 return url,说明用户已经同意支付了(但此时支付还没有真正发生)。这个页面会带有 paymentId 和 PayerID 两个参数(注意大小写!)你需要用这两个参数向 Paypal 发送一个 Execute 请求,如果请求成功,就代表支付动作完成了。另外,你配置的 WebHook 也会接受到一条事件(一般不是马上收到,而是要晚几秒钟)。
示例代码
明白了这个过程,我们接下来看实际的代码。为了方便阅读且避免泄漏业务内容,我删掉了一些错误处理和业务相关的代码,你在开发的时候当然应该仔细处理错误。
要调用 Paypal 接口首先要实现用户认证和授权。Paypal REST 接口使用 OAuth 协议,如果你使用 SDK 的话,这部分已经为你封装好了,你只需要传入 Client ID/Client Secret:
var clientId = "...";
var clientSecret = "...";
var credential = new OAuthTokenCredential(clientId, clientSecret);
var accessToken = credential.GetAccessToken();
apiContext = new APIContext(accessToken);
return apiContext;
接下来是调用 Paypal Create 的部分。这部分构造数据的结构很复杂,但实际上内容并不多,我就不详细写出了,你参考 API 文档的示例代码 即可。需要注意的是应答数据的 approval_url,你需要根据这个地址向浏览器返回一个跳转(302)。
然后是 Paypal Execute 部分,这一步很简单:
var payerId = Request.QueryString["PayerID"];
var paymentId = Request.QueryString["paymentId"];
var paymentExecution = new PaymentExecution()
{
payer_id = payerId
};
var paymentIn = Payment.Get(apiContext, paymentId);
var paymentOut = paymentIn.Execute(apiContext, paymentExecution);
最后,作为补充,我也列出 WebHook 的一般性处理代码:
Request.InputStream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(Request.InputStream, Encoding.UTF8))
{
string json = await reader.ReadToEndAsync();
dynamic jsonBody = JObject.Parse(json);
string webhookId = jsonBody.id;
var whe = WebhookEvent.Get(apiContext, webhookId);
switch (whe.event_type)
{
case "PAYMENT.CAPTURE.COMPLETED":
...
case "PAYMENT.CAPTURE.DENIED":
...
}
}
其中 WebHook 事件类型的分类及具体说明可以参考 API 文档。