概览
ECardPay API基于 HTTPS 协议,接入方应按照说明进行POST请求,请参见 API列表.
所有API的请求体和响应体均采用 JSON
格式 并采用 UTF-8
编码。接入方应在请求头中包含 Content-Type: application/json
.
所有API的请求和响应都包含一些 公共参数 , 分别位于请求头和响应头,详见 公共参数.
所有API的请求和响应都进行了加密和签名, 详见加密机制,签名机制.
公共参数
请求头
名称 | 必填 | 描述 | 备注 | 示例值 |
---|---|---|---|---|
apiKey | Y | Api 调用 Key | 预先配置. | |
service | Y | API名称 | see API列表. | createCard |
version | Y | API版本 | 当前版本 2.0 . | 2.0 |
requestId | Y | 请求流水号 | 每个请求唯一,建议使用UUID . | 64c9183e-1f89-4c32-b2d2-ba79201e4ed4 |
timestamp | Y | 请求时间 | UNIX时间戳(毫秒). | 1577851018000 |
sign | Y | 请求数据签名 | 详见 签名机制. | 7b73bb09b4aab6a7c80 (部分数据) |
响应头
名称 | 描述 | 备注 | 示例值 |
---|---|---|---|
service | API名称 | 请求头原样返回. | createCard |
version | API版本 | 请求头原样返回. | 2.0 |
requestId | 请求流水号 | 请求头原样返回. | 64c9183e-1f89-4c32-b2d2-ba79201e4ed4 |
timestamp | 响应时间 | UNIX时间戳(毫秒). | 1277851018000 |
code | 响应码 | 枚举值,3位数字,详见响应码下拉框. | 200 (非200 表示API调用失败) |
sign | 响应数据签名 | 详见签名机制. | 7b73bb09b4aab6a7c80 (部分数据) |
响应码
Code | Message | 备注 |
---|---|---|
200 | succeed | 成功. |
400 | payload decrypt failed | 无法解密数据. |
405 | unsupported method | 请求方法不支持。(仅支持POST ) |
406 | too many requests | 请求过于频繁. |
407 | verify sign failed | 无法验证签名. |
408 | app api key not find | Api Key不存在. |
409 | request id is null or duplicate | 请求流水号重复. |
417 | the parameter is null or invalid | 请求头必填参数为空. |
500 | system error(not fixed) | 系统错误. |
API列表
名称 | 方法 | 请求头service参数 |
---|---|---|
创建卡 | POST | createCard |
注销卡 | POST | cancelCard |
充值卡 | POST | rechargeCard |
查询卡 | POST | queryCardDetail |
更新卡 | POST | changeCard |
可用卡段 | POST | cardBins |
卡交易 | POST | cardTransactions |
账户余额查询 | POST | queryAccountBalance |
加密机制
为保证数据的安全性,ECardPay会对每个请求和响应进行加密。
接入方与ECardPay需使用对称加密算法AES/ECB/PKCS5Padding
,对请求体和响应体进行加密与解密,结果采用Base64
编码。
请求体
原始请求体
各字段含义详见下方各API说明。
接入方: 对原始请求体
先使用AES
密钥加密,再进行Base64
编码。结果作为实际请求体
中payload
字段的值。发送实际请求体
。
ECardPay: 对收到的实际请求体
的payload
字段的值先进行Base64
解码,再使用AES
密钥解密。结果即为原始请求体
。
原始请求体
{
"key_1": "value_1",
"key_2": "value_2",
"key_3": "value_3"
}
实际请求体
{
"payload": "ewogICJrZXlfMSI6ICJ2YWx1ZV8xIiwKICAia2V5XzIiOiAidmFsdWVfMiIsCiAgImtleV8zIjogInZhbHVlXzMiCn0="
}
响应体
原始响应体
各字段含义详见下方各API说明。
ECardPay: 对原始响应体
先使用AES
密钥加密,再进行Base64
编码。结果作为实际响应体
中payload
字段的值。发送实际响应体
。
接入方:对收到的实际响应体
中payload
字段的值先进行Base64
解码,再使用AES
密钥解密。结果即为原始响应体
。
原始响应体
{
"key_1": "value_1",
"key_2": "value_2",
"key_3": "value_3"
}
实际响应体
{
"payload": "5L2XuwCQ3tnkL2Xk0J6i7MJtd6gkladDmN0WR8vzoi1ViSZ69/nSr8I9lykShKbTy5JnWD0O/Ly8mqn7GJNxvd1WX5CV2gU+q5Lmg1KJrgg="
}
Java工具类示例
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;
import static java.nio.charset.StandardCharsets.UTF_8;
public class AesUtils {
private static final Base64.Encoder ENCODER = Base64.getEncoder();
private static final Base64.Decoder DECODER = Base64.getDecoder();
public static String aesEncrypt(SecretKey key, String plaintext) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherBytes = cipher.doFinal(plaintext.getBytes(UTF_8));
return new String(ENCODER.encode(cipherBytes), UTF_8);
}
public static String aesDecrypt(SecretKey key, String ciphertext) throws Exception {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] cipherBytes = DECODER.decode(ciphertext.getBytes(UTF_8));
return new String(cipher.doFinal(cipherBytes), UTF_8);
}
public static SecretKey newAesKey(String keyStr) {
return new SecretKeySpec(DECODER.decode(keyStr.getBytes(UTF_8)), "AES");
}
public static String toAesKeyStr(SecretKey key) {
return new String(ENCODER.encode(key.getEncoded()), UTF_8);
}
}
签名机制
为保证API的安全调用,ECardPay会对每个请求和响应通过签名进行身份验证。
接入方与ECardPay需使用签名算法HMAC SHA256
,对请求待签字符串和响应待签字符串进行签名,签名结果采用Hex
编码,对应请求头和响应头的sign字段。
请求待签字符串
所有字段按如下顺序依次使用|符号连接。
apiKey|service|version|requestId|timestamp|payload
apiKey,service,version,requestId and timestamp 来自请求头中对应字段。 payload 来自实际请求体中payload字段。
接入方:对请求待签字符串使用HMAC-SHA256生成消息摘要作为签名,再进行hex编码。结果作为请求头中sign字段的值。
响应待签字符串
所有字段按如下顺序依次使用|
符号连接。
service|version|requestId|timestamp|code|payload
service,version,requestId,timestamp,code 来自响应头中对应字段。 payload 来自实际响应体中payload字段。
ECardPay:对响应待签字符串使用HMAC-SHA256生成消息摘要作为签名,再进行hex编码。结果作为请求头中sign字段的值。
Java工具类示例
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
public class HmacTest {
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
String hmacSHA256Algorithm = "HmacSHA256";
String data = "e4664784e85e82799696acbf70580bbdcf0bfbf4|createCard|2.0|a5ebc0ba-b7ec-11ed-afa1-0242ac120002|1277851018000|ewogICJrZXlfMSI6ICJ2YWx1ZV8xIiwKICAia2V5XzIiOiAidmFsdWVfMiIsCiAgImtleV8zIjogInZhbHVlXzMiCn0=";
String key = "886f04ad550d95459ec1d3af1747a844ed32951852e491b3cddea61aca5b2630";
SecretKeySpec secretKeySpec = new SecretKeySpec(hex2Bytes(key), hmacSHA256Algorithm);
Mac mac = Mac.getInstance(hmacSHA256Algorithm);
mac.init(secretKeySpec);
String sigStr = bytesToHex(mac.doFinal(data.getBytes()));
System.out.println(sigStr);
}
private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray();
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = HEX_ARRAY[v >>> 4];
hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
}
return new String(hexChars);
}
public static byte[] hex2Bytes(String str)
{
byte[] bytes = new byte[str.length() / 2];
for (int i = 0; i < bytes.length; i++)
{
bytes[i] = (byte) Integer
.parseInt(str.substring(2 * i, 2 * i + 2), 16);
}
return bytes;
}
}