To authenticate your requests, we provide each client a pair of access token and secret
key. The secret key is only used for HMAC SHA-1 signing and not transmitted over the
wire along with your requests.Each request must contain identity authentication
information to confirm the identity and authority of the sender
introduction
Follow these steps to quickly complete identity authentication
Step 1: get token and key
Step 2: Every request need contain the HTTP header
Request Headers |
---|
X-WallTeach-Date | Request sending time
| Time format: RFC1123 Format format:EEE, DD MM YYYY HH:MM:SS ZZZ Sample:Thu, 04 Nov 2021 03:39:28 GMT Notice: Greenwich Mean Time (GMT) is Beijing Time (GMT+8) minus 8 hours. When the time is more than 15 minutes different from the server time, the request will be denied, and a HTTP 401 returned. |
Authorization | The standard HTTP header carries the authentication signature. | Format: WallTech < Token>: <Base64 Encoded HMAC SHA-1 Hash> Sample:WallTech test5AdbzO5OEeOpvgAVXUFE0A:LhpcUyKXCaGcn3tVPwY4nX44XTA= Explain: <Access Token>: API Token <Base64 Encoded HMAC SHA-1 Hash> Through the key, such as key=79db9e5OEeOpvgAVXUFWSD, use the SecretKeySpec class to encrypt the key in HmacSHA1 mode, and then initialize a Mac object with the algorithm HmacSHA1, and then use the key to initialize the Mac object. Finally, the Mac object is processed as Byte, and then Base64 conversion operation is performed on it.
|
Content-Type | application/json | / |
Accept | application/json | / |
Step 3 Start your API docking
You can now begin to integrate the etower API into your test / formal environment. For complete information on all API operations, refer to the generic
API documentation. For technical assistance, please email etowercs@walltechsystem.cn
1.2 Version and Backward Compatibility
The API is versioned, and different major versions use different URLs. For minor version
enhancement, we may add new features/properties, but never remove or change any
existing features/properties. API clients are required to tolerant newly added properties in
response JSON.
- For example, a REST call returns JSON like{"orderId": "12345", "price": 69, "priceCurrency": "AUD"}
API clients are required to be insensitive to new JSON properties in the future. But the
existing 3 properties won’t be removed or redefined. Should the response have a new
property in the future minor version release, the client implementation need still be able
to work.
- For example Add trackingno field {"orderId": "12345", "price": 69, "priceCurrency": "AUD", "trackingNo": "123456"}
Backward compatibility is not assured between major versions
1.3 Error Handling
Implementation errors that can be found and prevented at development stage are
handled using HTTP status code.
The description of HTTP status code:
- HTTP 2xx indicates successful returns in terms of implementation logic;
Like authentication signature mismatch, malformed JSON requests, inconsistent data,
etc.
Returned HTTP status codes are in accordance with HTTP protocol specification. These
problems can be prevented during development stage.
- 5xx is Service internal error,;
when it happens, please contact us for assistance.
- On the other hand, some "errors" cannot be prevented effectively.
An example can be wrong postcode. System cannot eliminate possible wrong postcode
since we get the postcode from e-commerce customers.
We have a different strategy for those errors. When that happens, REST API returns
HTTP status of 2xx, and the response JSON may contains specific return code
Encryption example
You can directly refer to the following code samples or download the compressed package API Signature Demo.zip
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
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,'application/octet-stream');
$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();
?>
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":""
},
]
}])
}
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);
}
}
}
}
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)
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);
}
}
}
}