Skip to main content
版本: 2.0.x

请求与响应

在使用 PTS 的请求和响应时,有一些基本规则。在开始实施之前务必确认这些规则。

  1. 所有请求和数据都使用 UTF-8 格式。
  2. 交易请求基于 HTTPS 协议,仅支持 POST 表单。
  3. 所有参数和参与签名的数据必须按 ASCII 排序。空值仍需包含在签名中。
  4. 所有请求都有指定的标头。请遵循请求标头的设置。
  5. 请向我们的客户服务团队索要 API 主机 URL。
  6. 请告诉我们您的 Host IP,以便我们将您的 IP 添加到白名单中。

请求格式

请按照以下指南构建您的请求:

  1. 准备请求数据并生成签名。
  2. 将请求正文转换为 JSON 字符串。
  3. 使用您的商户安全码通过 AES-ECB-PKCS7 加密请求 JSON 字符串。
  4. 通过 base64_encode 编码您的加密字符串,获取最终的请求字符串。
  5. HTTPS 请求的 Content-Type 应为 text/plain

准备您的请求数据并生成签名

{
"order_id": "20210514183849",
"amount": "40000",
"currency": "CNY",
"timestamp": "1612245402",
"callback_url": "http://my.service/callback",
"redirect_url": "https://my.service/redirect",
"channel": "alipay",
"bank_code": "",
"remark": "test",
"user_id": "1",
"sign": "lOp6SoczkquxzYTDufsVTIjjTdKuCGZnGEa7…."
}

// 将请求正文转换为 JSON 字符串
{"order_id":"20210514184046","amount":"40000","currency":"CNY","timestamp":"1612245402","callback_url":"http://my.service/callback","redirect_url":"https://my.service/redirect","channel":"alipay","bank_code":"","remark":"test","user_id":"1","sign":"lOp6SoczkquxzYTDufsVTIjjTdKuCGZnGEa7..."}

// 使用商户安全码通过 AES-ECB-PKCS7 加密 JSON 字符串,并通过 base64_encode 编码您的加密字符串
wbTkX4OdkK8xqvrnqqKalTp/XiC+svRLvgu6UGQ5gDPx9iTRSS3ng8cRkLwfrxnN3Ba4YZAtMtb2PahMj0KNz56ovbuctKsMWMjztpIn2eLCHWNzVHRrU8eJ/aG0OgDztdceON2xBGYEtzpyf1Lc9jycfnd35tANhZgWFlNvCPrTNsbTjrVA3fH1gOKzn35CfHsuyWertBQjp/FqMkDWa7G1gRxXa2L1s...

// 现在,您可以通过 HTTPS POST 发送请求,Content-Type 应为 text/plain

// 或者,您可以通过HTTPS POST 发送请求,Content-Type 应为 application/json,並使用data参数。
{
"data": "wbTkX4OdkK8xqvrnqqKalTp/XiC+svRLvgu6UGQ5gDPx9iTRSS3ng8cRkLwfrxnN3Ba4YZAtMtb2PahMj0KNz56ovbuctKsMWMjztpIn2eLCHWNzVHRrU8eJ/aG0OgDztdceON2xBGYEtzpyf1Lc9jycfnd35tANhZgWFlNvCPrTNsbTjrVA3fH1gOKzn35CfHsuyWertBQjp/FqMkDWa7G1gRxXa2L1s..."
}

请求示例代码

import base64
import json
import hashlib
import random
import time
import calendar
import requests

from aes import AESCrypt
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import serialization

user_id = '' # '1'
url = '' # 'http://service.local.test'
safecode = '' # '164ddce3d0b13d21fbc4cd02e14d9f98'

def send_request(url_path, params, sign_type):
token = ''
# Get Before Sign string
serialize_sign_string = serialize_sign(params, safecode, sign_type)
print('serialize sign string:::' + serialize_sign_string)
# Assign sign to params

#
sign = generate_signature(serialize_sign_string)
print('sign base64 encode string:::' + sign)
params['sign'] = sign

json_string = json.dumps(params, indent=4, ensure_ascii=False)
# AES encrypt
aes = AESCrypt(safecode)
aes_string = aes.encrypt(json_string).decode('utf-8')
print('AES string::' + aes_string)
# Request

try:
headers = {'content-type': 'text/plain', 'Authorization': token}
response = requests.post(url=(url + url_path), data=aes_string, headers=headers)
dict_obj = json.loads(response.text)
print('response result::' + response.text)
if dict_obj.get('code') != 1000:
raise Exception(dict_obj.get('message'))
except Exception as e:
# Get token
token = get_token()
headers = {'content-type': 'text/plain', 'Authorization': token}
response = requests.post(url=(url + url_path), data=aes_string, headers=headers)
dict_obj = json.loads(response.text)
print('response result::' + response.text)

if response.status_code == 200:
return response.text
else:
return None

post_params = {
'user_id': user_id,
'order_id': f'TEST{user_id}{calendar.timegm(time.gmtime())}',
'amount': random.randint(10, 1000),
'currency': 'PHP',
'channel': 'QRPH',
'callback_url': 'http://my.service/callback',
'redirect_url': 'https://my.service/redirect',
'timestamp': calendar.timegm(time.gmtime()),
'email': '[email protected]',
'remark': 'test'
}

send_request('/merchant/payment', post_params, 'payment')

# aes.py
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64

class AESCrypt:
def __init__(self, key):
self.key = key.encode('utf-8')
self.block_size = 16 # AES block size is 16 bytes

def encrypt(self, data):
cipher = AES.new(self.key, AES.MODE_ECB)
padded_data = pad(data.encode('utf-8'), self.block_size)
ciphertext = cipher.encrypt(padded_data)
return base64.b64encode(ciphertext)

def decrypt(self, encrypted_data):
encrypted_data = base64.b64decode(encrypted_data)
cipher = AES.new(self.key, AES.MODE_ECB)
decrypted_data = unpad(cipher.decrypt(encrypted_data), self.block_size)
return decrypted_data.decode('utf-8')

响应格式

来自 PTS 的响应和回调将遵循以下格式。

Note

✅ 必填 ⭕ 可選 ❌ 不適用

标头内容
Content-Typeapplication/json
参数类型必填说明
code字符串成功返回 1000,其他为 错误代码
message字符串结果描述
data对象当 code 为 1000 时提供
// Example
{
"code": "1000",
"message": "Accepted",
"data": {
// 仅在 code=1000 时可用
}
}