DoneSpeak

初步认识 Stripe 支付

字数: 5.1k时长: 19 min
2019/04/07 Share

前言

这段时间在做支付相关的工作,由于业务主要是面向国外的用户,因而就接触了部分国外的支付支付相关的平台。接下来的内容主要是初步看了 Stripe 平台的文档所了解到的基本内容,后面会在使用的过程中不断地进行完善。

基本介绍和与其他支付平台的对比

什么是Stripe

Stripe - 基于API的便捷支付渠道 中对Stripe所提供的功能/产品给了较为不错的参考。

使用范围

在我写这篇博客之时(2019-04-07),stripe已经支持32个国家的使用,而我在查找资料的时候,看到的基本都是说25个国家。支持的国家(https://stripe.com/global)

201904100303-stripe-business-contries.png

从列表中我们可以看到,其实中国大陆是还没有被支持的。为了能够进行收钱,我们需要一个在Stripe支持国家列表中的国家的银行账号。如果中国的企业单位希望使用的话,可以通过 StripeAtlas 创建一个美国的银行账号。更多关于 Atlas 可以看下 Atlas 的主页介绍,或者看下36氪的《为什么说想把业务做到海外去的公司,都需要关注 Stripe Atlas ?》。这里就不做展开介绍了。

和其他平台的简单对比

有朋友使用过PayPalSquare。PayPal的开发难度更大,隐藏的价格远比想象中的还要高,表面上看,每笔钱进来,需要付给PayPal 2.99%的费用,但实际上确付了5%还要高。而且在使用新的PayPal账号的时候,发现新账号不接受信用卡支付。而Square相对于PayPal,开发难度要更简单。但在开发App端的支付时,发现Square的SDK仅仅支持较低版本的安卓系统,这就不得不放弃Square了。

不同的平台有不同的优缺点,总的来说。Stripe开发简单,支付的支付方式很多(支付宝和微信支付目前都已经支持了),适合创业团队使用。而Square对线下的支付有着很好的支持,如果有线下支付的需要的业务可以考虑使用Square。而PayPal更加适合大型企业的使用。

支付平台的选择不是这篇文章的重点,如果想要了解更多的对比细节,可以查看如下的参考文章。

点击这里,可以查看Stripe平台的价格。

参考

支付流程

支付流程)。整个支付流程还是比较简单的,总的来说就是前端通过Stripe平台获取支付令牌,后端利用这个支付令牌进行请求Stripe进行实际支付。用户的信用卡敏感信息不会通过我们的后台,Stripe会帮我们处理复杂的PCI compliance。这里会涉及到企业的免责问题。

stripe-flow.png

  1. 客户端将用户输入的信用卡信息(如果使用的其他的支付方式)发送到 Stripe 服务器。
  2. Stripe 服务器会对用户提交的信用卡信息进行检查校验,如果通过校验,则会返回一个token信息给客户端。
  3. 客户端将token和订单信息发送到服务器。
  4. 服务器会计算该订单的金额,并发送到Stripe服务器进行扣费。这里需要注意是,订单的金额是由后台计算决定的,不是由前端告知后台的。没有人会直接让客户决定商品的价格。
  5. Stripe返回交易结果给服务器端。
  6. 服务将交易结果返回给客户端。

测试账号

为了方便我们进行各种测试,Stripe 为我们的测试提供了足够的测试账号。

  1. Test card numbers and tokens 利用这里的各种类型的卡号可以进行完整流程的测试,token则可以方便后台进行独立的测试。这里提供的支付信息默认都是美国的,如果需要测试其他国家的支付,可以使用国际测试账号
  2. 3D Secure test card numbers and tokens
  3. Testing for specific responses and errors 测试异常和错误的测试卡号和token。
  4. Disputes 纠纷测试卡号和token。
  5. Rate limits
  6. Sources
  7. Redirect sources
  8. Webhooks

一步支付

后台得到支付使用的token之后,在进行收款时, 设置capture为true,Stripe则会直接进行收账。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_yoursecretkey";

// Token is created using Checkout or Elements!
// Get the payment token ID submitted by the form:
String token = request.getParameter("stripeToken");

Map<String, Object> params = new HashMap<>();
params.put("amount", 999);
params.put("currency", "usd");
params.put("description", "Example charge");
params.put("source", token);
// params.put("capture", true);
Charge charge = Charge.create(params);

每个token只能使用一次,而且会很快就会失效了。事实上,token本身是不会失效的,但是CVC信息在很短的时间内可用,在延迟之后使用令牌会导致在没有CVC信息的情况下执行收费。

两步支付

Stripe支持分步骤支付,可以先授权支付,然后等待稍后进行结算。交易的资金将由发卡单位进行担保。授权的有效期为七天,如果没有及时进行收费,授权将会被取消并释放资金。利用两步支付,我们可以在支付流程中增加一个支付审核的流程,用于防止支付欺诈。

第一步: 创建一个uncaptured的charge

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_yoursecretkey";

// Token is created using Checkout or Elements!
// Get the payment token ID submitted by the form:
String token = request.getParameter("stripeToken");

Map<String, Object> params = new HashMap<>();
params.put("amount", 999);
params.put("currency", "usd");
params.put("description", "Example charge");
params.put("source", token);
params.put("capture", false);
Charge charge = Charge.create(params);

第二步: 进行capture

1
2
3
4
5
6
// Set your secret key: remember to change this to your live secret key in production
// See your keys here: https://dashboard.stripe.com/account/apikeys
Stripe.apiKey = "sk_test_yoursecretkey";

Charge charge = Charge.retrieve("ch_mh4nUTTkwbhC3i9gpcm0");
charge.capture();

支付的附加信息

发送支付邮件

Stripe 可以设置每笔账单的邮件接受,每个charge会对该邮箱发送email。

1
params.put("receipt_email", "jenny.rosen@example.com");

设置附加信息

Stripe支持添加Metadata到自己的支付请求中,将会有助于自己管理每笔支付信息。这些信息只有自己可以看到,而客户是看不到的。如果启用的Radar,可以在Radar利用这些信息的设置Radar规则。

1
2
3
Map<String, String> metadata = new HashMap<>();
metadata.put("order_id", 6735);
params.put("metadata", metadata);

支付失败

支付过程中,会存在支付失败的结果。交易结果中会含有失败的类型和原因描述。建议对每种失败类型进行处理,错误列表看: https://stripe.com/docs/declines/codes。decline-codes列表对应outcome.reason。考虑是否需要将这些错误信息转化为平台的错误信息。需要注意的是,前端在获取授权的时候会有哪些错误返回,又应该如何进行展示。并不是所有的交易失败都可以确定具体的原因,这些失败通常会返回 codegeneric,这时候最好让你的客户直接联系发卡银行,咨询具体原因。

返回结果和失败原因

1
2
3
4
5
6
7
8
9
10
...
outcome:
{
network_status: "declined_by_network"
reason: "expired_card"
risk_level: "normal"
seller_message: "The bank returned the decline code `expired_card`."
type: "issuer_declined"
},
...

造成失败的原因可以总结如下:

  1. 支付被发卡单位拒绝 (type:"issuer_declined")
    1. 信息错误,信用卡过期
    2. 有些信用卡会被限制使用的场景和国家,这些都会造成支付失败。
  2. Stripe 安全屏蔽(type: “blocked”)
    1. Stripe 认为交易不安全
  3. 无效的API调用(type: "invalid"。这个在生产环境中应该尽量避免, 该类型失败的支付不会显示在Dashboard中)

如果Stripe屏蔽了一些你知道是合法安全的支付,你可以在Dashboard中标记该卡为安全。标记为安全不会继续尝试本次支付,但是会允许其之后的支付。

编程中对支付失败的处理

如果希望在集成环境中对支付结果进行自动的处理,可以通过如下两种方式对charge的outcome进行处理:

1. 处理支付失败时返回的API错误。 对于被冻结的和信用卡发行方拒绝的付款,错误包括该charge的ID,然后可以使用该charge的ID来retrive该charge。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
try {
// Use Stripe's library to make requests...
} catch (CardException e) {
// Since it's a decline, CardException will be caught
System.out.println("Status is: " + e.getCode());
System.out.println("Message is: " + e.getMessage());
} catch (RateLimitException e) {
// Too many requests made to the API too quickly
} catch (InvalidRequestException e) {
// Invalid parameters were supplied to Stripe's API
} catch (AuthenticationException e) {
// Authentication with Stripe's API failed
// (maybe you changed API keys recently)
} catch (APIConnectionException e) {
// Network communication with Stripe failed
} catch (StripeException e) {
// Display a very generic error to the user, and maybe send
// yourself an email
} catch (Exception e) {
// Something else happened, completely unrelated to Stripe
}

2. 使用webhooks监听事件提示。 当支付失败时,charge.failed事件就会被触发,返回的结果会包含Charge对象。

纠纷和防欺诈

支付平台都应该注意到交易过程中如何处理交易纠纷和防范交易欺诈,以免在交易过程中处于不利地位,设置是亏钱亏货。这部分内容会很多,你可以点击这里到平台中查看更多的信息。下面的内容为我在整理的大概内容。

纠纷

当持卡人向发卡单位提出付款问题时,就会发生争议(也称为退款)。发行方产生正式争议,立即撤销支付。支付的金额,连同卡网收取的另一笔85元争议费(适用于香港的用户),会从你的帐户结余中扣除。

我们需要做的是,如何证明之前的支付是有效的。应该通过 Stripe的Dashboard进行提交资料,因为上面会有一些指导。我们应该在纠纷有效时间内提供证据,否则将无法提供证据. 具体时间有纠纷中提供的信息。而且我们只能提交一次资料,如果资料没有提交完整,在尝试通过email进行提交等都是没有用的。

处理纠纷是要给Stripe交手续费的。
对方获胜: 纠纷金额退换给对方和卡网收取纠纷费用HK$85.00。
我方获胜: 卡网收取纠纷费用HK$85.00,纠纷金额退换给我们。

纠纷创建和关闭时,Stripe都会自动发送一封邮件给你,以及触发 webhook的 charge.dispute.createdcharge.dispute.closed 事件。

纠纷中需要提交的证据(后台开发中需要注意保留这些信息)

  • 网络日志,电子邮件通信,货件跟踪号码和送货确认,先前退款或更换货件的证明等
  • 交易记录中应该保留重要的时间
  • AVS/CVC
  • 支付人支付时候的 IP address
  • 如果是虚拟产品, 需要设法记录用户是否已经下载了该产品, 或者是否已经使用了该服务.

防范纠纷和欺诈

为了防范纠纷和欺诈,我们需要在开发的时候留意一些必要的操作。

1. 收集尽可能多的支付信息

  • 客户的名称
  • 客户的email地址
  • CVC 数字
  • 完整的账单地址和邮政编号
  • 运送地址 (如果和账单地址不一样的话)

有些信息时在前端获取token的时候收集,有些是在后台进行charge的时候收集。(这里需要确认那些信息需要提供给Stripe,进行Radar,以及提供这些信息给Stripe是否安全)。

2. 使用校验检查
当进行支付的时候,Stripe会将我们提供的信息提交到发卡单位,发卡单位会对这些信息进行校验。但验证不通过时,这次支付就又可能就是一次欺诈。因此,强烈推荐收集: CVC,Postal code 和 billing address。这些都有助与帮助检测潜在的欺诈行为。

每个Charge Object中都会含有校验信息. 具体见verification response。当然也可以在Dashboard中看到校验结果。

Card verification code check (CVC) Businesses are not permitted to store the CVC。所以一般而言,CVC只会通过物理丢失,或者在不安全的网站输入而被盗。

Address verification (AVS) AVS checks determine whether these pieces of information match the billing address on file with the card issuer。Radar 默认阻止不通过 postal code verification的支付。注意,如果使用了billing address verification,当用户填写的地址和用户申请信用卡时候的地址不一致,将无法完成支。

如果你有多个商业系统,建议使用不同的账号。Stripe提供了Multiple Account的功能来设置不同的账号。

在平时我们使用绑定信用卡到支付平台的时候,会先进行少量金额的支付,比如一美元,再进行自动退款,应该是为了通知信用卡持有者有人正在使用他的卡进行支付。

线上欺诈的类型

线上欺诈的类型。线上欺诈和对实体商业的欺诈有着根本上的不同,因为在线上你很难确定你实际销售的对象是谁。在接受线上交易是,你非常有必要知道有哪些欺诈方式。

  • Stolen cards 使用偷来的信用卡支付。当信用卡被盗刷卡的持有者通过银行追被盗刷的钱时, 我们的产品或者服务是不会被返回的。这意味我们要同时承担金钱和产品的亏损。
  • Overpayments 支付更多的钱
  • Alternative refunds
  • Marketplace 先支付过多的钱,然后找商家退款,并告知原来的卡已经关闭了,需要退到另一张卡中。其实商家还是可以退款到原来的卡中,用户只要联系银行即可将钱取出。因此我们应该尽量按原路返回退款。
  • Card testing 欺诈前对卡片可支付性进行测试。一般会在没有限制支付金额的网站进行测试。通过实现Captcha或者rate-limiting charges可以有助于和这种类型的欺诈做斗争。
  • Friendly 合法持卡做在进行交易的时候发起的纠纷。开发的时候应尽量对信息进行校验,同时尽量在用户支付的页面中明确地给出支付协议。

识别潜在的欺诈

识别潜在的欺诈。Stripe为我们给出了一些建议,让我们能够尽量提前识别出潜在的欺诈。当然,Stripe的Rada功能也会自动识别出具有高欺诈风险的信用卡付款。如下为内容概要,更加详细的内容以官网内容为准。

  • General 这里提到的内容比较多。这里摘取其中的两点。1,如果用户在下单之后提出修改地址,应该要注意。因为这又可能是为了跳过收获地址的校验。2,对于第一次交易,或者是特殊区域的交易可以做一个特殊的处理。
  • Physical goods 可以利用物理地址信息进行防范。
  • Digital goods or services 虚拟产品的防范需要尽可能地去验证各种信息. 因为没有物流过程, 所以欺诈者可以快速并大量的进行消费。
  • Donations or crowdfunding 大概是因为会直接成功, 所以会经常被拿来测试卡的额度以及测试这张卡是否可用。应该通过 CAPTCHA 等方式减慢信用卡的使用速度。

对于反常的订单(订单金额特别大, 量特别大), 则需要特殊处理, 比如通过电话确认或者email确认之类的.

  • The order is much larger than normal, or is only for your most expensive products
  • The customer changed the shipping address after placing the order
  • The customer requested expedited shipping
  • The products ordered have a hight street resale value
  • The shipping destination is vastly different from the billing address or the card’s country of origin (e.g., billing address is Spain, shipping address is France)

可以在交易流程中增加一个支付审核的流程,并使用两步支付的方法来进行实现。

更加安全

  1. 使用Stripe的Radar[https://stripe.com/docs/radar]
  2. we highly recommend also having Checkout collect the user’s postal code, as address and postal code verifications help reduce fraud. Simply add data-zip-code="true" to the above and make use of Radar’s built-in rules to decline payments that fail verification.
  3. 使用https协议
  4. To best leverage Stripe’s advanced fraud functionality, include this script on every page on your site, not just the checkout page. Including the script on every page allows Stripe to detect anomalous behavior that may be indicative of fraud as users browse your website. <script src="https://js.stripe.com/v3/"></script>

退款

退款一旦发生, 将不会被停止。

全部退款

1
2
3
Map<String, Object> params = new HashMap<>();
params.put("charge", stripeToken);
Refund refund = Refund.create(params);

部分退款

1
2
3
4
Map<String, Object> params = new HashMap<>();
params.put("charge", stripeToken);
params.put("amount", 1000);
Refund refund = Refund.create(params);

可以使用charge.refund.updated监控退款事件。如果charge是通过Customer的方式发生的,且在Customer中含有email信息,则在退款发生时,会发送消息给用户。

小小的注意事项

支付精度

支付精度。在实现支付的时候,我们需要关注Stripe平台的精度。
支付单位
默认使用最小单位, 如美元用美分.对于零位小数货币,仍然以整数形式提供金额,但不乘以100。例如,要收取500英镑,只需提供500英镑的金额。(零位小数货币列表supported charge currencies)

最小支付金额
由于Stripe的处理费结合了一小部分固定金额和百分比,因此在使用Stripe创建费用时强制执行最低金额。这可以确保您不会因收费而损失金钱。您可以收取的最低金额取决于支付的银行帐户结算货币
mininum-charge-amounts.png

最大支付金额
The only limit to the maximum amount you can charge a customer is a technical one. The amount value supports up to eight digits (e.g., a value of 99999999 for a USD charge of $999,999.99).
需要设置美元的最大支付值为 $999,999.99 . 或者设置一个其他的值.

防止Stripe IP无法访问

防止Stripe IP无法访问
因为调用接口需要访问到Stripe的服务器,以及在利用webhooks接受支付回调时,接受Stripe服务器的访问。因此需要在系统里面确保Stripe服务器的可访问性。

为了能够及时的知道Stripe Ip的变动,可以订阅Stripe的API announce mailing list

其他

使用webhooks

使用webhooks可以监控支付的一些触发事件

更多支付方式

这里的介绍中还没有涉及到其他的支付方式,事实上Stripe支持非常多的支付方式,都已经支持支付宝和微信,设置还支持比特币支付。Stripe有一个Payment Intents API可以对多种支付方式做更好的实现。

善用Card和Customer

善用Card和Customer功能,可以方便对支付的管理和提供用户的体验。这里的内容都比较多,暂时就不展开详细介绍了。

账单和发票

Stripe提供账单的功能对指定用户进行周期性的收费,这就可以用与实现类似会员自动续费的功能了。

请不要随便保存用户的信用卡信息

除非你有PCI的认证,否则请不要在数据库中保存用户的信用卡信息,甚至让这些信息经过你的服务器。

IOS应用程序中如果可以使用Stripe可以优先考虑Stripe

根据苹果公司的规定,出售数字化内容需要使用应用内购买,比如电子游戏附带的游戏级别和应用给予用户的虚拟物品。而对于像衣服这样的实物,则允许使用像Stripe 这样的其他支付方案。使用Stripe支付,就可以不用给苹果交高额的费用。

CATALOG
  1. 1. 前言
  2. 2. 基本介绍和与其他支付平台的对比
    1. 2.1. 什么是Stripe
    2. 2.2. 使用范围
    3. 2.3. 和其他平台的简单对比
  3. 3. 支付流程
    1. 3.1. 测试账号
    2. 3.2. 一步支付
    3. 3.3. 两步支付
  4. 4. 支付的附加信息
    1. 4.1. 发送支付邮件
    2. 4.2. 设置附加信息
  5. 5. 支付失败
    1. 5.1. 返回结果和失败原因
    2. 5.2. 编程中对支付失败的处理
  6. 6. 纠纷和防欺诈
    1. 6.1. 纠纷
    2. 6.2. 防范纠纷和欺诈
    3. 6.3. 线上欺诈的类型
    4. 6.4. 识别潜在的欺诈
    5. 6.5. 更加安全
  7. 7. 退款
  8. 8. 小小的注意事项
    1. 8.1. 支付精度
    2. 8.2. 防止Stripe IP无法访问
  9. 9. 其他
    1. 9.1. 使用webhooks
    2. 9.2. 更多支付方式
    3. 9.3. 善用Card和Customer
    4. 9.4. 账单和发票
    5. 9.5. 请不要随便保存用户的信用卡信息
    6. 9.6. IOS应用程序中如果可以使用Stripe可以优先考虑Stripe