API Documentation

Michael Lai edited this page Aug 18, 2014 · 34 revisions

Welcome

The Lexity App Platform for Ecommerce is only a few steps away. This guide is designed to help you understand Lexity's APIs and to figure out how to use Lexity in order to distribute your services and applications to SMBs from Shopify to Magento with a single development cost.


Lexity API Concept Overview

The Lexity API is a RESTful API implemented in JSON on top of HTTP. Lexity provides read-write access to a collection of ecommerce-related objects (e.g. products, orders, script tags) via the verbs GET/POST/PUT/DELETE. With these APIs, developers should be able to interact with store's products, monitor inventory, dynamically modify the store's website, etc., using one common API for stores on all platforms.

What we mean when we say Store

Lexity has integrations with a number of store platforms (Shopify, Magento, and many others) and has normalized the varied data provided by each of these platforms in order to create a representation of a Store. As an API developer, you will interact with a Lexity store, which in turn interacts with a store on any one of these platforms.

In the process of developing our cross-platform app store, we have seen the pain involved in figuring out how to get a list of products from the different (or non-existent) APIs of Shopify, Etsy and XCart. We know how difficult it is to get the owners of these websites to put a script tag in the correct place on their site, especially when the store template language differs and the template editor is located in entirely different places on, e.g., Magento and ProStores.

Lexity has persevered through this developer maze in order to create our own App Gallery. As a third-party app developer, you are the beneficiary of this—with our API, you don't even need to know the store's platform in order to write your application.

The one caveat about working with different store platforms is that they do not all provide the same features and abilities. To address this, Lexity has defined a set of Capabilities and Requests which in turn define the needs and wants of your application. Your requests of capabilities define which stores will be work properly with your application.

Cross-platform development using Capabilities and Requests

Each store platform has its own strengths and limitations, which we have codified into a set of Capabilities. The current list of capabilities in the Lexity API include:

Capability Description Notes
write_script_tag The ability to include a Javascript code snippet on every page of the store's website
read_script_tag The ability to determine if a Javascript code snippet (added via the write_script_tag capability) is on the store's website
separate_domain Whether the store has its own domain (the store’s url is "http://name.store.com" or "http://specific-store.com" instead of "http://marketplace.com/store-x")
read_products The ability to read data (product URLs, descriptions, inventory, etc.) about products from the store’s product catalog
write_products The ability to edit data (descriptions, inventory counts, etc.) about a product in the store’s product catalog coming soon
read_orders The ability to read the store’s order history coming soon

Capabilities are required for certain API calls, and performing certain API calls on a store that does not allow a capability will result in an error.

As an app-developer, you need to decide which capabilities your app needs in order to run properly. You can do this by looking at which of the API endpoints you intend to use. From the above list of capabilities, an app makes a certain requests for each capability. The type of request is one of the following:

Request Description
required The store must provide this capability in order for this application to work (but the capability need not be available immediately)
required_for_setup The store must provide this capability in order for this application to work. Furthermore, this capability must be "usable" immediately after app setup in order for the application to work at all.
optional This capability is not required in order for the application to work, but if the capability is provided, it will improve the functionality of the application.
(blank) If you don’t request a capability, then you do not need this capability. It also means that you have no guarantee on being able to use this capability.

Getting Access

Simply sign up for a developer account at the Commerce Central Developer Portal, and you'll have full access to our sandbox and APIs. From there, you're only a couple clicks away from creating a test application!


Getting Started with Lexity

Once you create an app on the Developer Portal, you'll be provided with an API secret and token which you will use to communicate with the Lexity API. The api secret is known only to you and to Lexity. Don’t share this secret; if someone gets a hold of your API secret, they can access and modify information about stores who have trusted you with their data.

For illustration in this section, we will explain how the sample application Sample App uses the Lexity API with api key sample_app_key, api secret sample_app_secret and welcome url http://sample-app.com/welcome.

In general, the api key and api secret are each random strings with 32 hex characters (looking something like 13d8740db918b4744f9d5514d55391be).

New Customer App Installations

A Lexity customer comes to the Lexity App Gallery and sees the Sample App listed. She decides to install the app for her store, http://example-store.com. By clicking on the button that says Add, she begins the process of installing your Sample App on her store's Lexity account.

At the end of the Lexity app installation process, we take the welcome url for your application and redirect the merchant to your website with a collection of parameters appended. For our example app installation, the merchant will be redirected to

http://sample-app.com/welcome?token=735c433875c919a4a7bc2b40e695b809&app_token=sample_app_key&store_url=http%3A%2F%2Fexample-store.com&pid=a123b456&timestamp=1346884490&signature=3f1e8aba4426ff6f5d5bf579a4204e60

The parameters are used to (a) give your application information about which store installed your app and to (b) give your application the appropriate credentials in order to access the Lexity API for this store. Note that the parameters are URL-encoded. The following table describes the parameters (after being URL-decoded):

parameter example value notes
token 735c433875c919a4a7bc2b40e695b809 The store connection token for Lexity API access this store
app_token sample_app_key Your api key
store_url http://example-store.com The URL of the store who just installed Sample App
pid a123b456 The unique store id of the store who just installed Sample App. We use the variables pid and store_id interchangeably.
timestamp 1346884490 A UNIX timestamp with the time of the redirect (in seconds since UNIX Epoch, midnight Jan-1-1970 GMT)
signature 3f1e8aba4426ff6f5d5bf579a4204e60 A signature used to verify that the request to your application is coming from Lexity
p BB optiona This is an optional parameter used internally for some platforms.
id aaa optional This is an optional parameter used internally for some platforms.

Note: You should be computing the signature for Commerce Central requests using ALL querystring parameters. New parameters may be added as we expand the functionality of the platform.

When URL-encoding and URL-decoding query parameters, Lexity uses Ruby's CGI library. Most standard URL encoding and decoding libraries are directly compatible with this.

Verifying Lexity Redirects with Signatures

When Lexity redirects a merchant to your application, it will include query parameters to help you identify the store and the application and also to validate the request.

With your api key, api secret and the provided signature, you should use the following procedure to validate the authenticity of the incoming request:

  1. Collect all URL query parameters (not including the signature) and URL-decode them.
  2. For each parameter and value, construct the string "parameter=value".
  3. Construct a new string called sorted_params by sorting these "parameter=value" strings and concatenating them together (with no delimiter).
  4. Your calculated signature is the hex digest of the md5 hash of the string with your sorted_params appended to the end of your app_secret.
  5. Ensure that the provided signature in the query string equals the calculated signature; if so, this request is legitimately coming from Lexity.

Your sort function should match Ruby's default string comparison order, which is case-sensitive and ascending.

In Ruby, use the following code to calculate the signature

require "digest/md5"
require "cgi"

def signature(app_secret, parameters)
  sorted_params = parameters.collect{|k,v| "#{k}=#{v}"}.sort.join
  Digest::MD5.hexdigest(app_secret + sorted_params)
end

def valid_signature?(query_params)
  provided_signature = query_params.delete("signature")
  query_params.each{|k,v| query_params[CGI.unescape(k)] = CGI.unescape(v)}
  provided_signature == signature("sample_app_secret", query_params)
end

# Assume that the query parameters arrive in a hash (while still url-encoded), like:
query_params = {
 "token" => "735c433875c919a4a7bc2b40e695b809",
 "app_token" => "sample_app_key",
 "store_url" => "http%3A%2F%2Fexample-store.com",
 "pid" => "a123b456",
 "timestamp" => "1346884490",
 "signature" => "3f1e8aba4426ff6f5d5bf579a4204e60"
}

In fact, whenever Lexity redirects a logged in merchant with your app installed to any "in-app" url on your website, all of these query parameters will be attached to the URL, and you should validate the request with the same procedure. The following are examples of when Lexity sends merchants to your site:

  • When a merchant finishes installing your app and goes to your welcome url http://sample-app.com/welcome, the merchant will go to http://sample-app.com/welcome?app_token=sample_app_key&token=...
  • When a merchant clicks to go to use your app and goes to your home url http://sample-app.com/home, the merchant will go to http://sample-app.com/home?app_token=sample_app_key&token=...

Using the API: Authentication

You always need to provide three pieces of information when making API calls: the store's unique id (store_id), your app's api_token, and a store_connection_password for this store.

The api_token is provided to you when your application is registered with us. The store's store_id is sent to you within the query parameters as the value with parameter pid and is described further in the section Verifying Lexity Redirects with Signatures above. The store_connection_password for your app's API usage on behalf of the store with a given store_id should be generated from these same query parameters.

To generate the store_connection_password for API access using this store, you take the token query parameter (also referred to as the store_connection_token) and calculate the hex digest of the md5 hash of the string with the api secret appended to the end of the token. In Ruby, the function that calculates the store_connection_password looks like the following:

require "digest/md5"

def store_connection_password(store_connection_token, api_secret)
  Digest::MD5.hexdigest(store_connection_token + api_secret)
end

Using the API: Basics

In this and all following sections, strings {wrapped_in_braces} indicate parameter substitutions, and code strings [in_square_braces] are optional.

Authentication against the API uses HTTP basic authentication. With a store_id, api_token and store_connection_password, the base URL (base_url) for all API calls is

https://{api_token}:{store_connection_password}@api.lexity.com/v1/store/{store_id}

Lexity also provides access to a Sandbox API server for your testing purposes. With a separate sandbox_store_id, sandbox_api_token and sandbox_store_connection_password, the base URL for all Sandbox API calls is

https://{sandbox_api_token}:{sandbox_store_connection_password}@sandbox-api.lexity.com/v1/store/{sandbox_store_id}

The API is implemented as JSON over HTTPS, following the REST principles as much as possible. This means that:

  • every object (product, script tag, order, etc.) has an id
  • every object (product, script tag, order, etc.) has a unique URL
  • communication is stateless

It is rather simple to construct the URL of the API call based on the Object you want to interact with and the type of request you're making. The specific request is

{HTTP_METHOD} {base_url}[/{pluralized object name}[/{request specifier}]].{format}[?{conditions}]

Every request is always bound to a Store. If you want information about that store, you do not specify an object name (i.e. if {pluralized object name} is missing, you are referencing the Store).

  • The parameter HTTP_METHOD is one of GET,POST,PUT,DELETE based on the semantics of the REST operation you are using. Generally GET will give you information about object(s), POST will create new object(s), PUT will modify existing object(s), and DELETE will delete object(s).

  • The {request specifier} is either count, indicating that you want to count the number of objects satisfying some conditions, or {object_id}, indicating that you want to act on an object with a given id.

  • Because we only support the JSON format at this point, format will be json. In particular, for POST and PUT requests you will have to set the Content-Type header to be application/json in order for the server to interpret your data correctly.

  • The {conditions} are only used in GET requests, to filter the object(s) according to some parameters. Each object defines a set of allowable conditions and is in the object-specific documentation under the section "Query Parameters Available for this Object".

A few examples of constructed API calls are:

  • Get information about a store:
    GET https://{api_token}:{store_connection_password}@api.lexity.com/v1/store/{store_id}.json

  • Get information about products in a particular collection:
    GET https://{api_token}:{store_connection_password}@api.lexity.com/v1/store/{store_id}/products.json?collection_id={collection_id}

  • Modify information about an existing product:
    PUT https://{api_token}:{store_connection_password}@api.lexity.com/v1/store/{store_id}/products/{product_id}.json

  • Count the total number of products for a store created since 1-Jan-2012:
    GET https://{api_token}:{store_connection_password}@api.lexity.com/v1/store/{store_id}/products/count.json?created_at_min=2012-01-01

  • Add a script tag to this store:
    POST https://{api_token}:{store_connection_password}@api.lexity.com/v1/store/{store_id}/script_tags.json

  • Remove a script tag from this store:
    DELETE https://{api_token}:{store_connection_password}@api.lexity.com/v1/store/{store_id}/script_tags/{script_tag_id}.json

Using the API: Calls and Call Limits

When an API request is successful, the data is returned along with the HTTP status code and status message 200 OK or 201 Created. Other status codes indicate errors in your API call:

  • 403 Forbidden - Indicates that the API call is not authorized. Double check your api_token, store_connection_password and store_id.

  • 503 Service Unavailable - Indicates that you are over the limit for API calls.

With every successful API call, Lexity returns a header HTTP_X_LEXITY_STORE_API_CALL_LIMIT with the value {n}/{m} where n represents the number of calls made within the last 5 minutes, and m represents the call limit. Unless otherwise arranged, app developers are allowed to make 500 API calls every 5 minutes.

Using the API: Specific Object Reference

Go to the following pages for specific documentation for the different Objects you can interact with:

APIs for more Objects are coming soon.

Using the API: App Uninstallations

Access to the API on behalf of a store is only valid while the app is installed on Lexity. If the app is uninstalled on Lexity, any validated API call will return the response

HTTP/1.1 403 Forbidden

{
  "errors": "Store has uninstalled your app"
}

Using the API: Testing in CURL

We love CURL. Here's a sample call you can make with curl to test whether your combination of store_id, api_token and store_connection_password are valid (keeping [sandbox-] in the URL if you're testing against the sandbox):

curl -X GET -H 'Content-Type: application/json' 'https://{api_token}:{store_connection_password}@[sandbox-]api.lexity.com/v1/store/{store_id}.json'