Purchase API - appendicies

Appendix A - Domain/currency mapping

DomainCurrency
AbeBooks.comUSD
AbeBooks.co.ukGBP
AbeBooks.itEUR
AbeBooks.frEUR
AbeBooks.deEUR
IberLibro.comEUR
ZVABEUR

Appendix B - Order Status Descriptions

Order StatusDescription
04Extra Shipping Accepted
05Ordered
14Item Unavailable
17Cancelled By Buyer
19Credit Card Rejected
24Refunded
35Shipped
53Max Price Exceeded
54Inactive Seller
90Extra Shipping Rejected
93Extra Shipping Requested

Appendix C - Response Status Codes

Status CodeDescription
2000Order status successfully retrieved
2002Dryrun succeeded
2003Duplicate request received for order currently being processed
2010Order created successfully

Error Codes

Status codeDescription
4000Malformed message
4001The credit card token provided did not match a credit card on your account
4002No listings were included with the request
4002One or more listings had a quantity less than 1
4002The total number of items ordered exceeded the limit of 250
4003Unable to parse JSON
4090Received duplicate RequestID with different content
4010Authentication failure
4011The Abe-Date header was missing
4012Unable to parse the Abe-Date header
4013Request expired
4014Invalid access key
4015Access key expired
4016The Abe-Signature header was missing
4017Invalid request signature
4018The Abe-RequestId header was missing or invalid
4030Not permitted to access
4220The request was malformed, details can be found in the response body
4293Too many requests with an invalid CCToken were made
4292Too many failed authentication attempts were made
4291Request exceeds rate limit
4041Order not found
4042Could not find the resource/malformed URI
4050HTTP method not supported
4060Requested mediatype not supported
4150Submitted mediatype not supported
5000Server error, this incident has been recorded
5030Server 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;
      }
    }
  }
}