介绍

PAYJT是由广州市雪梨网络科技有限公司开发的支付宝及微信收款平台。为个人 / 独立开发者 提供安全、简单、稳定、正规的收款服务。

目前支持微信 JSAPI / 收银台 / 支付宝当面付 等支付方式。微信资金由官方 D+1 结算自动下发个人银行卡,支付宝为即时到账,到签约支付宝余额。

收款原理

PAYJT是微信支付服务商、支付宝技术服务商,因此我们采用的收款方式完全合规合法,资金由支付宝和微信官方结算,安全可靠。

常见问题

不用安装 APP,不需要手机监控,不用上传二维码

钱款直接到你的账户,不经过 PayJT 中转

微信 T+1 ,支付宝即时到账

支付的时候,微信支付名字可以自定义,支付宝显示自己的名字

审核时间多久?微信几分钟,支付宝几个小时

微信什么时候打电话?微信里面会有通知,一般是审核通过后第二天

微信电话漏接怎么办?没事,会再打

打电话会问什么问题?机器人拨打的,测试手机连通性,按1即可

"商户-XXX" 这个可以修改吗?不能,微信自动的

支付宝支付的时候显示什么名称?你签约支付宝的名字

支持个人接入吗?

当然,PAYJT 支持个人、个体户、企业、其他组织接入

个人签约和个体户、公司签约有什么区别?

个人限额,个体户、公司不限额

已经在其它地方签约,还可以在 PAYJT 签约吗?

可以

一个微信号可以开通多少个?

一个身份证、银行卡可以注册多个微信号,一个微信号可以开通一个 PAYJT

申请的微信和支付宝不同同一个人的可以吗?

可以

资金有风险吗?

没有,资金由微信官方 T+1 自动结算到 个人同名 银行卡,支付宝即时到账个人账户余额。安全可靠无风险

什么是小微商户?

小微商户指依据法律法规和相关监管规定免于办理工商注册登记、无营业执照的实体特约商户

PAYJT 怎么收费?

微信/支付宝渠道,官⽅收 0.38% 固定⼿续费,从每笔收款中扣除

PAYJT 平台0.8%手续费,交易成功后从你的 PAYJT 账号余额中扣除,需要预先充值到你的 PAYJT 账号

能否免费开通?

针对医疗、教育、民生、公益等领域,我们尽可能免费提供服务。请咨询客服详细说明情况

微信支付特点?

微信单笔限额 2W, 单日限额 5W

每天早上十点前腾讯会将 0:00 之前的款项下发到绑定的个人银行卡中,打款人显示为:财付通支付有限公司

支持jsapi 和收银台 (微信内置浏览器可直接拉起支付)

支付宝支付特点?

支付宝单笔限额 2W, 单日限额 5W

支付宝为及时到账,到签约个人支付宝账号余额

支持拉起H5(支付宝 app 支付)

API接入

微信收银台(JSAPI)

接口地址:https://payjt.com/api/wxpay/jspayPrepay
调用方法:GET
调用参数:
 - appId, 必填, 在后台应用配置页面查看
 - price, 必填, 订单价格(单位:元)
 - title, 必填, 订单标题
 - userOrderId, 必填, 商户订单号
 - userNameId, 必填, 订单购买用户对应的唯一id(便于后续商户自己对账)
 - callbackUrl, 必填, 支付成功后回调地址。
 - sign, 必填, 数据签名 详见签名算法

 收银台方式是通过JSAPI方式发起的支付,只是简化了开发步骤和流程。适用于微信webview环境,支持相册识别或长按识别或直接扫码支付。

 收银台请求步骤:
 构建请求参数
 使用浏览器携带参数跳转至收银台地址
 服务端接收异步通知

 请求返回:
	收银台模式下,请求直接发起收银台支付。用户支付成功后,后台系统会异步通知

 请求成功无返回。请求失败返回:
	appId错误
	签名错误
	微信未签约
	余额不足
              	

支付宝当面付

接口地址:https://payjt.com/api/alipay/createOrder
调用方法:GET
调用参数:
 - appId, 必填, 在后台应用配置页面查看
 - price, 必填, 订单价格(单位:元)
 - title, 必填, 订单标题
 - userOrderId, 必填, 商户订单号
 - userNameId, 必填, 订单购买用户对应的唯一id(便于后续商户自己对账)
 - callbackUrl, 必填, 支付成功后回调地址。
 - sign, 必填, 数据签名 详见签名算法

 即支付宝当面付。用户扫描商户展示在各种场景的二维码进行支付。付款完成后PayJT通知商户服务器付款结果。

 扫码请求步骤:
 构建请求参数
 POST 参数到请求地址
 根据返回内容展示二维码
 用户支付成功后接收异步通知

 正确返回:
	字段名称			字段类型		必填参数		说明
	code			integer		Y		200
	payId			string		Y		平台的唯一订单号
	userOrderId		string		Y		用户传的订单号
	qrCode			string		Y		可将该参数生成二维码展示出来进行扫码支付

 失败返回:
	字段名称			字段类型		必填参数		说明
	code			integer		Y		500
	data			string		Y		错误原因
								appId错误
								签名错误
								支付宝未签约
								余额不足
              	

支付成功异步通知

接口地址:你传入的 callbackUrl 参数
调用方法:GET
调用参数:
 - payId, 平台订单唯一标示可用于查询订单状态
 - orderType, 支付方式【可选0(微信) ,1(支付宝)】
 - price, 订单价格
 - userOrderId, 订单号(商户唯一订单号)
 - userNameId, 订单购买用户对应的唯一id(便于后续商户自己对账)
 - sign, 必填, 数据签名 详见签名算法

当你收到 Pay 的回调请求后,如果响应 HTTP code 200 那么 PayJT 会认为通知成功,
否则会再次通知 6 次,间隔为 1/2/4/16/64/300 分钟。
              

付款结果查询接口

接口地址:https://payjt.com/api/order/queryByUserOrderId?userOrderId=userOrderId
调用方法:GET

注意:api 里面的 userOrderId 为发起付款接口的 userOrderId

接口返回:
 - {"code": 500,"data":"订单不存在"}, 订单不存在
 - {"code": 200,"data":{"payStatus":0}}, 未支付
 - {"code": 200,"data":{"payStatus":1}}, 已过期
 - {"code": 200,"data":{"payStatus":2}}, 已收款已回调
 - {"code": 200,"data":{"payStatus":3}}, 已收款回调中
 - {"code": 200,"data":{"payStatus":4}}, 已收款回调失败,继续尝试中
 - {"code": 200,"data":{"payStatus":5}}, 已收款回调失败
              

签名算法

签名生成的通用步骤如下:

第一步,设所有发送或者接收到的数据为集合M,将集合M内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串stringA。
第二步,在stringA最后拼接上 &key=密钥 得到stringSignTemp字符串,并对stringSignTemp根据utf-8编码取出byte字符数组,然后进行MD5运算,得到sign值

签名例子(Java)
public static String getSign(Map map, String appKey){
     Collection keyset= map.keySet();
     List keyList= new ArrayList<>(keyset);
     Collections.sort(keyList);
     StringBuilder sb = new StringBuilder();
     for (String key : keyList){
         sb.append(key).append("=").append(map.get(key)).append("&");
     }
     sb.append("key=").append(appKey);
     return DigestUtils.md5DigestAsHex(sb.toString().getBytes("utf-8"));
 }
              

Demo (Java例子,其他语言请参考自行开发)

	/**
	 * 微信收银台
	 * */
	public Map rechangewx(
			Integer userId,
			Float amount,
			Integer type,
			UserPO receiptPayUser,
			String notifyUrl)
			throws WriterException, IOException {
		Map result = new HashMap();
		UserPO userPo = userService.getById(userId);
		// 支付最大允许32个长度,否则返回长度失败
		int maxAllowLength = 32;
		String deviceId = userPo.getEmail();
		if (deviceId.length() > maxAllowLength)
			deviceId = deviceId.substring(0, maxAllowLength);

		String out_trade_no = getOrderid(deviceId);
		String appId = String.valueOf(receiptPayUser.getId());
		String userOrderId = out_trade_no;
		String userNameId = deviceId;
		String title = "pay";
		String price = String.valueOf(amount);
		String callbackUrl = notifyUrl;

		Map map = new HashMap<>();
		map.put("appId", appId);
		map.put("userOrderId", userOrderId);
		map.put("userNameId", userNameId);
		map.put("title", title);
		map.put("price", price);
		map.put("callbackUrl", callbackUrl);
		String sign = getSign(map, receiptPayUser.getAppKey());

		// 收银台模式
		String payUrl = "https://payjt.com/api/wxpay/jspayPrepay";
		payUrl += "?appId=" + appId;
		payUrl += "&userOrderId=" + userOrderId;
		payUrl += "&userNameId=" + userNameId;
		payUrl += "&title=" + title;
		payUrl += "&price=" + price;
		payUrl += "&callbackUrl=" + callbackUrl;
		payUrl += "&sign=" + sign;

		RechangePO rechangePO = new RechangePO();
		rechangePO.setPaysapiId("paywx_" + appId + "_"/** 等有回调再填,这里先留空。 */
		);
		rechangePO.setOrderId(userOrderId);
		rechangePO.setPrice(amount);
		rechangePO.setUserId(userPo.getId());
		rechangePO.setCreateTime(new Date());
		rechangePO.setStatus(0);
		rechangePO.setDescription("充值");
		rechangeService.save(rechangePO);

		result.put("qrCode", "");
		result.put("userOrderId", userOrderId);
		result.put("qrCodeRaw", payUrl);
		result.put("payPrice", price);
		String weixingOrderType = "0";
		result.put("orderType", weixingOrderType);

		return result;
	}

	/**
	 * 支付宝当面付
	 * */
	public Map rechangeAlipay(
			Integer userId,
			Float amount,
			Integer type,
			UserPO receiptPayUser,
			String notifyUrl)
			throws WriterException, IOException {
		Map result = new HashMap();
		UserPO userPo = userService.getById(userId);
		// 支付最大允许32个长度,否则返回长度失败
		int maxAllowLength = 32;
		String deviceId = userPo.getEmail();
		if (deviceId.length() > maxAllowLength)
			deviceId = deviceId.substring(0, maxAllowLength);

		String out_trade_no = getOrderid(deviceId);
		String appId = String.valueOf(receiptPayUser.getId());
		String userOrderId = out_trade_no;
		String userNameId = deviceId;
		String title = "pay";
		String price = String.valueOf(amount);
		String callbackUrl = notifyUrl;

		Map map = new HashMap<>();
		map.put("appId", appId);
		map.put("userOrderId", userOrderId);
		map.put("userNameId", userNameId);
		map.put("title", title);
		map.put("price", price);
		map.put("callbackUrl", callbackUrl);
		String sign = getSign(map, receiptPayUser.getAppKey());
		map.put("sign", sign);

		String payUrl = "https://payjt.com/api/alipay/createOrder";

		String qrCode = "";
		try {
			HttpClientUtil mHttpClientUtil = new HttpClientUtil();
			JSONObject respJson = mHttpClientUtil.doPost(payUrl, map, "utf-8");
			int code = respJson.getIntValue("code");
			final int SUCCESS_CODE = 200;
			if (code != SUCCESS_CODE)
				throw new IllegalArgumentException(respJson.getString("data"));
			qrCode = respJson.getJSONObject("data").getString("qrCode");
		} catch (Exception e) {
			e.printStackTrace();
			throw new IllegalArgumentException(e.getMessage());
		}

		RechangePO rechangePO = new RechangePO();
		rechangePO.setPaysapiId("paywx_" + appId + "_"/** 等有回调再填,这里先留空。 */
		);
		rechangePO.setOrderId(userOrderId);
		rechangePO.setPrice(amount);
		rechangePO.setUserId(userPo.getId());
		rechangePO.setCreateTime(new Date());
		rechangePO.setStatus(0);
		rechangePO.setDescription("充值");
		rechangeService.save(rechangePO);

		result.put("qrCode", "");
		result.put("userOrderId", userOrderId);
		result.put("qrCodeRaw", qrCode);
		result.put("payPrice", price);
		String alipayOrderType = "1";
		result.put("orderType", alipayOrderType);

		return result;
	}

	protected String getOrderid(String deviceId) {
		return MD5Tools.MD5(deviceId + new Date().getTime());
	}

	/**
	 * 签名
	 */
	public static String getSign(Map map, String privateKey) {
		Collection keyset = map.keySet();
		List keyList = new ArrayList<>(keyset);
		Collections.sort(keyList);
		StringBuilder sb = new StringBuilder();
		for (String key : keyList) {
			sb.append(key).append("=").append(String.valueOf(map.get(key))).append("&");
		}
		sb.append("key=").append(privateKey);
		return DigestUtils.md5DigestAsHex(sb.toString().getBytes(“utf-8”));
	}

	/**
	 * 支付成功收款回调
	 * */
	public void sendGload(Integer orderType, BigDecimal price, String userOrderId, String userNameId, String payId,
			String sign) {
		System.out.println(String.format("orderType:%d price: %f userOrderId: %s userNameId: %s payId: %s sign: %s",
				orderType, price.doubleValue(), userOrderId, userNameId, payId, sign));
		System.out.println("回调  ****sendGload");
		//TODU
		//这里验证签名
		try {
			RechangePO rechangePO = rechangeService.findNoPayByOrderId(userOrderId);
			if (rechangePO != null) {
				rechangePO.setPayTime(new Date());
				rechangePO.setGold(new Float(price.floatValue() * 10).intValue());
				System.out.println("1111111111111");
				rechangeService.setSuccessStatus(rechangePO);
				System.out.println("22222222222222");
				userService.addMoney(rechangePO.getUserId(), price);
				System.out.println("33333333333333");
			}
		} catch (Exception e) {
			System.out.println(e);
			System.out.println("5555555555555555555");
		}
	}
}