Appendix A - Domain/currency mapping
Domain | Currency |
AbeBooks.com | USD |
AbeBooks.co.uk | GBP |
AbeBooks.it | EUR |
AbeBooks.fr | EUR |
AbeBooks.de | EUR |
IberLibro.com | EUR |
ZVAB | EUR |
Appendix B - Order Status Descriptions
Order Status | Description |
04 | Extra Shipping Accepted |
05 | Ordered |
14 | Item Unavailable |
17 | Cancelled By Buyer |
19 | Credit Card Rejected |
24 | Refunded |
35 | Shipped |
53 | Max Price Exceeded |
54 | Inactive Seller |
90 | Extra Shipping Rejected |
93 | Extra Shipping Requested |
Appendix C - Response Status Codes
Status Code | Description |
2000 | Order status successfully retrieved |
2002 | Dryrun succeeded |
2003 | Duplicate request received for order currently being processed |
2010 | Order created successfully |
Error Codes
Status code | Description |
4000 | Malformed message |
4001 | The credit card token provided did not match a credit card on your account |
4002 | No listings were included with the request |
4002 | One or more listings had a quantity less than 1 |
4002 | The total number of items ordered exceeded the limit of 250 |
4003 | Unable to parse JSON |
4090 | Received duplicate RequestID with different content |
4010 | Authentication failure |
4011 | The Abe-Date header was missing |
4012 | Unable to parse the Abe-Date header |
4013 | Request expired |
4014 | Invalid access key |
4015 | Access key expired |
4016 | The Abe-Signature header was missing |
4017 | Invalid request signature |
4018 | The Abe-RequestId header was missing or invalid |
4030 | Not permitted to access |
4220 | The request was malformed, details can be found in the response body |
4293 | Too many requests with an invalid CCToken were made |
4292 | Too many failed authentication attempts were made |
4291 | Request exceeds rate limit |
4041 | Order not found |
4042 | Could not find the resource/malformed URI |
4050 | HTTP method not supported |
4060 | Requested mediatype not supported |
4150 | Submitted mediatype not supported |
5000 | Server error, this incident has been recorded |
5030 | Server is temporarily unavailable or busy |
Sample Code: Python
from datetime import datetime import hashlib, hmac import uuid import requests # Task 1: get message body checksum (empty string if GET request) message_body = "sample payload" body_checksum = hashlib.sha256(message_body).hexdigest() # Task 2: Gather signature elements # First element method = 'POST' # Second element uri = 'https://purchase.api.abebooks.com/v1/orders' # Third element timestamp = datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ') # Fourth element is the body checksum # Task 3: create the final string final_string = '\n'.join([method, uri, timestamp, body_checksum]) print "final string to sign: " + final_string # Task 4: generate the request signature access_key = 'SAMPLE_ACCESS_KEY' secret_key = 'SAMPLE_SECRET_KEY' signature = hmac.new(key=secret_key, msg=final_string, digestmod=hashlib.sha256).hexdigest() print signature # Task 5: submit the request: (you can use any library you like) requestid = str(uuid.uuid4()) header_dictionary = { 'Abe-Date': timestamp, 'Abe-Access-Key': access_key, 'Abe-Signature': signature, 'Abe-RequestId': requestid, 'Content-Type': 'application/json' } response = requests.post(uri, data=message_body, headers=header_dictionary)
Sample Code: Java
import org.apache.http.client.methods.*; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.HttpEntity; import org.apache.http.util.EntityUtils; import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.security.InvalidKeyException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.time.Instant; import java.util.*; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.apache.commons.codec.binary.Hex; public class SigningTutorial { public static final String HMAC_SHA256 = "HmacSHA256"; public static void main(String[] args) throws IOException, NoSuchAlgorithmException, InvalidKeyException { String accessKey ="SAMPLE_ACCESS_KEY"; String secretKey ="SAMPLE_SECRET_KEY"; // Task 1: get message body checksum (empty string if GET request) String messageBody = "sample content"; String bodyChecksum = SigningTutorial.getChecksum(messageBody); // Task 2: Gather signature elements // First element String method = "POST"; // Second element String uri = "https://purchase.api.abebooks.com/v1/orders"; // Third element String dateTime = Instant.now().toString(); // Fourth element is the body checksum // Task 3: create the final string String finalString = method + "\n" + encodedURI + "\n" + dateTime + "\n" + bodyChecksum; String requestId = UUID.randomUUID().toString(); System.out.println(finalString); System.out.println(requestId); // Task 4: generate the request signature String signature = SigningTutorial.getHMAC(secretKey, finalString); // Task 5: submit the request: // We used apache's http client as an example, you don't have to; CloseableHttpClient httpClient = HttpClients.createDefault(); HttpUriRequest uriRequest = new HttpPost(uri);; ContentType json = ContentType.create("application/json"); ((HttpPost)uriRequest).setEntity(new StringEntity(messageBody, json)); // Set headers uriRequest.setHeader("Abe-Date", dateTime); uriRequest.setHeader("Abe-Access-Key", accessKey); uriRequest.setHeader("Abe-Signature", signature); uriRequest.setHeader("Abe-RequestId", requestId); // Execute the method CloseableHttpResponse response = httpClient.execute(uriRequest); try { // do something useful with the response and ensure it is fully consumed System.out.println(response.getStatusLine()); HttpEntity entity1 = response.getEntity(); System.out.println(EntityUtils.toString(entity1)); EntityUtils.consume(entity1); } finally { response.close(); } } public static String getChecksum(String message) throws NoSuchAlgorithmException { MessageDigest md = MessageDigest.getInstance("SHA-256"); md.update(message.getBytes(StandardCharsets.UTF_8)); String checksum = Hex.encodeHexString(md.digest()); return checksum; } public static String getHMAC(String secretKey, String message) throws NoSuchAlgorithmException, InvalidKeyException { Mac sha256_HMAC = Mac.getInstance(HMAC_SHA256); SecretKeySpec secret_key = new SecretKeySpec(secretKey.getBytes(), HMAC_SHA256); sha256_HMAC.init(secret_key); String hash = Hex.encodeHexString(sha256_HMAC.doFinal(message.getBytes())); return hash; } }
Sample Code: C#
using System; using System.Net; using System.IO; using System.Text; using System.Globalization; using System.Security.Cryptography; namespace FileAPI { public class SigningTutorial { static public void Main() { // Task 1: get message body checksum (empty string if GET request) string messageBody = "sample content"; string bodyChecksum = SigningTutorial.GetChecksum(messageBody); // Task 2: Gather signature elements // First element string method = "POST"; // Second element string uri = "https://purchase.api.abebooks.com/v1/orders"; string encodedURI = SigningTutorial.UrlEncode(uri.ToLower()); // Third element string timeStamp = DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"); // Fourth element is the body checksum // Task 3: create the final string string finalString = method + "\n" + encodedURI + "\n" + timeStamp + "\n" + bodyChecksum; // Task 4: generate the request signature string secretKey = "EXAMPLE_SECRET_KEY"; string signature = SigningTutorial.GetHMAC(secretKey, finalString); // Task 5: submit the request WebRequest request = WebRequest.Create(uri); request.Method = method; // Set the headers string accessKey = "EXAMPLE_ACCESS_KEY"; request.Headers.Add("Abe-Date", timeStamp); request.Headers.Add("Abe-Access-Key", accessKey); request.Headers.Add("Abe-Signature", signature); request.Headers.Add("Abe-RequestId", Guid.NewGuid()); // Set the message body properties if (!string.IsNullOrEmpty(messageBody)) { byte[] messageBodyBytes = Encoding.UTF8.GetBytes(messageBody); request.ContentType = "application/json"; request.ContentLength = messageBodyBytes.Length; Stream newStream = request.GetRequestStream(); newStream.Write(messageBodyBytes, 0, messageBodyBytes.Length); } // Execute the method string result = null; using (HttpWebResponse response = request.GetResponse() as HttpWebResponse) { StreamReader reader = new StreamReader(response.GetResponseStream()); result = reader.ReadToEnd(); Console.WriteLine(result); // other handling... } } private static string GetChecksum(string message) { var encoding = new System.Text.ASCIIEncoding(); byte[] messageBytes = encoding.GetBytes(message); using (var sha256 = new SHA256Managed()) { byte[] hashbytes = sha256.ComputeHash(messageBytes); string hexhash = BitConverter.ToString(hashbytes).Replace("-", "").ToLower(); return hexhash; } } private static string GetHMAC(string secret, string message) { var encoding = new System.Text.ASCIIEncoding(); byte[] keyByte = encoding.GetBytes(secret); byte[] messageBytes = encoding.GetBytes(message); using (var hmacsha256 = new HMACSHA256(keyByte)) { byte[] hashmessage = hmacsha256.ComputeHash(messageBytes); string hexhash = BitConverter.ToString(hashmessage).Replace("-", "").ToLower(); return hexhash; } } } }