小包专线

追踪轨迹

海外派

运价试算

未出账单详情

更新时间:2026-01-21 11:32:34

-接口概要

根据运单号获取未出账单详情

此接口需要联系燕文销售申请权限;

-公共参数

*所有请求都需要提供公共参数

参数名 类型 是否必填 描述
data String 是 业务接口参数
-业务参数

API调用除了必须包含公共参数外,如果API本身有业务级的参数也必须传入,每个API的业务级参数请参考文档以下章节。

推送IP:49.235.52.214(白名单备案)

-关于加密规则

采用AES加密方式,实例方法参见下方附件 

测试环境加密KEY:开通权限至燕文客户中心【财务管理-账单接口-未出账单接口-配置接口】沙箱服务配置

正式环境加密KEY:开通权限至燕文客户中心【财务管理-账单接口-未出账单接口-配置接口】正式服务配置

-请求方式

请求方式具体参考接口,用POST方式发起请求。发送参数时请以json方式发送数据。

Content-Type:application/json

-请求参数
字段名 类型 是否必填 描述
waybillNumber String 是 运单号
exchangeNumber String 否 转单号
orderNumber String 否 订单号
pickupWarehouse String 是 发货仓
customerCode String 是 发货账号
merchantCode String 是 商户号
calcWeight Int 是 计费重量
weight Int 是 实重
weightUnit String 是 重量单位
expressLength int 是 长,默认单位cm
expressWidth int 是 宽,默认单位cm
expressHeight int 是 高,默认单位cm
timeOfExpress date 是 账单日期
timeOfCalc datetime 是 计费时间
deliveryChargeOfOriginal decimal 是 折前资费
deliveryCharge decimal 是 折后资费
linehaulCharge decimal 是 干线费
surcharge decimal 是 附加费
vatCharge decimal 是 税费
totalAmount decimal 是 合计金额
currency String 是 币种,默认CNY
remark String 是 备注
version int 是 版本号,默认1,账单每调整一次,版本号+1
regionName String 是 目的地
productName String 是 产品名称
merchantName String 是 商户名称
expenseType String 是 交易类型
-请求示例:
{"data":"BBj85GSylO5g0HFuHFJoLoWvH4h6/kIF0/AmBxh//GqvHLr+Mg1P4HKyp9//7GAwqnLSHDDgkO/neascvLoT34R16kZ84spPfCBo3a+ALewBMwro5mdoSIzf/sO5QM8CYVOZUP9fe1yrdk/hPHABaZmv3sSxwjhLeeU8CWuVXTrf5dhr1qiq6h5wz+6WHGXs+Z9x/1JH3057YSUEKsZw+/zFr2H99OBPtP1WyVahNJTsvsNU9ihl9QQiNe9Ue+g3ZGxa6XKKa0g01xSeKfSIDfPPdkMaQx9+KYJnubVLqTkUPypiL7HDbDVtp/a5nUrP2bhNB6on4AKM7PhU5qqv05Tp4OyjAWD7CDMTJjL+RMhwICpEBmHbCnlztp/Lk3CfH+gDdTx3qHeZNr5QudcRNwIBuAkRRzEyp/ktPjgHIuPU7rFc+5QCqyNvzM0PLkdryYjT0RHRl+Zf80kn2eJAsvFbcCS8UijP79pNhhaLrk3rrWq3wtowQFT62BK8cq3Jf2Tp5a8Du5hEqlUPo/n9j2WUMCF920VK8rsnzk/ZQf05xNOom++rc3xwEdnbqRvrU2PRLklUUO95WpHn/+1hHfQX9xlxNdJj/BmhnygonOA6uTe2L+U+XjtV9x9JsTDNG79x5b0ooWCHaIOtlZBhMe2BCPNjyfQADsBycxDq6bFr2XDS7cJPXd0UUeT3+yYNe1qN0Zan91s0RHM37Z9gMS8JHrfJlBG/q7xE+oLXY30wViiR8UUtOtyCFnClzlSFoxfaiUa2i+mK/QSrIKakmzyQ4GPD1L/ZOic8M1FIY/YeWIr36Nfqvx2kBO6bt7NYy+0sRGN9fd+dqF4OvRuSOc5h+7SptHP8vrIO5nU8i7dQr74M6IUO85XT4dl3ftFu"}

data格式详情:

{"waybillNumber":"UG307850645YP","exchangeNumber":"4205315092612902849687000000637032","orderNumber":"AMTULAD21122860849","pickupWarehouse":"义乌燕文","customerCode":"1234567890","merchantCode":"1234567890","calcWeight":616,"weight":616,"weightUnit":"g","expressLength":0,"expressWidth":0,"expressHeight":0,"expenseType":"TC01","timeOfExpress":"2021-12-29","timeOfCalc":"2021-12-29 09:57:26","deliveryChargeOfOriginal":92.30,"deliveryCharge":88.64,"linehaulCharge":0.29,"surcharge":0.00,"vatCharge":0.00,"totalAmount":88.93,"currency":"USD","remark":"重量调整","version":1,"regionName":"美国","productName":"燕文专线追踪-普货","merchantName":"YW-TEST"}
- 返回参数
字段名 类型 必填 描述
success Boolean 是 是否成功
code String 是 消息编码。成功为0,失败且需触发重推为1,失败并不用触发重推为2.
message String 是 消息描述
data object 否 接口返回的数据对象
-返回示例:
{
	"success": true,
	"code": "0",
	"message": "操作成功",
	"data": object
}
- 重推机制

若接口因网络或返回值success为false等导致数据未能推送成功,则该条数据五分钟后重试,若重试五次后依旧未成功则不再重试,需要人工干预方能重新推送。

-附件A-Java
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.SecureRandom;

public class AesUtils {
    private static final String ALGORITHMSTR = "AES/ECB/PKCS5Padding";

    /**
     * AES加密
     *
     * @param content    待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的byte[]
     * @throws Exception
     */
    public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
        secureRandom.setSeed(encryptKey.getBytes("utf-8"));
        kgen.init(128, secureRandom);
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance("AES");// 创建密码器
        byte[] byteContent = content.getBytes("utf-8");
        cipher.init(Cipher.ENCRYPT_MODE, key);// 初始化
        byte[] result = cipher.doFinal(byteContent);
        return result; // 加密
    }


    /**
     * AES加密为base 64 code
     *
     * @param content    待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的base 64 code
     * @throws Exception
     */
    public static String aesEncrypt(String content, String encryptKey) throws Exception {
        return encode(aesEncryptToBytes(content, encryptKey));
    }

    /**
     * AES解密
     *
     * @param encryptBytes 待解密的byte[]
     * @param decryptKey   解密密钥
     * @return 解密后的String
     * @throws Exception
     */
    public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG") ;
        secureRandom.setSeed(decryptKey.getBytes("utf-8"));
        kgen.init(128, secureRandom);
        SecretKey secretKey = kgen.generateKey();
        byte[] enCodeFormat = secretKey.getEncoded();
        SecretKeySpec key = new SecretKeySpec(enCodeFormat, "AES");
        Cipher cipher = Cipher.getInstance("AES");// 创建密码器
        cipher.init(Cipher.DECRYPT_MODE, key);// 初始化
        byte[] result = cipher.doFinal(encryptBytes);
        return new String(result,"utf-8"); // 解密
    }


    /**
     * 将base 64 code AES解密
     *
     * @param encryptStr 待解密的base 64 code
     * @param decryptKey 解密密钥
     * @return 解密后的string
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
        return StringUtils.isEmpty(encryptStr) ? null : aesDecryptByBytes(decode(encryptStr), decryptKey);
    }

    /**
     * 解码
     *
     * @param base64
     * @return
     */
    public static byte[] decode(final String base64) {
        if (StringUtils.isEmpty(base64)) {
            return null;
        }
        return Base64.decodeBase64(base64);
    }

    /**
     * 加码
     *
     * @param binaryData
     * @return
     */
    public static String encode(byte[] binaryData) {
        return Base64.encodeBase64String(binaryData);
    }


    public static void main(String[] args) throws Exception {
        String content = "我是明文";
        String password = "12345678";
        // 加密
        System.out.println("加密前:" + content);
        String decode = aesEncrypt(content,password);
        System.out.println("密文字符串:" + decode);
        // 解密
        System.out.println("解密后:" + aesDecrypt(decode, password)); //不转码会乱码

    }
}
-附件B-PHP
<?php
echo "解密处理:";

$sKey = substr(openssl_digest(openssl_digest('1234567890', 'sha1', true), 'sha1', true), 0, 16);
$iv = '';
$decrypted = openssl_decrypt(base64_decode('BBj85GSylO5g0HFuHFJoLoWvH4h6/kIF0/AmBxh//GqvHLr+Mg1P4HKyp9//7GAwqnLSHDDgkO/neascvLoT34R16kZ84spPfCBo3a+ALewBMwro5mdoSIzf/sO5QM8CYVOZUP9fe1yrdk/hPHABaZmv3sSxwjhLeeU8CWuVXTrf5dhr1qiq6h5wz+6WHGXs+Z9x/1JH3057YSUEKsZw+4z4pl7mWRY7FrEmotRpXIkRurY3rgweW4W1cnGlROCY8670nWNhVhIyW4fhJurJJq66mhXKBLyawDJNR1b4nTJJlf+DLyApjwmYiQbcnFZNf7rRDV37yks6wmWHGS0prlrI1T3akrA5Q4mYDSmknfn170+j52Jp9JmSq4YNgZyAcKqYRZJLkgwFaDgd8ai26nVydVM8ovD0LBA4QWen0Lz2aiahP46ODFxDeeY8Y9FtXpW2AGuZyCkCh2xZr0VDmvQQdoLdfaWQfjsR5S8CyuNz0sAya6pH1ndPQYD/SDn66iPMkbG3/7wy37GZxL3ds4Pw9HQ6aGYrONjOGPOz/cgyT5wrPX4alsAz+WIc3lql+pvnM4Kbli0rHNy2SzoxMnJCu1LDjCN//l3PpCXz0LrEq2XKyZB3SxgeBgRJNsHC1tyxhATwUUvgV4bvcIV6kLPxIxatGkH3AmDoc4ZT8mtbSOQi33JQJsBCw7O3uYzKwkORhyQvp0L+Po7iuqF1urGxEJEzQal7jAT7Ps97uvK0tVZUqjlLvKV2YvE6m/v3OWwGBLS2VFrPsmFmo0jyDeJKSmFj36msuaWWJWtXerD53l8+HBDBAFVWPPYVbw7RSZ20fwElHeLu4VF5PU2GnY0SqfY2YqadD9H9bSSd5YmdHuUHL2bQjD3hz7WUX73+1J3KNDl0KhQiEe64XGBnwQ=='), 'AES-128-ECB', $sKey, OPENSSL_RAW_DATA, $iv);
echo $decrypted;
-附件C-Python
#! /usr/bin/python3
# -*- coding:utf-8 -*-

import base64
from Crypto.Cipher import AES
import hashlib


class AesEncryptDecrypt:
    def __init__(self, key: str):
        """
        Init AES object used by encrypt or decrypt.
        AES-ECB-PKCS5Padding,the same as AES in java.
        :param key: Original key.
        """
        self.aes = AES.new(self.get_sha1prng_key(key), AES.MODE_ECB)

    @staticmethod
    def get_sha1prng_key(key: str) -> bytes:
        """
        key encrypted with SHA1PRNG,same as Java AES/ECB/PKCS5Padding mode.
        :param key :Original key.
        :return: key encrypted with SHA1PRNG,which used in AES Object.128 bits(16 long bytes).
        """
        signature: bytes = hashlib.sha1(key.encode()).digest()
        signature: bytes = hashlib.sha1(signature).digest()
        return signature[:16]

    @staticmethod
    def pkcs5_padding(data: bytes) -> bytes:
        """
        Padding PKCS5
        When pieces of data are required for alignment, fill in bytes.
        needSize = 16-len(data) % 16
        if needSize == 0:
            needSize = 16
        return data + needSize.to_bytes(1, 'little')*needSize

        :param data:string data need padding.
        :return:
        """
        '''
        num: int = ord(data[-1])
        padding_data: str = data + num * chr(num)
        return padding_data
        '''
        needSize = 16 - len(data) % 16
        if needSize == 0:
            needSize = 16
        return data + needSize.to_bytes(1, 'little') * needSize

    @staticmethod
    def pkcs5_unpadding(data: str) -> str:
        """
        Unpadding PKCS5
        num: int = ord(data[-1])
        unpadding_data = data[: -1 * num]
        return unpadding_data

        paddingSize = data[-1]
        return data.rstrip(paddingSize.to_s(1, 'little'))

        :param data:
        :return:
        """
        num: int = ord(data[-1])
        unpadding_data = data[: -1 * num]
        return unpadding_data

    def aes_encrypt(self, data: str) -> str:
        """
        Encrypt string by AES.
        String to bytes-->padding PKCS5--> Encrypt by AES-->Encrypt by Base64-->Base64 to string.
        :param data:string needed encrypt.
        :return:String encrypted.
        """
        # String to bytes.
        data_bytes = data.encode(encoding='utf-8')
        # print(f'data_bytes:{data_bytes}')
        # Padding PKCS5
        data_padding = self.pkcs5_padding(data_bytes)
        # print(f'data_padding:{data_padding}')
        # Encrypt by AES.
        encrypt_aes = self.aes.encrypt(data_padding)
        # print(f'encrypt_aes:{encrypt_aes}')
        # Encrypt by Base64
        encrypt_base64 = base64.b64encode(encrypt_aes)
        # print(f'encrypt_base64:{encrypt_base64}')
        # Base64 to string
        encrypt_data = encrypt_base64.decode(encoding='utf-8')
        # print(f'encrypt_data:{encrypt_data}')
        return encrypt_data

    def aes_decrypt(self, data: str) -> str:
        """
        Encrypt string by AES.
        String to bytes-->Decrypt by base64-->Decrypt by AES-->bytes to string-->unpadding string
        :param data:String needed decrypted.
        :return:String decrypted.
        """
        # String to bytes.
        decrypt_bytes = data.encode(encoding='utf-8')
        # print(f'decrypt_bytes:{decrypt_bytes}')
        # Decrypt by base64.
        decrypt_base64 = base64.decodebytes(decrypt_bytes)
        # print(f'decrypt_base64:{decrypt_base64}')
        # Decrypt by AES
        decrypt_aes = self.aes.decrypt(decrypt_base64)
        # print(f'decrypt_aes:{decrypt_aes}')
        # bytes to string
        decrypt_string = decrypt_aes.decode(encoding='utf-8')
        # print(f'decrypt_string:{decrypt_string}')
        # unpadding string
        decrypt_data = self.pkcs5_unpadding(decrypt_string)
        # print(f'decrypt_data:{decrypt_data}')
        return decrypt_data


if __name__ == '__main__':
    key = '1234567890'
    aes = AesEncryptDecrypt(key)
    encrypt_data = 'I am a string that needed to be encrypted!'
   # data needed decrypted.
    decrypt_data = 'oDlBOiK6y4prLlWa0qAQnM0C67pgmUyRAPcHlfoYkHqLeXDxuS14yuCvM8G6dvmX'
    print(aes)
    print(aes.aes_encrypt(encrypt_data))
    print(aes.aes_decrypt(decrypt_data))