# uni.requestPayment(OBJECT)

pay

uni.requestPayment is a client-side payment API that unifies all platforms. Whether it is in a MiniApp or an App, the client uses this API to call payment.

When this API runs on each terminal, it will be automatically converted to the native payment calling API of each terminal.

Note that payment requires not only client-side development, but also server-side development. Although the client API is unified, the payment application opening and configuration backfill of each platform still need to look at the payment documents of each platform.

For example, WeChat has different application entrances and usage processes such as App payment, MiniApp payment, H5 payment, etc. Corresponding to uni-app, you need to apply for WeChat App Payment on the App side, while the MiniApp side applies for WeChat MiniApp Payment.

如果服务端使用uniCloud,那么官方提供了uniPay云端统一支付服务,把App、微信小程序、支付宝小程序里的服务端支付开发进行了统一的封装。

前端统一的uni.requestPayment和云端统一的uniPay搭配,可以极大提升支付业务的开发效率,强烈推荐给开发者使用。uniPay的文档另见:https://doc.dcloud.net.cn/uniCloud/uni-pay/uni-app.html

Platform Difference Description

App H5 微信小程序 支付宝小程序 百度小程序 抖音小程序 飞书小程序 QQ小程序 快手小程序 京东小程序
Description x x

OBJECT parameter description

Parameter Name Type Required Description Platform Difference Description
provider String 服务提供商,通过 uni.getProvider 获取。
orderInfo String/Object 订单数据,注意事项 App、支付宝小程序、百度小程序、抖音小程序
timeStamp String Required for WeChat MiniApp Timestamp seconds from January 1, 1970 to the present, that is, the current time. WeChat MiniApp
nonceStr String Required for WeChat MiniApp Random string with a length of 32 characters or less. WeChat MiniApp
package String Required for WeChat MiniApp The value of the prepay_id parameter returned by the unified ordering interface. The submission format is: prepay_id=xx. WeChat MiniApp
signType String Required for WeChat MiniApp Signature algorithm, which should be the same as the value when placing an order in the background WeChat MiniApp
paySign String Required for WeChat MiniApp Signature, please refer to WeChat MiniApp Payment Document WeChat MiniApp
bannedChannels Array<String> 需要隐藏的支付方式,详见 百度小程序支付文档 百度小程序
service Number 抖音小程序必填 固定值:5(拉起小程序收银台)开发者如果不希望使用抖音小程序收银台,service设置为3/4时,可以直接拉起微信/支付宝进行支付:service=3: 微信API支付,不拉起小程序收银台;service=4: 支付宝API支付,不拉起小程序收银台。其中service=3、4,仅在1.35.0.1+基础库(头条743+)支持 抖音小程序
_debug Number 仅限调试用,上线前去掉该参数。_debug=1时,微信支付期间可以看到中间报错信息,方便调试 抖音小程序
getOrderStatus Function 抖音小程序必填 商户前端实现的查询支付订单状态方法(该方法需要返回个Promise对象)。 service=3、4时不需要传。 抖音小程序
success Function No Callback for successful interface call
fail Function No Callback function for interface call failure
complete Function No The callback function of the end of the interface call (the call will be executed if the call succeeds or fails)

WeChat MiniAppsignType description

legal value description
MD5 Only available in v2 version interface
HMAC-SHA256 Only available on v2 interface
RSA Only available in v3 interface

# Precautions

  • APP端,如果你的应用在用户完成支付后;立即给支付的用户push消息通知。会与前端支付回调相互冲突,请延迟执行推送。
  • 抖音小程序支付接口调整使用时请注意发起头条支付

# orderInfo Notes

  1. The orderInfo of Baidu MiniApp is of Object type. For detailed data structure, please refer to: Baidu Cashier Payment.
  2. 支付宝小程序的 orderInfo(支付宝的规范为 tradeNO) 为 String 类型,表示支付宝交易号。
  3. 抖音小程序的 orderInfo 为 Object 类型,详见:发起头条支付
  4. On the App side, Alipay payment orderInfo is of String type.
  5. On the App side, the WeChat payment orderInfo is of type Object.
  6. On the App side, Apple in-app payment orderInfo is of type Object, {productid: 'productid'}.

# H5 平台

  • 普通浏览器平台的支付,仍然是常规web做法。uni-app未封装。但DCloud提供了uni-pay插件,已封装了web支付,详见
  • 在普通浏览器里也可以调起微信进行支付,这个在微信叫做H5支付,此功能未开放给普通开发者,需向微信单独申请,详见
  • 微信内嵌浏览器运行H5版时,可通过js sdk实现微信支付,需要引入一个单独的js,详见,也可以直接使用uni-pay,无需再单独引入其他js

Description of payment conditions supported by each platform

  • 微信小程序里只支持微信小程序支付,在 微信商户平台 申请支付时,选择公众号支付。
  • App 里支持微信sdk支付、支付宝sdk支付、苹果iap应用内支付,在各平台申请支付时选择 App 支付。其他支付(如银联)请使用web-view组件以H5方式实现或在插件市场搜索相应插件。
  • The Alipay MiniApp only supports Alipay payment.
  • Baidu MiniApp is Baidu Pay, which encapsulates Duxiaoman, Alipay and WeChat Pay.
  • Various payments are demonstrated in Hello uniapp.

# App platform payment process

Process: Payment platform function application -> configure payment parameters in manifest.json -> call API in uni-app for payment

  1. Check payment in manifest.json - App module permission selection
  2. manifest.json - App SDK配置 中,勾选需要的支付平台,目前有微信支付、支付宝支付、苹果应用内支付(IAP),其中微信支付需要填写从微信开放平台获取的AppID
  3. These configurations need to be packaged to take effect, and the real machine operation is still the setting of the HBuilder base, which can be debugged with a custom base. For offline packaging, please refer to the offline packaging documentation to configure in the native project.
  4. After configuration and packaging, you can get a list of configuration results through uni.getProvider. Note that what is returned here is the manifest configuration, which has nothing to do with whether WeChat or Alipay is installed on the mobile phone.

# App payment

# Example

uni.requestPayment({
    provider: 'alipay',
    orderInfo: 'orderInfo', //微信、支付宝订单数据 【注意微信的订单信息,键值应该全部是小写,不能采用驼峰命名】
    success: function (res) {
        console.log('success:' + JSON.stringify(res));
    },
    fail: function (err) {
        console.log('fail:' + JSON.stringify(err));
    }
});

# Alipay App payment

# application process

Log in to the Alipay account and create an application to access the Alipay App payment capability, including the following steps:

- Create app (get appid)
- Activate the App payment function
- Configure keys (get public key, private key)

For details, please refer to the official Alipay documentation: Quick access to App payment

If Alipay is not installed on the mobile phone, it will start Alipay's wap page login when it is called. If the corresponding client has been installed, its client login will be started.

# WeChat App payment

# application process

  • Go to the WeChat Open Platform to apply for a mobile application and enable the payment function. After applying for the application, you can get the AppID and AppSecret value
  • App access WeChat Merchant Platform, select App to pay
  • After the payment function is activated, the configuration data of the payment service server can be obtained: PARTNER (Tenpay merchant number), PARTNER_KEY (Tenpay key), PAYSIGNKEY (payment signature key)
  • You need to fill in the appid applied for from the WeChat Open Platform back to manifest-App SDK Configuration-Payment-WeChat Payment. Effective after packaging.

For details, please refer to the official WeChat document: Mobile Application Development

Note that WeChat's App payment, MiniApp payment, and H5 payment are different systems. WeChat MiniApp Payment When applying for payment on the WeChat Merchant Platform, select the official account payment; ordinary browsers can also call up WeChat for payment, which is called H5 payment in WeChat , this function is not open to ordinary developers, you need to apply to WeChat separately, [see details]( https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=15_1 )

# Sample code

uni.requestPayment({
    "provider": "wxpay", 
    "orderInfo": {
        "appid": "wx499********7c70e",  // 微信开放平台 - 应用 - AppId,注意和微信小程序、公众号 AppId 可能不一致
        "noncestr": "c5sEwbaNPiXAF3iv", // 随机字符串
        "package": "Sign=WXPay",        // 固定值
        "partnerid": "148*****52",      // 微信支付商户号
        "prepayid": "wx202254********************fbe90000", // 统一下单订单号 
        "timestamp": 1597935292,        // 时间戳(单位:秒)
        "sign": "A842B45937F6EFF60DEC7A2EAA52D5A0" // 签名,这里用的 MD5/RSA 签名
    },
    success(res) {},
    fail(e) {}
})

# Apple In-App Payments

# application process

Log in to [App Store Connect](https://appstoreconnect.apple.com) with your Apple developer account, and add in-app purchases on the function tab page of the app. Notice:
- The information of the in-app purchase item needs to be filled in completely and then saved. At this time, the status of the in-app purchase item should be ready to submit. When the submitted application passes the review, the status will become approved
- When testing, it is recommended to use a test certificate to hit a custom iOS dock for testing
- Add an App Store Connect user in the app TestFight tab, you can use this user account for testing when testing payments

# Payment Process

  1. Get the payment channel (uni.getProvider)

  2. Get the product list through the payment channel (iapChannel.requestProduct)

  3. Check if there are open orders (iapChannel.restoreCompletedTransactions, optional check at the right time)

  4. Request payment, pass product information (uni.requestPayment)

  5. The client receives the payment receipt returned by Apple and sends it to the server, where the server requests the Apple server to verify whether the payment is valid

  6. The server closes the order on the client side after verifying that the ticket is valid (iapChannel.finishTransaction)

Before HBuilder 3.5.1, the order was lost in some cases due to the automatic closing of the order

HBuilder 3.5.1 + added the parameter manualFinishTransaction to manually close the order, call iapChannel.finishTransaction at the right time to close the order

HBuilder 3.5.1+ starts to support the method of getting IAP payment channel through uni.getProvider

# Get IAP payment channel

uni.getProvider({
  service: 'payment',
  success: (res) => {
    const iapChannel = res.providers.find((channel) => {
      return (channel.id === 'appleiap')
    })

    // If iapChannel is null, it means that the current package does not contain the iap payment module. Note: HBuilder base does not contain iap channel
  }
});

# Get product list from Apple server

iapChannel.requestProduct(<Function> success, <Function> fail)

success callback value type Array<Product>

# Get the list of transactions that have been paid by the Apple server and have not been closed

iapChannel.restoreCompletedTransactions(<Function> success, <Function> fail)

success callback value type Array<Transaction>

# Close Apple Server Order

iapChannel.finishTransaction(Transaction, <Function> success, <Function> fail)

All fail callbacks have the format { errCode: xxx, errMsg: '' }

# Request payment uni.requestPayment()

uni.requestPayment({
    provider: 'appleiap',
    orderInfo: {},
    success: (e) => {
      // e is of type Transaction, see the description below for details
    }
})

# Parameter Description

# orderInfo

property type default value description
productid String Product id, configured in Apple Developer Center
username String Transparent parameter, generally used to mark the relationship between the order and the user, this field is returned when the ticket is verified to the Apple server twice
quantity Number 1 The purchase quantity, at least 1
manualFinishTransaction Boolean false 3.5.1+ 支持,手动关闭订单,值为 false 时支付完成后自动关闭订单,true时不关闭订单,需要在合适的时机调用 finishTransaction 关闭订单。建议设置为 true, 默认值为 false 是为了向下兼容
paymentDiscount Object 促销优惠(HBuilderX 3.7.0+ 手机系统iOS12.2+支持)
# 促销优惠参数说明
属性 类型 必填 说明
offerIdentifier String 促销id
keyIdentifier String 密钥
nonce String 唯一id (必须小写 24小时有效)
signature String 签名
timestamp Number 创建证书的时间戳(毫秒 24小时有效)

# Product

property type description
title String Product title
description String Product description
productid String Product id, configured in Apple Developer Center
price Number Price
pricelocal String 币种,例如: zh_CN@currency=CNY
discount Array 折扣信息(HBuilderX 3.7.0+ 手机系统iOS12.2+支持)
# Discount
属性 类型 说明
price Number 促销价格
periodUnit String 周期单位(day: 日,week: 周,month: 月,year: 年)
discountType String 优惠类型(introductory: 推介促销 subscription: 订阅促销)
promotionType String 促销类型(payAsYouGo: 随用随付,payUpFront: 预先支付,freeTrial: 免费试用)
code String 促销代码
units Number 促销期数

# Transaction

property type description
payment Object Payment information, see description below for details
transactionDate String Transaction date, example 2022-01-01 08:00:00
transactionIdentifier String Transaction Unique Identifier
transactionReceipt String The payment receipt is used to verify the validity of the transaction to Apple's server twice on the developer's server
transactionState String Transaction Status Code

# Payment

property type description
productid String productid
quantity String Purchase Quantity
username String Transparent parameter

# transactionState

Value type: String

value description
1 Successful transaction

Precautions

  • For the same order, transactionReceipt will change after calling restoreCompletedTransactions repeatedly, not a unique value
  • Calling finishTransaction to close the order may not take effect immediately, depending on Apple's servers
  • Sandbox environment: a test account can only purchase the same product once, repeated tests need to clear the purchase record or re-add the sandbox test account
  • Sandbox environment: calling restoreCompletedTransactions has no response for a long time, check whether the sandbox account logged in by the device is normal

# Sandbox account

  1. Log in to the Apple Developer Center and add a sandbox account
  2. Log in to the sandbox account on your phone or iPad, go to System Settings -> App Store

# Order Lost Scenario

  • The user does not bind the AppStore payment method, call uni.requestPayment() to prepare for payment, trigger the failed fail callback, errCode=2, the user has not bound the payment method, and the in-app payment process ends. The system pop-up box guides the user to bind the payment method. This process will jump to the system application AppStore to bind the payment method. If the binding is successful, the synchronization payment is successful, and the user successfully pays.

# Sample code

<template>
  <view class="content">
    <view class="uni-list">
      <radio-group @change="applePriceChange">
        <label class="uni-list-cell" v-for="(item, index) in productList" :key="index">
          <radio :value="item.productid" :checked="item.checked" />
          <view class="price">{{item.title}} {{item.price}}</view>
        </label>
      </radio-group>
    </view>
    <view class="uni-padding-wrap">
      <button class="btn-pay" @click="payment" :loading="loading" :disabled="disabled">确认支付</button>
    </view>
  </view>
</template>

<script>
  import {
    Iap,
    IapTransactionState
  } from "./iap.js"

  export default {
    data() {
      return {
        title: "iap",
        loading: false,
        disabled: true,
        productId: "",
        productList: []
      }
    },
    onLoad: function() {
      // create example
      this._iap = new Iap({
        products: [] // 苹果开发者中心创建
      })

      this.init();
    },
    onShow() {
      if (this._iap.ready) {
        this.restore();
      }
    },
    onUnload() {},
    methods: {
      async init() {
        uni.showLoading({
          title: '检测支付环境...'
        });

        try {
          // Initialize, get the iap payment channel
          await this._iap.init();

          // Get product list from apple server
          this.productList = await this._iap.getProduct();
          this.productList[0].checked = true;
          this.productId = this.productList[0].productid;

          // populate the product list, enable the interface
          this.disabled = false;
        } catch (e) {
          uni.showModal({
            title: "init",
            content: e.message,
            showCancel: false
          });
        } finally {
          uni.hideLoading();
        }

        if (this._iap.ready) {
          this.restore();
        }
      },
      async restore() {
        // Check the order that the user has paid and has not closed last time, the possible reasons: the first time the card is bound, the network is interrupted, etc.

        // Check if the user is logged in here

        uni.showLoading({
          title: '正在检测已支付且未关闭的订单...'
        });

        try {
          // Check unclosed orders from Apple server, optionally filter according to username, which is consistent with the value passed through when calling payment
          const transactions = await this._iap.restoreCompletedTransactions({
            username: ""
          });

          if (!transactions.length) {
            return;
          }

          // Developer business logic, get the current user's unfinished order list from the server, and compare with the local
          // omitted here

          switch (transaction.transactionState) {
            case IapTransactionState.purchased:
              //let result = await this.validatePaymentResult();

              // if (result) {
              //   await this._iap.finishTransaction(transaction);
              // }
              break;
            case IapTransactionState.failed:
              // close unpaid orders
              await this._iap.finishTransaction(transaction);
              break;
            default:
              break;
          }
        } catch (e) {
          uni.showModal({
            content: e.message,
            showCancel: false
          });
        } finally {
          uni.hideLoading();
        }
      },
      async payment() {
        if (this.loading == true) {
          return;
        }
        this.loading = true;

        uni.showLoading({
          title: '支付处理中...'
        });

        try {
          // const orderId = await this.createOrder({
          //   productId: this.productId
          // });

          // Request Apple Pay
          const transaction = await this._iap.requestPayment({
            productid: this.productId,
            manualFinishTransaction: true,
            // username: username + orderId //Transparent parameters according to business requirements, associating user and order relationship
          });

          // await this.validatePaymentResult({
          //   orderId: orderId,
          //   username: username,
          //   transactionIdentifier: transaction.transactionIdentifier
          // });

          //await this._iap.finishTransaction(transaction);

          // payment successful
        } catch (e) {
          uni.showModal({
            content: e.message,
            showCancel: false
          });
        } finally {
          this.loading = false;
          uni.hideLoading();
        }
      },
      createOrder({
        productId
      }) {
        return new Promise((resolve, reject) => {})
      },
      validatePaymentResult(data) {
        return new Promise((resolve, reject) => {});
      },
      applePriceChange(e) {
        this.productId = e.detail.value;
      }
    }
  }
</script>

<style>
  .content {
    padding: 15px;
  }

  button {
    background-color: #007aff;
    color: #ffffff;
  }

  .uni-list-cell {
    display: flex;
    flex-direction: row;
    align-items: center;
    padding: 10px;
    border-bottom: 1px solid #eee;
  }

  .price {
    margin-left: 10px;
  }

  .btn-pay {
    margin-top: 30px;
  }
</style>
// uni iap

const ProviderType = {
  IAP: 'iap'
}

const IapTransactionState = {
  purchasing: "0", // A transaction that is being processed by the App Store.
  purchased: "1", // A successfully processed transaction.
  failed: "2", // A failed transaction.
  restored: "3", // A transaction that restores content previously purchased by the user.
  deferred: "4" // A transaction that is in the queue, but its final status is pending external action such as Ask to Buy.
};

class Iap {

  _channel = null;
  _channelError = null;
  _productIds = [];

  _ready = false;

  constructor({
    products
  }) {
    this._productIds = products;
  }

  init() {
    return new Promise((resolve, reject) => {
      this.getChannels((channel) => {
        this._ready = true;
        resolve(channel);
      }, (err) => {
        reject(err);
      })
    })
  }

  getProduct(productIds) {
    return new Promise((resolve, reject) => {
      this._channel.requestProduct(productIds || this._productIds, (res) => {
        resolve(res);
      }, (err) => {
        reject(err);
      })
    });
  }

  requestPayment(orderInfo) {
    return new Promise((resolve, reject) => {
      uni.requestPayment({
        provider: 'appleiap',
        orderInfo: orderInfo,
        success: (res) => {
          resolve(res);
        },
        fail: (err) => {
          reject(err);
        }
      });
    });
  }

  restoreCompletedTransactions(username) {
    return new Promise((resolve, reject) => {
      this._channel.restoreCompletedTransactions({
        manualFinishTransaction: true,
        username
      }, (res) => {
        resolve(res);
      }, (err) => {
        reject(err);
      })
    });
  }

  finishTransaction(transaction) {
    return new Promise((resolve, reject) => {
      this._channel.finishTransaction(transaction, (res) => {
        resolve(res);
      }, (err) => {
        reject(err);
      });
    });
  }

  getChannels(success, fail) {
    if (this._channel !== null) {
      success(this._channel)
      return
    }

    if (this._channelError !== null) {
      fail(this._channelError)
      return
    }

    uni.getProvider({
      service: 'payment',
      success: (res) => {
        this._channel = res.providers.find((channel) => {
          return (channel.id === 'appleiap')
        })

        if (this._channel) {
          success(this._channel)
        } else {
          this._channelError = {
            errMsg: 'paymentContext:fail iap service not found'
          }
          fail(this._channelError)
        }
      }
    });
  }

  get channel() {
    return this._channel;
  }
}

export {
  Iap,
  IapTransactionState
}

# PayPal Payment Reference

# Stripe Payment Reference

# Google Pay Reference

# WeChat MiniApp payment

// Just as an example, not real parameter information.
uni.requestPayment({
    provider: 'wxpay',
	timeStamp: String(Date.now()),
	nonceStr: 'A1B2C3D4E5',
	package: 'prepay_id=wx20180101abcdefg',
	signType: 'MD5',
	paySign: '',
	success: function (res) {
		console.log('success:' + JSON.stringify(res));
	},
	fail: function (err) {
		console.log('fail:' + JSON.stringify(err));
	}
});

# uniCloud开发

  • 前端:使用 uni-pay 组件发起支付。
  • 服务端:使用uniPay,该服务对应的演示工程在插件市场:https://ext.dcloud.net.cn/plugin?id=1835,此示例为完整的前后端支付演示,使用uniPay可极快的完成支付业务开发。

# php development

  • Front-end: Use uni.request to request the server interface, get the order data, use uni.requestPayment to initiate a payment request to the payment platform, and pull up the client of the payment platform to pay. Detailed code in hello uni-app.
  • Server: PHP can refer to https://github.com/dcloudio/H5P.Server/tree/master/payment.

# FAQ

  • Q: How to use aggregate payment such as ping++ A: The js API of uni-app has been unified across terminals, and the client does not need to use three-party aggregation payment. If the server chooses uniCloud, there is no need for three-party aggregation payment. If the server is developed using traditional servers such as php and java, you can use three-party aggregation payment on the server.

  • Q: How to use other payments on the App, such as UnionPay and PayPal. A: App 3.4+ already supports PayPal, the previous version of App 3.4 uses the following scheme

    1. You can use their wap version to pay in the web-view component
    2. Native sdk can be integrated, available in the plug-in market, see details. You can also develop native plug-ins by yourself. For development documents, see https://ask.dcloud.net.cn/article/35428
  • Q: Appstore audit reports that PGPay SDK is not allowed to be listed A: For digital products (such as purchasing members and other products that do not require physical delivery), Apple stipulates that Apple IAP in-app payment must be used, and Apple will be divided into 30%. When packing, do not check other payment methods such as WeChat or Alipay. If the package you submit contains sdk for payment such as WeChat, Alipay, etc., even if you do not use it, the Appstore will think that you have a hidden way, and will bypass the IAP in the future and will not give Apple a share, so it will refuse your App to go online. When the cloud is packaged, the payment module is selected in the manifest, but WeChat payment and Alipay payment are removed from the sdk configuration. Many developers' Android versions include WeChat and Alipay payments, so pay attention to separate judgments at this time. For details, see https://ask.dcloud.net.cn/article/36447