游戏支付 - 充值接口文档 SDK示例下载
一、初级模式(新手小白):
本文档以雷霆传奇H5为例子,其他游戏也是大同小异。
  • 第一步,下载接口SDK示例

  • 第二步,将下载的接口示例文件解压,放到游戏网站目录下

  • 第三步,用Notepad++、sublime text等编辑工具,参照示例里的使用说明.txt,修改config.php配置文件里的商户ID、商户密钥、算法密钥,数据库等信息,商户ID、商户密钥、算法密钥在【商户中心】 →【基本资料】里获取。

  • 通过以上配置,即可确定游戏分区通知地址,假如你的游戏网站域名是www.123.com,那么通知地址就是: http://www.123.com/pay/notify.php

  • 第四步,创建分组和分区

    分区重要参数:

    参数 是否必填 说明
    分区ID 部分游戏充值需要分区ID(游戏服数据库的ID),因此请正确填写
    分区数据库名 分区(游戏服)的数据库名称
    通知地址 用于通知服务端完成充值业务
  • 第五步,分区配置完成后,先模拟充值,测试配置是否正确,模拟充值成功后,分区充值才真正的实现并对外开放。

  • 对接完成后,将分组充值链接或者分区充值链接,添加到游戏网站的充值位置上即可。

二、高级模式(开发人员):
  • 创建分组和分区,然后获取分区充值链接,这个充值链接可以作为请求提交地址,提交参数参考下表:

    假设分区充值链接为:http://18pay.net/game?id=1,可以使用POST或者GET方式提交Http请求。

    提交参数:

    参数名称 参数含义 是否必填 说明
    account 充值账号 玩家充值账号,可以灵活应用,比如拼接分区ID和角色名(5_随便玩玩)
    money 充值金额 玩家充值金额
    paytype 支付方式 可选,1:支付宝 2:QQ钱包 3:微信支付,不传则默认为1
  • 接口回调通知

    回调通知作用:

    玩家完成付款后,平台会给分区的通知地址发送回调通知,用于完成账号或角色的充值。

    回调通知参数:

    参数名称 变量名 类型 是否加密传输 说明
    商户编号 appid string 明文传输
    参数集合 parameter string 端对端加密传输,非常安全,请参考下文的“端对端加密方式”

    parameter参数包含信息:

    参数名称 变量名 类型 是否加密传输 说明
    商户密钥 appkey string 平台分配的商户凭证,用于验证数据合法性。
    充值账号 account string 原样返回提交的充值账号
    充值金额 money float 实际付款金额
    游戏币别名 alias string 如元宝、钻石等
    充值比例 scale int
    分区ID quid int
    分区名称 quname string
    分区数据库名 database string
    订单编号 ordernumber string
    附加参数 商户自定义 string 原样返回

    附加参数示例:

    						
    //假设在添加分区时,设置的附加参数为:
    &dbhost=127.0.0.1&dbname=actor
    //那么可以直接如下接收:
    if (empty($_POST)) $_POST = $_GET;
    $dbhost= $_POST[dbhost];
    $dbname= $_POST[dbname];
    

    充值成功后返回:

    返回格式 json格式
    如果充值成功则返回 {"code":1,"msg":"充值成功"}
    如果充值失败则返回 {"code":0,"msg":"失败信息"}

    一定要按要求的格式返回,否则会出现通知失败或者重复充值的情况!正确的返回PHP示例:

    
    $arr=array(
     "code" => 1,
     "msg"  => "充值成功"
    );
    echo json_encode($arr, JSON_UNESCAPED_UNICODE);
    exit;
    
三、网关模式(TCP通信):
  • 第一步,下载通用充值网关软件

    点击下载: 通用充值网关
  • 第二步,打开充值网关软件,切换到【设置】菜单,配置相关参数

  • 第三步,创建分区,通信模式选择TCP,并填写正确的服务器IP、网关端口

  • 第四步,分区测试和网关配置都ok后,直接点击启用网关就可以了

 端对端加密方式
  • php
  • java
  • c#

ini_set("error_reporting","E_ALL & ~E_NOTICE");
header('Content-Type:application/json; charset=utf-8');
if (!function_exists('openssl_encrypt')){
	exit('请开启php.ini的openssl扩展');
}
$input="123456";   //要加密的字符串
$deskey='QDHPJKOS';//算法密钥 
$des = new Des();
$encode=$des->encrypt($input,$deskey);
echo "DES加密结果:".$encode;
$decode=$des->decrypt($encode,$deskey);
echo "\r\nDES解密结果:".$decode;

/**
 * DES加解密类
 */
class Des{
   
    /**
     *
     * 加密函数
     * 算法:des
     * 加密模式:ecb
     * 补齐方法:PKCS5
     *
     * @param unknown_type $input
     */
    public function encrypt($input, $key)
    {
		//由于php7.1废弃了mcrypt_* 一系列函数,所以采用openssl版本
		$str = $this->pkcsPadding($input, 8);
		$key = str_pad($key, 8, '0'); //3DES加密将8改为24
		$sign = @openssl_encrypt($str, 'DES-ECB', $key,OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
		//转为base64,可以有效解决乱码等问题
		$sign = base64_encode($sign);
		return $sign;
    }
    
    /**
     * 解密函数
     * 算法:des
     * 加密模式:ecb
     * 补齐方法:PKCS5
     * @param unknown_type $input
     */
    public function decrypt($input, $key)
    {
		//由于php7.1废弃了mcrypt_* 一系列函数 所以采用openssl版本
		$encrypted = base64_decode($input);
		$key = str_pad($key, 8, '0'); //3DES加密将8改为24
		$sign = @openssl_decrypt($encrypted, 'DES-ECB', $key,OPENSSL_RAW_DATA | OPENSSL_NO_PADDING);
		$sign = $this->unPkcsPadding($sign);
		$sign = rtrim($sign);
		return $sign;
    }
	/**
     * 填充
     *
     * @param $text
     * @param $blocksize
     * @return string
     */
    private function pkcsPadding($text, $blocksize)
    {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }
 
     /**
     * 去填充
     * 
     * @param $text
     * @return string
     */
    private function unPkcsPadding($text)
    {
		$pad = ord($text {strlen($text) - 1});
        if ($pad > strlen($text))
            return false;
        if (strspn($text, chr($pad), strlen($text) - $pad) != $pad)
            return false;
        return substr($text, 0, - 1 * $pad);
    }
    
}

package demoSys;

import java.security.SecureRandom;
import java.util.Base64;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;

public class Test {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String input = "123456";
		String deskey = "QDHPJKOS";
		String encode = encrypt(input, deskey);
		System.out.println("DES加密结果:" + encode);
		String decode = decrypt(encode, deskey);
		System.out.println("DES解密结果:" + decode);
	}

	public static String encrypt(String souce, String key) {
		try {
			// DES算法要求有一个可信任的随机数源
			SecureRandom sr = new SecureRandom();
			// 从原始密匙数据创建DESKeySpec对象
			DESKeySpec dks = new DESKeySpec(key.getBytes("UTF-8"));
			// 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey secretkey = keyFactory.generateSecret(dks);
			// Cipher对象实际完成加密操作
			Cipher cipher = Cipher.getInstance("DES");
			// 用密匙初始化Cipher对象
			cipher.init(Cipher.ENCRYPT_MODE, secretkey, sr);
			// 获取数据并加密
			byte encryptedData[] = cipher.doFinal(souce.getBytes("UTF-8"));
			// JDK1.8及以上可直接使用Base64,JDK1.7及以下可以使用BASE64Encoder
			// Android平台可以使用android.util.Base64
			return new String(Base64.getEncoder().encode(encryptedData));
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			return souce;
		}

	}

	public static String decrypt(String souce, String key) {
		try {
			// DES算法要求有一个可信任的随机数源
			SecureRandom sr = new SecureRandom();
			// 从原始密匙数据创建DESKeySpec对象
			DESKeySpec dks = new DESKeySpec(key.getBytes());
			// 创建一个密匙工厂,然后用它把DESKeySpec转换成 一个SecretKey对象
			SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
			SecretKey secretkey = keyFactory.generateSecret(dks);
			// Cipher对象实际完成加密操作
			Cipher cipher = Cipher.getInstance("DES");
			// 用密匙初始化Cipher对象
			cipher.init(Cipher.DECRYPT_MODE, secretkey, sr);
			// 将加密报文用BASE64算法转化为字节数组
			byte[] encryptedData = Base64.getDecoder().decode(souce);
			// 用DES算法解密报文
			byte decryptedData[] = cipher.doFinal(encryptedData);
			return new String(decryptedData, "UTF-8");
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
			return souce;
		}

	}

}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace demo
{
    class Program
    {
        static void Main(string[] args)
        {
            string message = "123456";//要加密的字符串
            string key = "QDHPJKOS";  //算法密钥
            string encode = encrypt(message, key);
            Console.Write("DES加密结果:" + encode);
            string decode = decrypt(encode, key);
            Console.Write("\r\nDES解密结果:" + decode);
            Console.Read();
        }
        /// DES算法,加密
        /// param message  待加密字符串
        /// param key      解密私钥
        /// return         加密后的Base64编码字符串
        public static string encrypt(string message, string key)
        {
            using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
            {
                byte[] inputByteArray = Encoding.UTF8.GetBytes(message);
                des.Key = UTF8Encoding.UTF8.GetBytes(key);
                des.IV = UTF8Encoding.UTF8.GetBytes(key);
                des.Mode = System.Security.Cryptography.CipherMode.ECB;
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                using (CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                    cs.Close();
                }
                string str = Convert.ToBase64String(ms.ToArray());
                ms.Close();
                return str;
            }
        }
        /// DES算法,解密
        /// param message  待解密字符串
        /// param key      解密私钥
        /// return         解密后的字符串
        public static string decrypt(string message, string key)
        {
            byte[] inputByteArray = Convert.FromBase64String(message);
            using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
            {
                des.Key = UTF8Encoding.UTF8.GetBytes(key);
                des.IV = UTF8Encoding.UTF8.GetBytes(key);
                des.Mode = System.Security.Cryptography.CipherMode.ECB;
                System.IO.MemoryStream ms = new System.IO.MemoryStream();
                using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
                {
                    cs.Write(inputByteArray, 0, inputByteArray.Length);
                    cs.FlushFinalBlock();
                    cs.Close();
                }
                string str = Encoding.UTF8.GetString(ms.ToArray());
                ms.Close();
                return str;
            }
        }
    }
}
 SDK接口示例下载
游戏名称 接口介绍 SDK下载
演示例子 最简单的示例,看得懂的同学可以自行写出其他游戏的接口 点击下载
mysql通用 利宝、天易、美廉等自定义游戏网关(mssql不能用,仅限mysql),简单转换下就可以了 点击下载
白日门 白日门角色名充值,无需下线直接到账 点击下载
白娘子 白娘子接口示例 点击下载
雷霆H5 雷霆H5帐号充值,无特殊符号的角色名充值接口示例 点击下载
西游H5 西游H5接口示例 点击下载
悟空传H5 悟空传H5接口示例 点击下载
战神引擎 战神引擎接口示例 点击下载
梦幻古龙 梦幻古龙接口示例 点击下载
龙城天下 龙城天下接口示例 点击下载
神雕侠侣 神雕侠侣接口示例 点击下载
全民奇迹 全民奇迹接口示例 点击下载
剑侠情缘 剑侠情缘接口示例 点击下载
龙途 龙途fly3d引擎接口示例 点击下载
幽冥传奇 幽冥传奇角色名充值,无需下线直接到账 点击下载
我是死神 我是死神接口示例 点击下载
聚合支付 - 接口开发文档 SDK示例下载
支付网关地址:

http://18pay.net/pay.html

提示:安全起见,提交方式推荐使用 POST ,请不要用 GET 方式提交。
接口参数说明:
参数名称 参数含义 是否必填 参与签名 参数说明
appid 商户号 平台分配商户号
payid 唯一标识 可以是用户ID,或者订单编号(必须确保是唯一的)
money 订单金额 订单提交的金额
type 支付方式 1:支付宝 2:QQ钱包 3:微信支付
notify_url 异步通知地址 付款后POST通知,优先级最高,留空为系统设置中的通知地址
return_url 同步通知地址 付款后用户跳转页面
subject 商品名称 商品名称,注意:值为空时不参与签名
param 自定义参数 原封返回 避免特殊字符,注意:值为空时不参与签名
sign 数据MD5签名 将需要构造的参数按首字母排序并拼接成url参数,然后进行md5加密签名
charset 编码 utf-8或gb2312,默认utf-8
签名算法:
  • 第一步

    设所有发送或者接收到的数据为集合,将集合内非空参数值的参数按照参数名从小到大排序(ASCII码字典序),使用 URL 键值对的格式(即key1=value1&key2=value2…)拼接成字符串 str 。

    
    $urlDatas=array(
    	"appid" => $appid,
    	"money" => $money,
    	"payid" => $payid,
    	"type" => $type,
    	"notify_url" => $notify_url,
    	"return_url" => $return_url
    );
    //ksort()对数组按照键名进行升序排序
    ksort($urlDatas);
    //reset()内部指针指向数组中的第一个元素
    reset($urlDatas);
    $str = ASCII($urlDatas);
    function ASCII($urlDatas = array()){
    	$str = '';//初始化
    	foreach ($urlDatas AS $key => $val) { //遍历参数数组
    		if ($val == ''||$key == 'sign') continue; //跳过这些不签名
    		if ($str) $str .= '&'; //第一个字符串签名不加& 其他加&连接起来参数
    		$str .= "$key=$val"; //拼接为url参数形式
    	}		
    	return $str;
    }
    
  • 第二步

    然后在字符串 str 后面拼接上 appkey(平台商户密钥),得到 stringSignTemp 字符串,最后对stringSignTemp 进行 MD5 运算,得到 sign 值

    
    $str="appid=$appid&money=$money&notify_url=$notify_url&payid=$payid&type=$type&return_url=$return_url";
    $stringSignTemp=$str.$appkey;
    $sign=md5($stringSignTemp);
    
支付结果通知:
参数名称 参数含义 参与签名 参数说明
pay_id 唯一标识 提交的的唯一标识,可以是用户ID,或者订单编号
pay_money 订单金额 实际付款金额
pay_no 交易流水号 付款后生成的唯一流水号
pay_time 交易时间 付款的时间戳
pay_type 支付方式 1:支付宝 2:QQ钱包 3:微信支付
param 扩展返回 商户附加数据,原封返回,提交什么就返回什么。注意:值为空时不参与签名
sign 数据签名 验证订单是否为合法

通知返回的参数示例如下:


pay_id=admin&pay_money=100.00&pay_no=20200217200042408995&pay_time=1487597795&pay_type=1&sign=c47f3cba123456b6b24542110a8928af
业务处理返回:
返回类型 返回数据
业务处理完成返回 ok 或者 success
业务处理失败还需要下次继续通知返回 fail

1、业务处理完成返回:ok 或者 success

2、业务处理失败还需要下次继续通知返回:fail

3、注意:一定要验证是否有pay_no参数值,因为只有该值存在,才是付款成功 。

  • notify_url异步通知示例(Thinkphp):

    
    $appkey="平台的商户密钥";
    if (empty($_POST)) $_POST = $_GET; //如果为GET方式访问 
    //ksort()对数组按照键名进行升序排序 
    ksort($_POST); 
    //reset()内部指针指向数组中的第一个元素 
    reset($_POST); 
    $sign = '';//初始化 
    foreach ($_POST AS $key => $val) { //遍历POST参数 
    if ($val == ''||$key == 'sign') continue; //跳过这些不签名 
    if ($sign) $sign .= '&'; //第一个字符串签名不加& 其他加&连接起来参数 
    $sign .= "$key=$val"; //拼接为url参数形式 
    } 
    $pay_id = $_POST['pay_id']; //需要充值的ID 或订单号 或用户名 
    $pay_money = (float)$_POST['pay_money']; //实际付款金额
    $pay_no = $_POST['pay_no']; //交易流水号 
    $pay_time = $_POST['pay_time']; //付款的时间戳 
    $pay_type = (int)$_POST['pay_type']; //支付方式 1:支付宝 2:QQ钱包 3:微信支付 
    $param = isset($_POST['param'])?$_POST['param']:'';//自定义参数 
    if (!$_POST['pay_no'] || md5($sign . $appkey) != $_POST['sign']) { //不合法的数据 
    exit('fail'); //返回失败 继续补单 
    } else { //合法的数据 
    /** 
    * 业务处理在这里写 
    */ 
    exit('success'); //返回成功,业务处理完成,下面不再执行了
     } 
    
  • return_url同步通知示例(Thinkphp):

    
    $appkey="平台的商户密钥";
    if (empty($_POST)) $_POST = $_GET; //如果为GET方式访问 
    //ksort()对数组按照键名进行升序排序 
    ksort($_POST); 
    //reset()内部指针指向数组中的第一个元素 
    reset($_POST); 
    $sign = '';//初始化 
    foreach ($_POST AS $key => $val) { //遍历POST参数 
    if ($val == ''||$key == 'sign') continue; //跳过这些不签名 
    if ($sign) $sign .= '&'; //第一个字符串签名不加& 其他加&连接起来参数 
    $sign .= "$key=$val"; //拼接为url参数形式 
    } 
    $pay_id = $_POST['pay_id']; //需要充值的ID 或订单号 或用户名 
    $pay_money = (float)$_POST['pay_money']; //实际付款金额 
    $pay_no = $_POST['pay_no']; //交易流水号 
    $pay_time = $_POST['pay_time']; //付款的时间戳 
    $pay_type = (int)$_POST['pay_type']; //支付方式 1:支付宝 2:QQ钱包 3:微信支付
    $param = isset($_POST['param'])?$_POST['param']:'';//自定义参数 
    if (!$_POST['pay_no'] || md5($sign . $appkey) != $_POST['sign']) { //不合法的数据 
    $result = '支付失败';
    } else { //合法的数据 
    /** 
    * 业务处理在这里写 
    */ 
    $result = '支付成功'; 
    } 
    $this->assign('pay_id',$pay_id);
    $this->assign('pay_no',$pay_no);
    $this->assign('pay_money',$pay_money);
    $this->assign('pay_type',$pay_type);
    $this->assign('pay_time',date("Y-m-d H:i:s",$pay_time));
    $this->assign('param',$param);
    $this->assign('result',$result);
    return view();
    
 SDK接口示例下载
语言类型 接口介绍 SDK下载
Thinkphp5 Thinkphp5的聚合支付接口示例 点击下载
PHP PHP的聚合支付接口示例 点击下载
ASP ASP的聚合支付接口示例 点击下载
Java Java的聚合支付接口示例 点击下载