页面树结构
转至元数据结尾
转至元数据起始

eTower为每一个API客户提供一个API令牌和对应的密钥。密钥只用作MAC SHA-1签名,密钥不会在请求中进行传输。每一个请求必须包含身份认证信息以证实发送方的身份和权限。

入门

根据以下步骤快速完成身份认证。 

第一步:获取 Token 和 Key 


测试环境





正式环境

1

Host

http://qa.etowertech.comHost

http://cn.etowertech.com (中国服务器)

http://us.etowertech.com (美国服务器)

2

Token

请与集成商联系

Token请与集成商联系
3

Key

请与集成商联系

key

请与集成商联系

第二步:添加请求报文头部信息

Request Headers

X-WallTech-Date请求发送时间

时间格式: RFC1123 Format

格式:EEE, DD MM YYYY HH:MM:SS ZZZ

样例:Thu, 04 Nov 2021 03:39:28 GMT

注意:格林威治时间(GMT),是北京时间(GMT+8)减去8小时。

当服务器接收时间与发送时间相差15分钟以上,服务端拒绝请求。

Authorization签名认证

格式:WallTech <Token>:<Base64 Encoded HMAC SHA-1 Hash>

样例:WallTech test5AdbzO5OEeOpvgAVXUFE0A:LhpcUyKXCaGcn3tVPwY4nX44XTA=

说明:

    • <Token>:API 令牌 Token。
    • <Base64 Encoded HMAC SHA-1 Hash> :

Java代码描述:

通过将API令牌Key,如Key=79db9e5OEeOpvgAVXUFWSD,使用SecretKeySpec类对Key进行HmacSHA1方式的加密,再初始化一个算法为HmacSHA1的Mac对象,然后使用key初始化这个Mac对象。最后将Mac对象处理为Byte,然后对其进行Base64转换操作。具体请参考 加密样例 说明。

Content-Typeapplication/json/
Acceptapplication/json/

第三步:开始您的API对接

您现在可以开始将 eTower API集成到您的测试/正式环境中。 有关所有 API 操作的完整信息,请参阅通用 API 文档。 如需技术帮助,请发送电子邮件至

etowercs@walltechsystem.cn 。

版本和兼容性

eTower对接API,每个主要版本号使用不同的URL。在同一个主版本号内,每一个次版本的发布会提供新的功能,但是已存在功能和信息不会被删除或修改。为了保证同一主版本的兼容性,API对接客户端必须能够忽略服务端返回新加的信息和功能。

    • 例如: 一个REST调用服务端返回JSON:{“orderId”:”12345”, “price”:69, “priceCurrency”:”AUD”}

客户端必须对将来新增的JSON属性不敏感,存在3个属性不会被删除或重新定义。

如果返回增加了trackingNo, 客户端要照常工作。

    • 例如:增加trackingNo字段:{“orderId”:”12345”, “price”:69, “priceCurrency”:”AUD”, “trackingNo”:”123456”}

不同主版本之间不保证此兼容性。

错误处理的基本规则

服务端和客户端的系统实现中的错误,包括可以在开发和测试中被发现和避免的,eTower 使用HTTP返回状态代码来处理。

HTTP 状态码说明:

    • 2XX是请求成功标识;
    • 4XX是客户端错误;
    • 例如:认证签名不符,JSON请求格式错误,请求不存在的数据等。

返回HTTP状态代码是按照HTPP协议规范,这些错误是可以在开发阶段发现和避免的。

    • 5XX 是服务端内部错误;

如有发现,请联系eTower团队。

有些错误是系统无法避免的,不是系统实现或逻辑错误;

    • 例如:由于邮编是收件人提供的,邮编错误在系统中是不可以避免的。

eTower对这类错误采用不同的处理方式。发生时,服务端仍返回HTTP 2XX,所有错误信息反映在结果JSON中。

加密样例

您可以直接参考以下代码样例,也可以进行下载压缩包 API Signature Demo.zip

JAVA Demo
package com.walltech.parcel.integration;


import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.TimeZone;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.walltech.platform.util.Base64;

public class IntegrationHelper {
    
    private static final char NEW_LINE = (char) 0x000A;
    
    private static final String HEADERS_AUTHORIZATION_PREFIX = "WallTech ";
    
    private static final String HMAC_SHA1_ALGORITHM = "HmacSHA1";
    
    private static String calculate(String secretAccessKey, String data) {
        try {
            SecretKeySpec signingKey = new SecretKeySpec(secretAccessKey.getBytes("UTF-8"), HMAC_SHA1_ALGORITHM);

            Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
            mac.init(signingKey);

            byte[] rawHmac = mac.doFinal(data.getBytes("UTF-8"));
            return new String(Base64.encode(rawHmac), "UTF-8");
        }
        catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
    
    
    /**
     * 
     * @param method should be POST,GET...(upperCase)
     * @param url   fully url (eg.:http://qa.etowertech.com/services/shipper/orders)
     * @param token
     * @param secret
     * @return
     */
    public static Map<String, String> buildHeader(String method, String url, String token, String secret) {
        Map<String, String> headers = new HashMap<String, String>();
        SimpleDateFormat format = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US);
        format.setTimeZone(TimeZone.getTimeZone("GMT"));
        String dateStr = format.format(new Date());
        StringBuilder sb = new StringBuilder();
        sb.append(method).append(NEW_LINE);
        sb.append(dateStr).append(NEW_LINE);
        sb.append(url);
        String authorization = MessageFormat.format(HEADERS_AUTHORIZATION_PREFIX + "{0}:{1}", token, calculate(secret, sb.toString()));

        headers.put("X-WallTech-Date", dateStr);
        headers.put("Authorization", authorization);
        return headers;
    }

}

PHP Demo
<?php
	
	define('WALLTECH_SERVER', 'http://qa.etowertech.com');
	define('ACCESS_TOKEN', 'test5AdbzO5OEeOpvgAVXUFE0A');
	define('SECRET_KEY', '79db9e5OEeOpvgAVXUFWSD');
	
	function build_headers($method, $path, $acceptType='application/json'){
		$walltech_date=date(DATE_RFC7231,time()-60*60*8);
		$auth = $method."\n".$walltech_date."\n".$path;
		$hash=base64_encode(hash_hmac('sha1', $auth, SECRET_KEY, true));
		
		//echo $walltech_date."<br>".$auth."<br>".$hash."<br>";
		return array(	'Content-Type: application/json',
						'Accept: '.$acceptType,
						'X-WallTech-Date: '.$walltech_date,
						'Authorization: WallTech '.ACCESS_TOKEN.':'.$hash);
	}
	
	function send_request($method,$headers,$body){
		$ch = curl_init(WALLTECH_SERVER.$method);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');  
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		
		curl_setopt($ch, CURLOPT_HTTPHEADER,$headers);   
		curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
		return curl_exec($ch);
	}
	
	function create_order(){
		$method='/services/integration/shipper/orders';
		$headers=build_headers('POST', WALLTECH_SERVER.$method);
		$body='[{"referenceNo":"12345","recipientName":"Paul Allan","addressLine1":"123 A Street","city":" PORT BOTANY","state":"NSW","postcode":"2036","weight":0.45,"description":"plastic toy","invoiceValue":9.89},{"referenceNo":"12346","recipientName":"Paul Allan","addressLine1":"123 A Street","city":" PORT BOTANY","state":"NSW","postcode":"2036","weight":0.45,"description":"plastic toy","invoiceValue":9.89}]';

		return send_request($method,$headers,$body);
	}

	function print_label(){
		$method='/services/integration/shipper/labels';
		$headers=build_headers('POST', WALLTECH_SERVER.$method);
		$body='["12345","12346"]';
		
		return send_request($method,$headers,$body);
	}
	
	function forecast(){
		$method='/services/integration/shipper/manifests';
		$headers=build_headers('POST', WALLTECH_SERVER.$method);
		$body='["12345","12346"]';
		
		return send_request($method,$headers,$body);
	}

	function track(){
                $method='/services/integration/shipper/trackingEvents';
                $headers=build_headers('POST', WALLTECH_SERVER.$method);
                $body='["SHW1005282011420","SHW1005379011425"]';

                return send_request($method,$headers,$body);
        }


	function pod() {
		$method='/services/integration/shipper/proof-of-delivery/3LQ0008086010229';
		$headers=build_headers('GET', WALLTECH_SERVER.$method);
		return send_request_get($method,$headers);
	}

	echo create_order();
	echo print_label();
	echo forecast();
?>



JS Demo
const ForecastDao = require('./ForecastDao');
var request = require('request');
var soap = require('soap');
var crypto = require('crypto');
var Base64 = require('js-base64').Base64;
var parseString = require('xml2js').parseString;
const path = require("path");
const $dao = require('../daos/Dao');
const $CONST = require("../../util/CONST");


const url = 'http://qa.etowertech.com';
const Token = 'test5AdbzO5OEeOpvgAVXUFE0A';
const Key = '79db9e5OEeOpvgAVXUFWSD';

module.exports={
    createOrder,
}

function createOrder(req,res,next,order,cb){
    if(!order){
        return cb();
    }
    let body = getJsonCreatOrder(order);
    //console.log(body);
    let X_WallTech_Date = (new Date()).toGMTString();
    let path =`/services/shipper/orders`;
    let auth = "POST" + '\n' + X_WallTech_Date + '\n' + url +path;
    let a = crypto.createHmac('sha1',Key).update(auth).digest().toString('base64');
    request({
        url: url +path ,
        method: "POST",
        headers: {
            'Authorization': "WallTech "+Token+":"+a,
            'Content-Type': 'application/json',
            'X-WallTech-Date':X_WallTech_Date,
            'Accept':'application/json',
            'Host':'qa.etowertech.com',
        },      
        body: body
    }, (error, response, body) => {
       // console.log(body);
        let r = {
            status: 0,
            code: "",  //物流内部单号  或者  跟踪单号
            info: "", //成功信息或者失败信息
            system: "UBI",
            track: "",
        };
    })
}


function getJsonCreatOrder(order){
    return JSON.stringify([{
        "trackingNo": "",
        "consignmentId": "",
        "referenceNo": order.no,
        "addressLine1": order.street,
        "addressLine2": "",
        "addressLine3": "",
        "city": order.city,
        "country": order.country,
        "description": order.ename,
        "nativeDescription":order.cname,
        "email": "",
        "facility": "*",
        "instruction": "",
        "invoiceCurrency": "AUD",
        "invoiceValue": 100,
        "phone": order.telephone,
        "platform": "",
        "postcode": order.postcode,
        "recipientCompany": "",
        "recipientName": order.uname,
        "serviceCode": order.shipcode,
        "serviceOption": "",
        "sku": "",
        "state": order.province,
        "weightUnit": "kg",
        "weight":order.weight,
        "dimensionUnit": "",
        "length": 20,
        "width": 20,
        "height": 20,
        "volume": 20,
        "shipperName": $CONST.J.j_contact,
        "shipperAddressLine1": $CONST.J.j_address,
        "shipperAddressLine2": "",
        "shipperAddressLine3": "",
        "shipperCity": $CONST.J.j_city,
        "shipperState": $CONST.J.j_province,
        "shipperPostcode": $CONST.J.j_post_code,
        "shipperCountry": $CONST.J.j_county,
        "shipperPhone": $CONST.J.j_tel,
        "recipientTaxId": "",
        "authorityToLeave": "",
        "incoterm": "",
        "lockerService": "",
        "extendData" :{
        "nationalNumber":"",
        "nationalIssueDate" : "",
        "cyrillicName":"",
        "imei":"",
        "isImei":false,
        "vendorid": "",
        "gstexemptioncode": "",
        "abnnumber": "",
        "sortCode": "",
         "coveramount":""
         },
        "orderItems": [
          {
            "itemNo": "1",
            "sku": "asd-xl",
            "description": order.ename,
            "nativeDescription":order.cname,
            "hsCode": order.ename,
            "originCountry": "CN",
            "unitValue": 50,
            "itemCount": order.quantity,
            "weight": 0,
            "productURL": "",
            "htsCode":"" 
          },
        ]
      }])
}





C# Demo
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;


namespace Parcel
{
    public class Sample
    {
        public Sample()
        {
        }
        
        static string WALLTECH_SERVER = "http://qa.etowertech.com";
        static string ACCESS_TOKEN = "test5AdbzO5OEeOpvgAVXUFE0A";
        static string SECRET_KEY = "79db9e5OEeOpvgAVXUFWSD";
       
        static void Main(string[] args)
        {
            Console.WriteLine("Creating order");
            CreateOrder();
            //PrintLabel();
        }

        public static void CreateOrder()
        {
            string PATH = "/services/shipper/orders";
            string BODY = "[{\"referenceNo\":\"6788\",\"recipientName\":\"Paul Allan\",\"addressLine1\":\"123 A Street\",\"city\":\" PORT BOTANY\",\"state\":\"NSW\",\"postcode\":\"2036\",\"weight\":0.45,\"description\":\"plastic toy\",\"invoiceValue\":9.89},{\"referenceNo\":\"12346\",\"recipientName\":\"Paul Allan\",\"addressLine1\":\"123 A Street\",\"city\":\" PORT BOTANY\",\"state\":\"NSW\",\"postcode\":\"2036\",\"weight\":0.45,\"description\":\"plastic toy\",\"invoiceValue\":9.89}]";
            SendRequest("POST", WALLTECH_SERVER + PATH, BODY);
        }

        public static void PrintLabel()
        {
            string PATH = "/services/shipper/labels";
            string BODY = "[\"12345\",\"12346\"]";
            SendRequest("POST", WALLTECH_SERVER + PATH, BODY, "application/octet-stream");
        }

        public static void Forecast()
        {
            string PATH = "/services/shipper/manifests";
            string BODY = "[\"12345\",\"12346\"]";
            SendRequest("POST", WALLTECH_SERVER + PATH, BODY);
        }

        static string EncodeAuth(string data, string key)
        {
            string rtn = null;
            if (null != data && null != key)
            {
                byte[] byteData = Encoding.UTF8.GetBytes(data);
                byte[] byteKey = Encoding.UTF8.GetBytes(key);
                using (HMACSHA1 myhmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
                {
                    using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
                    {
                        byte[] hashValue = myhmacsha1.ComputeHash(stream);
                        rtn = Convert.ToBase64String(hashValue);
                    }
                }
            }
            return rtn;
        }

        static protected void SendRequest(string method, string path, string body, string acceptType = "application/json")
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(path);
            // RFC 1123 date format, e.g. "Sun, 09 Mar 2008 16:05:07 GMT"
            string wallTechDate =String.Format("{0:R}", DateTime.UtcNow);
            string auth = method + '\n' + wallTechDate + '\n' + path;
            string hash = EncodeAuth(auth, SECRET_KEY);

            request.ContentType = "application/json";
            request.Accept = acceptType;
            request.Headers.Add("X-WallTech-Date", wallTechDate);
            request.Headers.Add("Authorization","WallTech " + ACCESS_TOKEN + ':' + hash);
            request.Method = method;

            byte[] data = Encoding.UTF8.GetBytes(body);
            request.ContentLength = data.Length;

            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(data, 0, data.Length);
            }

            try
            {
                Console.WriteLine("\nThe Uri that was requested is {0}",request.RequestUri);
                using (WebResponse response = request.GetResponse())
                {
                    Console.WriteLine("\nThe Uri that responded to the WebRequest is '{0}'",response.ResponseUri);
                    // Do something with response       
                    PrintWebResponse(response);  
                }
            }
            catch (WebException ex)
            {
                // Handle error
                Console.Error.WriteLine(ex.ToString());
            }
            Console.ReadLine();
        }

        static void PrintWebResponse(WebResponse response)
        {
            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                string text = reader.ReadToEnd();
                Console.WriteLine("Response: " + text);
            }            
        }
    }
}




Python Demo
import requests
from datetime import datetime
import hmac
import base64
from hashlib import sha1


#define function
def buildWalltechDate():
    now = datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
    return now

def buildAuthorization(now, key, token):
    signedString = bytes('POST\n%s\n%s' % (now, url), encoding='utf-8')
    signSha1 = hmac.new(key, signedString, sha1).digest()
    sign = base64.b64encode(signSha1).decode()
    authorization = 'WallTech %s:%s' % (token, sign)
    return authorization

def buildHeaders(now, authorization):
    headers = {
        "Content-Type": "application/json",
        "X-WallTech-Date": "%s" % (now),
        "Authorization": "%s" % (authorization),
        "Accept": "application/json",
    }
    return headers

#main thread

#your token && your key
token = "test9gPQuBsyNIhzTylSvh2"
key = bytes("TbKVYZ35YZF5RwODwZJrBA", encoding='utf-8')
#build headers
walltechDate = buildWalltechDate()
authorization = buildAuthorization(walltechDate, key, token)
headers = buildHeaders(walltechDate, authorization)

#createShipment
#your request url && your request method
method = "POST"
url = "http://qa.etowertech.com/services/shipper/orders"
#your data format of json string
data = "[\r\n  {\r\n    \"country\": \"US\",\r\n    \"serviceCode\": \"UBI.CN2US.STD\",\r\n    \"referenceNo\": \"123456dd78\",\r\n    \"recipientCompany\": \"Maxine Frost\",\r\n    \"recipientName\": \"Maxine Frost\",\r\n    \"addressLine1\": \"321 SW Water St.\",\r\n    \"addressLine2\": \"\",\r\n    \"addressLine3\": \"\",\r\n    \"phone\": \"07729717180\",\r\n    \"city\": \"Peorial\",\r\n    \"state\": \"Illinois\",\r\n    \"postcode\": \"61602\",\r\n    \"batteryType\": \"No Battery\",\r\n    \"batteryPacking\": \"No Battery\",\r\n    \"weight\": 2,\r\n    \"nativeDescription\": \"螺钉\",\r\n    \"recipientTaxId\": \"\",\r\n    \"description\": \"NUT\",\r\n    \"invoiceCurrency\": \"USD\",\r\n    \"invoiceValue\": 10,\r\n    \"packingList\": \".\",\r\n    \"sku\": \" 螺钉\",\r\n    \"orderItems\": [\r\n      {\r\n        \"nativeDescription\": \"螺钉\",\r\n        \"itemNo\": \"NUT\",\r\n        \"sku\": \"螺钉\",\r\n        \"description\": \"POLYETHYLENE,GRV<.94,VIS >1.44\",\r\n        \"hsCode\": \"0101100010\",\r\n        \"originCountry\": \"CHINA\",\r\n        \"unitValue\": 10,\r\n        \"itemCount\": 1,\r\n        \"weight\": 0.1\r\n      }\r\n    ]\r\n  }\r\n]"

#printLabel
#your request url && your request method
method = "POST"
url = "http://qa.etowertech.com/services/shipper/labels"

#forecast
#your request url && your request method
method = "POST"
url = "http://qa.etowertech.com/services/shipper/manifests"

#trackingEvents
#your request url && your request method
method = "POST"
url = "http://qa.etowertech.com/services/shipper/trackingEvents"

#request
#you should change your data to match the suitable request
response = requests.request(method, url, headers=headers, data=data.encode('utf-8'))
print(response.text)



.netsample Demo
using System;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;


namespace Parcel
{
    public class Sample
    {
        public Sample()
        {
        }
        
        static string WALLTECH_SERVER = "http://qa.etowertech.com";
        static string ACCESS_TOKEN = "test5AdbzO5OEeOpvgAVXUFE0A";
        static string SECRET_KEY = "79db9e5OEeOpvgAVXUFWSD";
       
        static void Main(string[] args)
        {
            Console.WriteLine("Creating order");
            CreateOrder();
            //PrintLabel();
        }

        public static void CreateOrder()
        {
            string PATH = "/services/shipper/orders";
            string BODY = "[{\"referenceNo\":\"6788\",\"recipientName\":\"Paul Allan\",\"addressLine1\":\"123 A Street\",\"city\":\" PORT BOTANY\",\"state\":\"NSW\",\"postcode\":\"2036\",\"weight\":0.45,\"description\":\"plastic toy\",\"invoiceValue\":9.89},{\"referenceNo\":\"12346\",\"recipientName\":\"Paul Allan\",\"addressLine1\":\"123 A Street\",\"city\":\" PORT BOTANY\",\"state\":\"NSW\",\"postcode\":\"2036\",\"weight\":0.45,\"description\":\"plastic toy\",\"invoiceValue\":9.89}]";
            SendRequest("POST", WALLTECH_SERVER + PATH, BODY);
        }

        public static void PrintLabel()
        {
            string PATH = "/services/shipper/labels";
            string BODY = "[\"12345\",\"12346\"]";
            SendRequest("POST", WALLTECH_SERVER + PATH, BODY, "application/json");
        }

        public static void Forecast()
        {
            string PATH = "/services/shipper/manifests";
            string BODY = "[\"12345\",\"12346\"]";
            SendRequest("POST", WALLTECH_SERVER + PATH, BODY);
        }

        static string EncodeAuth(string data, string key)
        {
            string rtn = null;
            if (null != data && null != key)
            {
                byte[] byteData = Encoding.UTF8.GetBytes(data);
                byte[] byteKey = Encoding.UTF8.GetBytes(key);
                using (HMACSHA1 myhmacsha1 = new HMACSHA1(Encoding.UTF8.GetBytes(key)))
                {
                    using (MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(data)))
                    {
                        byte[] hashValue = myhmacsha1.ComputeHash(stream);
                        rtn = Convert.ToBase64String(hashValue);
                    }
                }
            }
            return rtn;
        }

        static protected void SendRequest(string method, string path, string body, string acceptType = "application/json")
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(path);
            // RFC 1123 date format, e.g. "Sun, 09 Mar 2008 16:05:07 GMT"
            string wallTechDate =String.Format("{0:R}", DateTime.UtcNow);
            string auth = method + '\n' + wallTechDate + '\n' + path;
            string hash = EncodeAuth(auth, SECRET_KEY);

            request.ContentType = "application/json";
            request.Accept = acceptType;
            request.Headers.Add("X-WallTech-Date", wallTechDate);
            request.Headers.Add("Authorization","WallTech " + ACCESS_TOKEN + ':' + hash);
            request.Method = method;

            byte[] data = Encoding.UTF8.GetBytes(body);
            request.ContentLength = data.Length;

            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(data, 0, data.Length);
            }

            try
            {
                Console.WriteLine("\nThe Uri that was requested is {0}",request.RequestUri);
                using (WebResponse response = request.GetResponse())
                {
                    Console.WriteLine("\nThe Uri that responded to the WebRequest is '{0}'",response.ResponseUri);
                    // Do something with response       
                    PrintWebResponse(response);  
                }
            }
            catch (WebException ex)
            {
                // Handle error
                Console.Error.WriteLine(ex.ToString());
            }
            Console.ReadLine();
        }

        static void PrintWebResponse(WebResponse response)
        {
            using (StreamReader reader = new StreamReader(response.GetResponseStream()))
            {
                string text = reader.ReadToEnd();
                Console.WriteLine("Response: " + text);
            }            
        }
    }
}






Table of Contents ×

  • 无标签