




POST /v3/pay/transactions/jsapi\\-H"Authorization: ******* "\\-H"Content-Type:application/json"\\-d'{"appid": "wxd678efh567hg6787","description": "image Shop - Shenzhen Tengda - qq doll","out_trade_no": "1217752501201407033233368018","time_expire": "2018-06-08T10:34:56+08:00","attach": "custom args","notify_url","https://xxx.xxx.xxx/payBackx","amount": {"total": 100,"currency": "USD"},"payer": {"openid": "XXXXXXXX"},"detail": {"cost_price": 608800,"goods_detail": [{"merchant_goods_id": "1246464644","wechatpay_goods_id": "1001","goods_name": "iPhoneX 256G","quantity": 1,"unit_price": 528800}]}}'
{"prepay_id": "pid_xsxssx12w3123fefe"}
timeStamp, nonceStr, package, signType, paySignField | Type | Description |
timestamp | String | Time (in seconds) |
nonceStr | String | Random string with a length of 10 characters |
package | String | Fixed format: prepay_id=${prepay_id} |
signType | String | Fixed type: RSA |
paySign | String | Calculated using the mini program ID, timeStamp, nonceStr, prepayId, and privateKey. Refer to the algorithm below. |
// how to create paySignconst generatePaySign = function (appId, timestamp, nonceStr, prepayId, privateKey) {const string2sign = `${appId}\\n${timestamp}\\n${nonceStr}\\n${prepayId}\\n`;const sign = crypto.createSign('RSA-SHA256');sign.update(string2sign);const sBytes = sign.sign(privateKey, 'base64');const paySign = Buffer.from(sBytes, 'base64').toString('base64');return paySign;}
const response = {"timeStamp": "XXXXXX","nonceStr": "XXXXXXXX","package": "prepay_id=askdlfkadlsfkalsdjflakjsdf","signType": "RSA","paySign": "XXXXX",}
wx.requestPayment({timeStamp,nonceStr,package,signType:"RSA",paySign,success:function(res){// Pay success},fail:function(err){// cancel or pay has error}});
POST /notify_callbackContent-Type: application/json; charset=utf-8Content-Length: 52Connection: keep-aliveKeep-Alive: timeout=8Cache-Control: no-cache, must-revalidateX-Content-Type-Options: nosniffRequest-ID: 08F5B8C2B506102C18FDDFEEA30620BE821E28EDC405-0Content-Language: zh-CNWechatpay-Nonce: d824f2e086d3c1df967785d13fcd22efWechatpay-Signature: mfI1CPqvBrgcXfgXMFjdNIhBf27ACE2YyeWsWV9ZI7T7RU0vHvbQpu9Z32ogzc+k8ZC5n3kz7h70eWKjgqNdKQF0eRp8mVKlmfzMLBVHbssB9jEZEDXThOX1XFqX7s7ymia1hoHQxQagPGzkdWxtlZPZ4ZPvr1RiqkgAu6Is8MZgXXrRoBKqjmSdrP1N7uxzJ/cjfSiis9FiLjuADoqmQ1P7p2N876YPAol7Rn0+GswwAwxldbdLrmVSjfytfSBJFqTMHn4itojgxSWWN1byuckQt8hSTEv/Lg97QoeGniYP17T80pJeQyL3b+295FPHSO2AtvCgyIbKMZ0BALilAA==Wechatpay-Timestamp: 1722850421Wechatpay-Serial: PUB_KEY_ID_0000000000000024101100397200000006Wechatpay-Signature-Type: WECHATPAY2-SHA256-RSA2048{"id": "EV-2018022511223320873","create_time": "2015-05-20T13:29:35+08:00","resource_type": "encrypt-resource","event_type": "TRANSACTION.SUCCESS","summary": "pay success","resource": {"original_type": "transaction","algorithm": "AEAD_AES_256_GCM","ciphertext": "*************","associated_data": "","nonce": ""}}
Response timestamp\\nResponse random string\\nResponse body\\n1722850421\\n2d824f2e086d3c1df967785d13fcd22ef\\nbodyContent\\n
$ cat pay_pub.pem2-----BEGIN PUBLIC KEY-----3MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4zej1cqugGQtVSY2Ah8RMCKcr2UpZ8Npo+5Ja9xpFPYkWHaF1Gjrn3d5kcwAFuHHcfdc3yxDYx6+9grvJnCA2zQzWjzVRa3BJ5LTMj6yqvhEmtvjO9D1xbFTA2m3kyjxlaIar/RYHZSslT4VmjIatW9KJCDKkwpM6x/RIWL8wwfFwgz2q3Zcrff1y72nB8p8P12ndH7GSLoY6d2Tv0OB2+We2Kyy2+QzfGXOmLp7UK/pFQjJjzhSf9jxaWJXYKIBxpGlddbRZj9PqvFPTiep8rvfKGNZF9Q6QaMYTpTp/uKQ3YvpDlyeQlYe4rRFauH3mOE6j56QlYQWivknDX9VrwIDAQAB4-----END PUBLIC KEY-----
$openssl base64 -d -A <<< \\ 'CtcbzwtQjN8rnOXItEBJ5aQFSnIXESeV28Pr2YEmf9wsDQ8Nx25ytW6FXBCAFdrr0mgqngX3AD9gNzjnNHzSGTPBSsaEkIfhPF4b8YRRTpny88tNLyprXA0GU5ID3DkZHpjFkX1hAp/D0fva2GKjGRLtvYbtUk/OLYqFuzbjt3yOBzJSKQqJsvbXILffgAmX4pKql+Ln+6UPvSCeKwznvtPaEx+9nMBmKu7Wpbqm/+2ksc0XwjD+xlvlECkCxfD/OJ4gN3IurE0fpjxIkvHDiinQmk51BI7zQD8k1znU7r/spPqB+vZjc5ep6DC5wZUpFu5vJ8MoNKjCu8wnzyCFdA==' > signature.txt
$ openssl dgst -sha256 -verify pay_pub.pem -signature signature.txt << EOF1554209980c5ac7061fccab6bf3e254dcf98995b8c{"data":[{"serial_no":"5157F09EFDC096DE15EBE81A47057A7232F1B8E1","effective_time":"2018-03-26T11:39:50+08:00","expire_time":"2023-03-25T11:39:50+08:00","encrypt_certificate":{"algorithm":"AEAD_AES_256_GCM","nonce":"d215b0511e9c","associated_data":"certificate","ciphertext":"..."}}]}EOF
from cryptography.hazmat.primitives.ciphers.aead import AESGCMimport base64def decrypt(nonce, ciphertext, associated_data):key = "Your32Apiv3Key"key_bytes = str.encode(key)nonce_bytes = str.encode(nonce)ad_bytes = str.encode(associated_data)data = base64.b64decode(ciphertext)aesgcm = AESGCM(key_bytes)return aesgcm.decrypt(nonce_bytes, data, ad_bytes)
{code : 200}
- (void)requestPayment:(TMFMiniAppInfo *)app params:(NSDictionary *)params completionHandler:(MACommonCallback)completionHandler {[TUITool makeToast:@"Prepare to pay..."];// Request the App backend based on the params parameters passed in by the mini program[[TCMPPDemoPayManager sharedInstance] checkPreOrder:params completionHandler:^(NSError * _Nullable err, PayResponseData * _Nullable result) {[TUITool hideToastActivity];if (!err) {// The request succeeded,and the payment native page pops updispatch_async(dispatch_get_main_queue(), ^{TCMPPPaymentMethodsController *payMethodVC = [[TCMPPPaymentMethodsController alloc]init];payMethodVC.payResponseData = result;payMethodVC.app = app;[[[TCMPPShareMiniAppModule sharedInstance] topViewController].navigationController pushViewController:payMethodVC animated:NO];payMethodVC.completeHandle = ^(NSDictionary * _Nullable result, NSError * _Nullable error) {// Complete payment and call back to the mini programcompletionHandler(result,error);};});} else {// The request failed, payment was not completed, and the callback was sent to the mini programNSDictionary *retDic = @{@"retmsg":err.localizedDescription};if (result.returnCode && result.returnMessage) {retDic = @{@"returnCode":result.returnCode,@"returnMessage":result.returnMessage};}completionHandler(retDic,err);}}];}
@ProxyService(proxy = MiniOpenApiProxy.class)public class MiniOpenApiProxyV2Impl extends MiniOpenApiProxy {private static final String TAG = "MiniOpenApiProxy";@Overridepublic void requestPayment(IMiniAppContext miniAppContext, JSONObject params, AsyncResult result) {PaymentManagerV2.g().startPayment(miniAppContext, params, result);}}public class PaymentManagerV2 {private static final String TAG = "PaymentManager";private static PaymentManagerV2 instance;private final PayApiV2 payApi = new PayApiV2();private PaymentRequest paymentRequest;public static PaymentManagerV2 g() {if (instance == null) {instance = new PaymentManagerV2();}return instance;}public void startPayment(IMiniAppContext miniAppContext, JSONObject params, AsyncResult result) {// do params checkif (params.has("prepayId")) {checkOrder(miniAppContext, params, result);} else {JSONObject failRet = new JSONObject();try {failRet.put("success", false);} catch (JSONException e) {}result.onReceiveResult(false, failRet);}}/*** STEP 1: check order status** @param miniAppContext* @param params* @param result*/private void checkOrder(IMiniAppContext miniAppContext, JSONObject params, AsyncResult result) {String appId = miniAppContext.getMiniAppInfo().appId;Activity activity = miniAppContext.getAttachedActivity();payApi.checkOrder(appId, params, new PayApiV2.PayCallBack() {@Overridepublic void onSuccess(JSONObject checkRet) {String fee = checkRet.optString("actualAmount");double paymentValue = Double.parseDouble(fee) / 10000;showPayTypeList(activity, paymentValue, checkRet.toString());paymentRequest = new PaymentRequest(miniAppContext, checkRet, result, paymentValue);Log.e("TAG", "payment request " + this.hashCode());}@Overridepublic void onFailed(String errCode, String msg) {Log.e(TAG, "pay failed " + msg);activity.runOnUiThread(new Runnable() {@Overridepublic void run() {Toast.makeText(miniAppContext.getContext(), "failed", Toast.LENGTH_SHORT).show();}});result.onReceiveResult(false, new JSONObject());}});}/*** STEP 2: show pwd dialog** @param activity* @param money*/private void showPwdDialog(Activity activity, double money, ICustomPayCallback payCallback, int iconSrc,String desc) {CustomPayDemo.CustomPayDialog customPayDialog = new CustomPayDemo.CustomPayDialog(activity, money,R.style.MyAlertDialog, iconSrc, desc);customPayDialog.addPayResultListen(payCallback);customPayDialog.show();}/*** STEP 3: confirm pwd input and check pwd** @param activity* @param pwd* @param data* @param result*/private void checkPwdAndPay(Activity activity, String pwd, JSONObject data, AsyncResult result, String payModel,String payModelId) {if (checkPassWord(pwd)) {requestPayment(activity, data, result, payModel, payModelId);} else {JSONObject ret = new JSONObject();try {ret.put("errMsg", "bad pwd ");} catch (JSONException e) {}result.onReceiveResult(false, ret);activity.finish();}}private boolean checkPassWord(String pwd) {return "666666".equals(pwd);}/*** STEP 4: request payment** @param activity* @param data* @param asyncResult*/private void requestPayment(Activity activity, JSONObject data, AsyncResult asyncResult, String payModel, String paymdelId) {payApi.payOrder(data, new PayApiV2.PayCallBack() {@Overridepublic void onSuccess(JSONObject result) {weiString totalFee = result.optString("paymentAmount");showPayResult(true, activity, totalFee);JSONObject resultToJs = result.optJSONObject("data");asyncResult.onReceiveResult(true, resultToJs);}@Overridepublic void onFailed(String errCode, String msg) {JSONObject ret = new JSONObject();try {ret.put("errMsg", msg);ret.put("errCode", errCode);} catch (JSONException e) {}asyncResult.onReceiveResult(false, ret);activity.finish();}}, payModel, paymdelId);}private void showPayResult(boolean success, Activity activity, String total) {Intent intent = new Intent(activity, PaymentResultActivity.class);intent.putExtra("success", success);intent.putExtra("total", total);intent.putExtra("isV2", true);activity.startActivity(intent);activity.finish();}private void showPayTypeList(Activity activity, double total, String rawData) {Intent intent = new Intent(activity, PaymentMethodActivity.class);intent.putExtra("totalFee", total);intent.putExtra("rawData", rawData);activity.startActivity(intent);}public void showPwdConfirm(Activity activity, int iconSrc, String desc, String model, String modelId) {if (null != paymentRequest) {AsyncResult result = paymentRequest.result;JSONObject checkRet = paymentRequest.params;try {checkRet.put("appId", paymentRequest.miniAppContext.getMiniAppInfo().appId);} catch (JSONException | NullPointerException e) {}showPwdDialog(activity, paymentRequest.payValue, (retCode, msg, dialogInterface) -> {if (retCode == 1) {String pwd = ((CustomPayDemo.CustomPayDialog) dialogInterface).getInputText();Log.e(TAG, "onDismiss isComplete=" + pwd);if (!TextUtils.isEmpty(pwd)) {checkPwdAndPay(activity, pwd, checkRet, result, model, modelId);} else {Log.e(TAG, "empty pwd ~");JSONObject ret = new JSONObject();try {ret.put("errMsg", "empty pws");} catch (JSONException e) {}result.onReceiveResult(false, ret);activity.finish();}paymentRequest = null;}}, iconSrc, desc);}}public void notifyPaymentCancel() {if (null != paymentRequest) {JSONObject ret = new JSONObject();try {ret.put("errMsg", "cancel");} catch (JSONException e) {}paymentRequest.result.onReceiveResult(false, ret);paymentRequest = null;}}private static class PaymentRequest {public IMiniAppContext miniAppContext;public JSONObject params;public AsyncResult result;public double payValue = 0f;public PaymentRequest(IMiniAppContext miniAppContext, JSONObject params, AsyncResult result, double payValue) {this.miniAppContext = miniAppContext;this.params = params;this.result = result;this.payValue = payValue;}}}

Feedback