Skip to content

快速开始

前置条件

  • [ ] 商户号(merchant_no)
  • [ ] RSA 私钥
  • [ ] 平台公钥

环境

环境地址
测试https://sandbox-api.meepay.org
生产https://api.meepay.org

注意

开发阶段使用测试环境,测试完成后再切换生产环境。

支付请求示例

1. 构建认证和业务参数

javascript
// 认证参数(用于生成签名)
const authParams = {
  service_id: 'SVC1234567890',            // 服务商号
  timestamp: String(Math.floor(Date.now() / 1000)), // 时间戳
  nonce_str: generateNonceStr()           // 随机字符串
};

// 业务参数
const payParams = {
  merchant_no: '1234567890',              // 商户号
  out_trade_no: 'ORDER' + Date.now(),     // 商户订单号(唯一)
  total_amount: 100,                      // 金额:100 分 = 1 元
  subject: '测试商品',                     // 订单标题
  pay_method: 'wechat',                   // 支付方式:wechat 或 alipay
  sub_openid: 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o', // 微信 sub_openid
  notify_url: 'https://your-domain.meepay.org/api/notify' // 异步通知地址
};

// 生成随机字符串
function generateNonceStr() {
  return Math.random().toString(36).substring(2, 15);
}

2. 生成签名

javascript
const crypto = require('crypto');
const fs = require('fs');

// 读取私钥
const privateKey = fs.readFileSync('private_key.pem', 'utf8');

// 生成签名(仅针对认证参数)
function sign(authParams, privateKey) {
  // 1. 参数排序
  const sortedKeys = Object.keys(authParams)
    .filter(key => key !== 'sign' && authParams[key] !== null && authParams[key] !== undefined)
    .sort();
  
  // 2. 拼接字符串
  const signString = sortedKeys
    .map(key => `${key}=${authParams[key]}`)
    .join('&');
  
  console.log('待签名字符串:', signString);
  
  // 3. 生成签名
  const sign = crypto
    .createSign('RSA-SHA256')
    .update(signString)
    .sign(privateKey, 'base64');
  
  return sign;
}

const signValue = sign(authParams, privateKey);
const authorization = `RSA service_id=${authParams.service_id},timestamp=${authParams.timestamp},nonce_str=${authParams.nonce_str},sign=${signValue}`;

3. 发送请求

javascript
const https = require('https');

async function createPayOrder(authHeader, params) {
  const options = {
    hostname: 'sandbox-api.meepay.org',
    path: '/v1/pay/jsapi',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Authorization': authHeader
    }
  };
  
  return new Promise((resolve, reject) => {
    const req = https.request(options, (res) => {
      let data = '';
      res.on('data', (chunk) => { data += chunk; });
      res.on('end', () => {
        resolve(JSON.parse(data));
      });
    });
    
    req.on('error', reject);
    req.write(JSON.stringify(params));
    req.end();
  });
}

// 发起支付请求
const result = await createPayOrder(authorization, payParams);
console.log('请求结果:', result);

4. 处理响应

javascript
if (result.code === '00000') {
  console.log('支付订单创建成功');
  console.log('商户单号:', result.data.pay_trade_no);
  console.log('支付参数:', result.data.pay_params);
  
  // 将支付参数返回给前端,由前端调起支付
  return {
    success: true,
    payParams: result.data.pay_params
  };
} else {
  console.error('支付订单创建失败:', result.msg);
  return {
    success: false,
    message: result.msg
  };
}

5. 前端调起支付

微信支付(H5)

javascript
// 前端接收到 payParams 后
function invokeWechatPay(payParams) {
  if (typeof WeixinJSBridge === 'undefined') {
    alert('请使用微信浏览器打开');
    return;
  }
  
  WeixinJSBridge.invoke('getBrandWCPayRequest', {
    appId: payParams.appId,
    timeStamp: payParams.timeStamp,
    nonceStr: payParams.nonceStr,
    package: payParams.package,
    signType: payParams.signType,
    paySign: payParams.paySign
  }, function(res) {
    if (res.err_msg === 'get_brand_wcpay_request:ok') {
      // 支付成功
      alert('支付成功');
      window.location.href = '/pay/success';
    } else {
      // 支付失败或取消
      alert('支付失败');
    }
  });
}

微信小程序支付

javascript
wx.requestPayment({
  timeStamp: payParams.timeStamp,
  nonceStr: payParams.nonceStr,
  package: payParams.package,
  signType: payParams.signType,
  paySign: payParams.paySign,
  success: function(res) {
    // 支付成功
    wx.showToast({ title: '支付成功' });
  },
  fail: function(err) {
    // 支付失败
    wx.showToast({ title: '支付失败', icon: 'error' });
  }
});

支付宝支付(H5)

javascript
// 支付宝 H5 支付需要跳转到支付宝支付页面
function invokeAlipay(payUrl) {
  // 方式1: 直接跳转到支付宝支付页面
  window.location.href = payUrl;
  
  // 方式2: 在新窗口打开(适用于PC端)
  window.open(payUrl, '_blank');
}

// 如果返回的是支付宝表单,需要提交表单
function submitAlipayForm(formHtml) {
  const div = document.createElement('div');
  div.innerHTML = formHtml;
  document.body.appendChild(div);
  
  const form = div.querySelector('form');
  if (form) {
    form.submit();
  }
}

支付宝小程序支付

javascript
my.tradePay({
  tradeNO: transactionId, // 从后端获取的支付宝交易号
  success: function(res) {
    if (res.resultCode === '9000') {
      // 支付成功
      my.showToast({ content: '支付成功' });
    } else {
      // 支付失败
      my.showToast({ content: '支付失败: ' + res.resultMessage });
    }
  },
  fail: function(err) {
    my.showToast({ content: '支付失败' });
  }
});

完整示例

javascript
const crypto = require('crypto');
const fs = require('fs');
const https = require('https');

class MifPayClient {
  constructor(config) {
    this.serviceId = config.serviceId;
    this.privateKey = fs.readFileSync(config.privateKeyPath, 'utf8');
    this.baseUrl = config.sandbox ? 
      'https://sandbox-api.meepay.org' :
      'https://api.meepay.org';
  }
  
  buildAuthorization() {
    const authParams = {
      service_id: this.serviceId,
      timestamp: String(Math.floor(Date.now() / 1000)),
      nonce_str: crypto.randomBytes(16).toString('hex')
    };
    
    const sign = this.sign(authParams);
    return `RSA service_id=${authParams.service_id},timestamp=${authParams.timestamp},nonce_str=${authParams.nonce_str},sign=${sign}`;
  }
  
  sign(params) {
    const sortedKeys = Object.keys(params)
      .filter(key => key !== 'sign' && params[key] !== null && params[key] !== undefined)
      .sort();
    
    const signString = sortedKeys
      .map(key => `${key}=${params[key]}`)
      .join('&');
    
    return crypto
      .createSign('RSA-SHA256')
      .update(signString)
      .sign(this.privateKey, 'base64');
  }
  
  async createPayOrder(params) {
    const authorization = this.buildAuthorization();
    
    const requestParams = {
      merchant_no: params.merchantNo,
      out_trade_no: params.outTradeNo,
      total_amount: params.totalAmount,
      subject: params.subject,
      pay_method: params.payMethod,
      sub_openid: params.subOpenid,
      notify_url: params.notifyUrl
    };
    
    return this.request('/v1/pay/jsapi', requestParams, authorization);
  }
  
  async request(path, params, authorization) {
    const url = new URL(path, this.baseUrl);
    const options = {
      hostname: url.hostname,
      path: url.pathname,
      method: 'POST',
      headers: { 
        'Content-Type': 'application/json',
        'Authorization': authorization
      }
    };
    
    return new Promise((resolve, reject) => {
      const req = https.request(options, (res) => {
        let data = '';
        res.on('data', chunk => { data += chunk; });
        res.on('end', () => resolve(JSON.parse(data)));
      });
      req.on('error', reject);
      req.write(JSON.stringify(params));
      req.end();
    });
  }
}

// 使用
const client = new MifPayClient({
  serviceId: 'SVC1234567890',
  privateKeyPath: './private_key.pem',
  sandbox: true
});

const result = await client.createPayOrder({
  merchantNo: '1234567890',
  outTradeNo: 'ORDER' + Date.now(),
  totalAmount: 100,
  subject: '测试商品',
  payMethod: 'wechat',
  subOpenid: 'oUpF8uMuAJO_M2pxb1Q9zNjWeS6o',
  notifyUrl: 'https://your-domain.meepay.org/api/notify'
});

异步通知

javascript
app.post('/api/notify', (req, res) => {
  const notifyData = req.body;
  
  // 1. 验证签名
  if (!verifySign(notifyData, platformPublicKey)) {
    res.send('failure');
    return;
  }
  
  // 2. 处理业务
  if (notifyData.status === 'SUCCESS') {
    updateOrderStatus(notifyData.out_trade_no, 'PAID');
  }
  
  // 3. 返回成功
  res.send('success');
});

切换生产

javascript
const client = new MifPayClient({
  serviceId: 'YOUR_PROD_SERVICE_ID',
  merchantNo: 'YOUR_PROD_MERCHANT_NO',
  privateKeyPath: './prod_private_key.pem',
  sandbox: false
});

更多

米付科技版权所有,保留所有权利