产品接入指南

更新时间:

适用场景

适用于在商家移动端 App 内使用支付宝支付功能的场景。

Agent快速接入(推荐)

通过 npx -y @alipay/alipay-aipay@latest install 安装支付宝 AI 付 Skill,加载 alipay-aipay 技能为我的APP 集成支付宝支付,完成沙箱测试,并完成签约入驻

手动接入

整体流程

sequenceDiagram
    participant 用户
    participant 商户APP
    participant 商户服务端
    participant 支付宝

    Note over 用户,支付宝: 支付(必选)

    用户->>商户APP: 1.1 下单
    商户APP->>商户服务端: 1.2 请求生成订单
    商户服务端->>商户服务端: 1.3 [alipay.trade.app.pay]生成 orderStr
    商户服务端-->>商户APP: 1.4 返回 orderStr
    商户APP->>支付宝: 1.5 发起支付

    alt 异常
        支付宝-->>用户: 1.6 展示异常
        支付宝-->>商户APP: 1.7 返回异常
    else 正常
        支付宝-->>用户: 1.6 唤起收银台
        用户->>支付宝: 1.7 输入密码确认支付
        支付宝->>支付宝: 1.8 创建并推进交易
        支付宝-->>商户APP: 1.9 返回支付结果
        商户APP->>商户APP: 1.10 展示结果
        支付宝-->>商户服务端: 1.11 异步通知
        商户服务端->>商户服务端: 1.12 处理通知
        商户服务端->>支付宝: 1.13 查询订单
        支付宝-->>商户服务端: 1.14 返回订单信息
    end

    Note over 用户,支付宝: 退款(可选)

    用户->>商户APP: 2.1 申请退款
    商户APP->>商户服务端: 2.2 请求退款
    商户服务端->>支付宝: 2.3 发起退款
    支付宝-->>商户服务端: 2.4 返回退款结果
    支付宝-->>商户服务端: 2.5 交易状态变更通知

以下对重点步骤做简要说明:

  • 第 1.1 步用户在商户 App 客户端中购买商品下单。
  • 第 1.2 步商户订单信息由商户 App 客户端发送到服务端。
  • 第 1.3 步商家服务端调用 alipay.trade.app.pay(App 支付接口 2.0 接口),通过支付宝服务端 SDK 获取 orderStrorderStr 中包含了订单信息和签名)。
  • 第 1.4 步商家将 orderStr 发送给商户 App 客户端。
  • 第 1.5 步商家在客户端发起请求,将 orderStr 发送给支付宝。
  • 第 1.6 步支付宝进行支付预下单。正常场景下,会唤起支付宝收银台等待用户核身;异常场景下,会返回异常信息。
  • 第 1.9 步返回商家 App:用户在支付宝完成支付后,会跳转回商家页面,并返回最终的支付结果(即同步通知),可查看 同步通知说明
  • 第 1.11 步支付结果异步通知,支付宝会根据步骤 1.3 传入的异步通知地址 notify_url 发送异步通知,可查看 异步通知说明

除了正向支付流程外,支付宝也提供交易查询、关闭、退款、退款查询以及对账等配套 API。

重要说明

  1. 首先确认已完成开通产品、配置密钥等步骤,详情可查看产品一站式接入流程。
  2. 构造交易数据并签名必须在商家服务端完成,商家的应用私钥绝对不能保存在商家 APP 客户端中,也不能从服务端下发。
  3. 服务端生成的 orderStr 只是加签数据,并未请求到支付宝,只有客户端请求后,支付宝才会收到商户的订单信息。
  4. 同步返回的数据,只是一个简单的结果通知,商家确定该笔交易付款是否成功需要依赖服务端收到支付宝异步通知的结果进行判断,建议通过异步+查询方式判断避免错失异步漏失交易信息。
  5. 商家系统接收到通知以后,必须通过验签(验证通知中的 sign 参数)来确保支付通知是由支付宝发送的。建议使用支付宝提供的 SDK 来完成,详细验签规则可查看 异步通知说明异步返回结果验签
  6. 订单创建时间:支付宝订单将在用户输入正确完整的支付密码后创建,并非唤起收银台时创建(余额不足等情况会导致交易处于订单创建等待支付状态)。
  7. 订单支付超时时间:订单创建后未支付,默认最晚付款时间为 15 天,若超过第 15 天当天 24 点订单超时关闭不可支付(超时参数设置范围 5min~15d)。
  8. 异步或查询接口返回的 trade_status(交易状态)为 TRADE_SUCCESSTRADE_FINISHED 时,支付宝才会认定为买家付款成功。
  9. 由于网络异常等原因,可能会导致用户支付成功,但是商户侧未能成功接收到支付结果异步通知。因此当商家未收到支付结果通知时,必须要调用 alipay.trade.query(统一收单交易查询接口)来获取支付结果。
  10. 判断退款成功:退款接口返回 fund_change=Y 或者退款查询接口返回 refund_status=REFUND_SUCCESS

注意fund_change 只表示本次接口请求是否资金变动,不是指该笔交易是否资金变动。如果第一次退款成功,返回 Y,但是相同参数(如 out_request_no 不变)第二次请求则会返回 N,因此当 fund_change=N 时,建议通过退款查询接口进一步判断。

交易状态流程

flowchart TB
    START["下单唤起支付宝支付"]

    WAIT{"创建交易<br/>WAIT_BUYER_PAY<br/>创建交易,等待买家付款"}
    SUCCESS["交易成功<br/>TRADE_SUCCESS<br/>交易成功,可退款"]
    FINISHED["交易完成<br/>TRADE_FINISHED<br/>交易结束,不可退款"]
    CLOSED["交易关闭<br/>TRADE_CLOSED<br/>未付款交易超时关闭,<br/>或支付完成后全额退款"]

    START --> WAIT

    WAIT -- "① 买家付款成功" --> SUCCESS
    SUCCESS -- "② 退款期结束" --> FINISHED
    SUCCESS -- "③ 部分退款" --> SUCCESS
    SUCCESS -- "④ 全额退款" --> CLOSED
    WAIT -- "⑤ 未付款超时关闭" --> CLOSED
    WAIT -- "⑥ 支付成功且不可退款" --> FINISHED

随着订单支付成功、退款、关闭等操作,订单交易的每一个环节 trade_status(交易状态)也不同。

  1. 交易创建成功后,用户支付成功,交易状态转为 TRADE_SUCCESS(交易成功)
  2. 交易成功后,规定退款时间内没有退款,交易状态转为 TRADE_FINISHED(交易完成)
  3. 交易支付成功后,交易部分退款,交易状态仍为 TRADE_SUCCESS(交易成功)
  4. 交易成功后,交易全额退款,交易状态转为 TRADE_CLOSED(交易关闭)
  5. 交易创建成功后,用户未付款交易超时关闭,交易状态转为 TRADE_CLOSED(交易关闭)
  6. 交易创建成功后,用户支付成功后,若用户商品不支持退款,交易状态直接转为 TRADE_FINISHED(交易完成)

注意:交易成功后部分退款,交易状态仍为 TRADE_SUCCESS(交易成功)。

如果一直部分退款退完所有交易金额则交易状态转为 TRADE_CLOSED(交易关闭)。

如果未退完所有交易金额,超过有效退款时间后交易状态转为 TRADE_FINISHED(交易完成)不可退款。

支付流程

服务端接入:获取orderStr

示例代码、参数说明及错误码等信息,可查看 alipay.trade.app.pay(App 支付接口 2.0 接口) 接口文档。

orderStr 示例代码:

alipay_sdk=alipay-sdk-java-dynamicVersionNo&app_id=2014100900010000&biz_content=%7B%22total_amount%22%3A%220.01%22%2C%22product_code%22%3A%22QUICK_MSECURITY_PAY%22%2C%22subject%22%3A%22%E5%93%88%E5%93%88%E5%93%88%E5%93%88%E5%93%88%E5%A4%A7%E4%B9%90%E9%80%8F%22%2C%22out_trade_no%22%3A%2220220530000000011111101%22%7D&charset=utf-8&format=json&method=alipay.trade.app.pay&sign=iuO%2FTso2zr236p%2F%2FgyVoM9B7JGhyQqHHlL82siLLPI90xUruDVRt8hIOAroNid%2FTCbYUENSV4FkIZ5krrXm1qDFLHUnvtsUA3kToEojxyKilR8czZFYm6w91oxJseFZQJe0Os6IJg8oG29tYRf9TiXjB0leSwGQ3Ax8VilW2ATsne9L4A9Xah5fz7PTlKURTMYFqU166J2RH769wtTOjOb5Gs74aSdB3ymlZ486%2FGAcFwyXSvd3i8FEzsx3obLaM3oRQGQ%2Fx2jn8aL5qH3nVkGFIKA4xAUOZAaZSrj4EFw17HPFBYvcPwG55DQlmyLluh5lb4Ibi3j1ZxR4NiB0YFQ%3D%3D&sign_type=RSA2&timestamp=2022-05-30+17%3A43%3A28&version=1.0

客户端接入

安装 SDK:

# Podfile
pod 'AlipaySDK-iOS'

在支付订单页提前注册 AppID(非强依赖,但能加快唤起速度):

#import <AlipaySDK/AlipaySDK.h>

// 建议在进入支付订单页时调用,不是在点击付款按钮时
[[AlipaySDK defaultService] registerApp:@"你的APPID" universalLink:@"你的Universal Link"];

点击付款按钮时:

// 第一步:请求你的服务端,拿到 orderStr
// (省略网络请求代码,用你项目中已有的网络库实现)
NSString *orderStr = [从服务端返回的结果中取出];

// 第二步:把 orderStr 传给支付宝 SDK,唤起收银台
NSString *appScheme = @"你的AppScheme"; // 在 Info.plist > URL Types 中注册
[[AlipaySDK defaultService] payOrder:orderStr fromScheme:appScheme callback:^(NSDictionary *resultDic) {
    // 第六步:收到同步回调(用户在支付宝完成操作后跳回你的 App)
    NSString *resultStatus = resultDic[@"resultStatus"];
    [self handlePayResult:resultStatus result:resultDic[@"result"]];
}];

在 AppDelegate 中配置回调处理(必须实现,否则已安装支付宝的场景结果无法回传):

// iOS 9.0+
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url
            options:(NSDictionary<NSString*, id> *)options {
    if ([url.host isEqualToString:@"safepay"]) {
        [[AlipaySDK defaultService] processOrderWithPaymentResult:url
            standbyCallback:^(NSDictionary *resultDic) {
                // 同上,处理支付结果
                NSString *resultStatus = resultDic[@"resultStatus"];
                [self handlePayResult:resultStatus result:resultDic[@"result"]];
            }];
    }
    return YES;
}

Info.plist 配置: 在 URL Types 中添加你的 App Scheme,并在 LSApplicationQueriesSchemes 中添加 alipay,用于检测是否安装了支付宝 App。

添加 SDK 依赖(在 app/build.gradle 中):

// 将支付宝提供的 aar 文件放入 libs 目录
implementation fileTree(dir: 'libs', include: ['*.aar'])

在 AndroidManifest.xml 中声明必要的 Activity(缺少则 H5 支付无法唤起):

<activity
    android:name="com.alipay.sdk.app.H5PayActivity"
    android:configChanges="orientation|keyboardHidden|navigation|screenSize"
    android:exported="false"
    android:screenOrientation="behind"
    android:windowSoftInputMode="adjustResize|stateHidden" />

点击付款按钮时(需在子线程中执行,避免阻塞 UI):

// 第一步:请求你的服务端,拿到 orderStr
String orderStr = 从服务端拿到的结果;

// 第二步:在子线程中调用支付宝 SDK
new Thread(() -> {
    PayTask alipay = new PayTask(activity);
    Map<String, String> result = alipay.payV2(orderStr, true);

    // 回到主线程处理结果
    runOnUiThread(() -> {
        String resultStatus = result.get("resultStatus");
        handlePayResult(resultStatus, result.get("result"));
    });
}).start();
ohpm install @cashier_alipay/cashiersdk

module.json5 中配置:

"module": {
    "querySchemes": ["https"]   // SDK >= 15.8.29
}

点击付款按钮时:

import { Pay } from '@cashier_alipay/cashiersdk';

// 第一步:请求你的服务端,拿到 orderStr
const orderStr = await fetchOrderStrFromServer();

// 第二步:调用支付宝 SDK
new Pay().pay(orderStr, true)
    .then((result) => {
        const resultStatus = result.get('resultStatus');
        handlePayResult(resultStatus);
    })
    .catch((error: BusinessError) => {
        console.error(error.message);
    });

异步通知

App 支付异步通知发送到 alipay.trade.app.pay(App 支付接口 2.0 接口) 加签时入参的公共参数 notify_url 地址中,未设置该参数则不触发异步。通知参数及规则详见 异步通知说明

注意:由于网络异常等原因,可能会导致用户支付成功,但是商户侧未能成功接收到支付结果异步通知。因此当商家未收到支付结果通知时,必须要调用 alipay.trade.query(统一收单交易查询接口)来获取支付结果。

支付结果查询

商家可调用 alipay.trade.query(统一收单交易查询接口),通过商家网站唯一订单号 out_trade_no 或支付宝交易号 trade_no 查询对应订单支付情况。

重要入参说明

注意: 请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。

参数名参数说明
out_trade_no支付时传入的商户订单号,与 trade_no 必填一个。
trade_no支付时返回的支付宝交易号,与 out_trade_no 必填一个。

退款流程

交易发生后的一段时间内,由于业务原因(如金额错误、用户退款或者对账不平等)需要退款时,商家可以调用 alipay.trade.refund(统一收单交易退款接口),通过 out_trade_no(商家网站唯一订单号)或 trade_no(支付宝交易号),将对应订单支付款退还给买家。支付宝将在收到退款请求并且验证成功之后,按照退款规则将支付款按原路退到买家账号上。

说明: 支持全额或部分退款。

接口流程

sequenceDiagram
    participant 商户服务端
    participant 支付宝服务端

    商户服务端->>支付宝服务端: 1. 调用 alipay.trade.refund 接口发起退款请求
    支付宝服务端-->>商户服务端: 2. 返回退款结果

退款结果

退款说明

  • 退款周期: 默认12 个月,即交易发生后 12 个月内可发起退款,超过 12 个月则不可发起退款。
  • 退款方式: 资金原路返回用户账号。
  • 退款退费: 默认退款时手续费不退回。
  • 支付渠道为花呗、余额等退款即时到账。
  • 银行卡的退款时间以银行退款时间为准,一般情况下 2 小时内可到账(若退款到卡失败,退款金额会退回用户支付宝账户余额)。
  • 商家可以在 商家平台 > 对账中心 > 交易订单 中退款。
  • 退款接口会根据外部请求号 out_request_no 幂等返回,因此同一笔交易需要多次部分退款时,必须使用不同的 out_request_no

重要入参说明

注意: 请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。

参数名参数说明
out_trade_no支付时传入的商户订单号,与 trade_no 必填一个。
trade_no支付时返回的支付宝交易号,与 out_trade_no 必填一个。
out_request_no本次退款请求流水号,部分退款时必传。
refund_amount本次退款金额。

重要出参说明

参数名参数说明
refund_fee该笔交易已退款的总金额。

查询退款结果

商家/服务商可调用 alipay.trade.fastpay.refund.query(统一收单交易退款查询接口) 查询对应 out_request_no(退款请求号)的退款情况。

重要说明

  1. 退款查询接口的 trade_noout_trade_noout_request_no 必须和退款接口保持一致,否则交易号一致、out_request_no 不同,只会返回 10000success,但是没有具体的退款信息。
  2. 该接口的返回 10000 仅代表本次查询操作成功,不代表退款成功;当接口返回的 refund_status 值为 REFUND_SUCCESS 时表示退款成功,否则表示退款没有执行成功。

重要入参说明

注意: 请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。

参数名参数说明
out_trade_no支付时传入的商户订单号,与 trade_no 必填一个。
trade_no支付时返回的支付宝交易号,与 out_trade_no 必填一个。

对账流程(可选)

目前支付宝对外的常用对账方式有两种:

  • 一种是通过在 商家平台 > 对账中心 下载账单的方式来对账。
  • 一种是通过调用接口的方式来实现对账,下文介绍如何通过接口获取对账单下载链接。更多后台下载及账单示例图详情可查看 对账说明

商家可通过接口下载指定日期(当天除外)的业务明细账单文件,并结合自身业务系统实现自动对账。

接口流程

sequenceDiagram
    participant 商户服务端
    participant 支付宝服务端

    商户服务端->>支付宝服务端: 1. 调用 alipay.data.dataservice.bill.downloadurl.query 接口
    支付宝服务端-->>商户服务端: 2. 返回对账单下载地址
    商户服务端->>支付宝服务端: 3. 通过 HTTP 请求对账单下载地址
    支付宝服务端-->>商户服务端: 4.获得对账单文件流
    商户服务端->>商户服务端: 5. 读取文件流处理 CSV 文件自动对账,或保存至本地
  1. 商家系统调用 alipay.data.dataservice.bill.downloadurl.query(查询对账单下载地址接口),传入指定日期,获得该日期账单文件的下载地址。
  2. 商家系统通过 HTTP 方式后台访问账单下载链接,将账单 CSV 文件下载到本地后自行处理。注意该下载链接仅 30 秒,在得到链接后系统需要立刻下载账单文件。

重要入参说明

**注意:**请严格按照接口文档中的参数入参,传入非接口文档中的参数是无效的,并且可能会导致请求被拦截或其它异常。

参数名参数说明
bill_type固定传入 trade
bill_date需要下载的账单日期,最晚是当期日期的前一天。

下载账单文件示例代码

//将接口返回的对账单下载地址传入urlStr
String urlStr = "下载地址";
//指定希望保存的文件路径
String filePath = "/Users/fund_bill_20160405.csv.zip";
URL url = null;
HttpURLConnection httpUrlConnection = null;
InputStream fis = null;
FileOutputStream fos = null;
try {
    url = new URL(urlStr);
    httpUrlConnection = (HttpURLConnection) url.openConnection();
    httpUrlConnection.setConnectTimeout(5 * 1000);
    httpUrlConnection.setDoInput(true);
    httpUrlConnection.setDoOutput(true);
    httpUrlConnection.setUseCaches(false);
    httpUrlConnection.setRequestMethod("GET");
    httpUrlConnection.setRequestProperty("CHARSET", "UTF-8");
    httpUrlConnection.connect();
    fis = httpUrlConnection.getInputStream();
    byte[] temp = new byte[1024];
    int b;
    fos = new FileOutputStream(new File(filePath));
    while ((b = fis.read(temp)) != -1) {
        fos.write(temp, 0, b);
        fos.flush();
    }
} catch (MalformedURLException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        if(fis!=null) fis.close();
        if(fos!=null) fos.close();
        if(httpUrlConnection!=null) httpUrlConnection.disconnect();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

附录:自定义参数说明

  1. 商家在请求参数中自己附加的一些额外参数,请勿和支付宝系统中约定的 key(如 alipay.trade.app.pay(App 支付接口 2.0)等接口 公共请求参数/请求参数重名,否则将可能导致未知的异常。
    1. 例如以下示例中 app_id=2014072300007148&version=1.0&biz_content 的 key 是公共请求参数,商家/服务商自己的扩展参数需要放在 biz_content 内部,例如示例中 tips 属性。下面 total_amount 属性是商家按照自己的业务属性赋值的,但是由于 total_amount 同时也是支付宝关键 key,支付宝将会认为这个 total_amount 是支付宝业务的参数应该是金额,这个最终将导致误解析。
    2. **注意:**下列请求串为了展示清晰,未进行 encode 并且做了格式化处理。
app_id=2014072300007148&charset=UTF-8&version=1.0&timestamp=2016-07-01 08:08:08&method=alipay.trade.app.pay&notify_url=https://api.**.com/pay_receive_notify.html&sign_type=RSA2&sign=ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE&version=1.0&biz_content=
{
  "body":"对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。",
  "subject":"大乐透",
  "out_trade_no":"70501111111S001111119",
  "timeout_express":"90m",
  "total_amount":"一共花费了10元",
  "product_code":"QUICK_MSECURITY_PAY",
  "tips":"测试一笔支付"
  }
  1. 商家的请求参数中,所有的 key(支付宝关键 key 或者商家自己的 key),其对应的 value 中都不应该出现支付宝关键 key,否则该类交易将可能被支付宝拦截禁止支付。
    1. 例如以下的请求中 "subject":"大乐透 这个辣条不错 out_trade_no=123 total_fee=123.5",其 value 值中有支付宝关键 key 值 out_trade_nototal_fee,这样的业务请求参数支付宝将会拦截。
    2. 注意: 下列请求串为了展示清晰,未进行 encode 并且做了格式化处理。
app_id=2014072300007148&charset=UTF-8&version=1.0&timestamp=2016-07-01 08:08:08&method=alipay.trade.app.pay&notify_url=https://api.**.com/pay_receive_notify.htm&sign_type=RSA2&sign=ERITJKEIJKJHKKKKKKKHJEREEEEEEEEEEE&version=1.0&biz_content=
  {
    "body":"对一笔交易的具体描述信息。如果是多种商品,请将商品描述字符串累加传给body。",
    "subject":"大乐透 这个辣条不错 out_trade_no=123 total_fee=123.5",
    "out_trade_no":"70501111111S001111119",
    "timeout_express":"90m",
    "total_amount":10.0,
    "product_code":"QUICK_MSECURITY_PAY"
  }
  1. 商家支付请求参数的安全注意点
    1. 请求参数的 sign 字段请务必在服务端完成签名生成(不要在客户端本地签名)。
    2. 支付请求中的 total_amount(订单金额) ,请务必依赖服务端,不要轻信客户端上行的数据(客户端本地上行数据在用户手机环境中无法确保一定安全)。