Introduction

The UltraCart API is organized around REST and JSON. Our API uses cutting edge REST API functionality to deliver resource-oriented URLs that are efficient at exposing the maximum amount of functionality in an easy to use interface. Our APIs are all defined using the OpenAPI (Swagger) specification which allows us to provide generated client libraries and documentation that are always accurate and efficient to program against. Whenever possible, JSON is the format for the request and the response of our APIs and our client libraries convert the information into language specific objects.

Authentication

Our APIs support two primary methods of authentication:

OAuth 2.0 authentication is the industry standard way of authenticating a third party application, such as a plugin, to an UltraCart account with a limited set of permissions. If you're developing an application that is going to be used by multiple merchants, then OAuth 2.0 authentication is appropriate.

Simple key authentication is exactly what it sounds like. A simple key that is generated by the system and is useful for authenticating API calls for your organization. If you're developing an in-house application to automate interactions with UltraCart, then simple key authentication is the appropriate mechanism to use.

All of the client libraries generated for the UltraCart REST API support both methods of authentication.

OAuth 2.0

Authenticating with OAuth 2.0 involves having the end user client the authorization link. The URL contains the client ID for your Developer Application, redirect information (optional), the request type of code and a random number. When the user clicks the link, they are taken to the UltraCart login page. The user must login first, then they are shown a page about your application, the permissions it is requesting, and are given the chance to approve or deny it. If they approve the application then their browser is redirected to a page which takes the code parameter from the URL and then calls the OAuth /token REST API to exchange the temporary authorization code for a more permanent access token. More details of how to configure an OAuth application are provided on the OAuth resource page.

Simple Key

The simple key authentication is by far the simplest. When you create a new application under

Configuration -> Back Office -> Authorized Applications

and choose simple key as your authentication scheme, a very long key is generated for your application to use. This key is easily specified when instantiating the API. If you're doing individual internal development, use this authentication scheme.

All API requests must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.

If you're application is running from a known IP address, we encourage you to also restrict API calls to that particular IP address as an added security measure.

Date/Times

All of the date/time objects within our REST API are String variables in the format ISO-8601. This is the standard format utilized by the OpenAPI specification, but it also provides another host of benefits, including:

Errors

UltraCart uses conventional HTTP response codes to indicate the success or failure of an API request. In general, codes in the 2xx range indicate success, codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, a value is inappropriate, your requests are happening at too fast a rate, etc.), and codes in the 5xx range indicate an error with UltraCart's servers (these are rare). Most API responses will contain the following attributes:

AttributeData Type
successboolean
errorError

In addition to returning a non-2xx HTTP response code, the response body will be a JSON object with these particular fields populated. This allows you a more granular understanding of the error that is returned.

Expanding Objects

In order to limit the size of the responses and the number of API calls to the server, UltraCart supports expanding of certains objects through the _expand query parameter. The best example of expansion is the item object because they contain a large amount of data. Often times programs want to query an item, but only a portion of it, make a change, and then update the item. REST expansion allows you to indicate how you want to the object expanded beyond the basic object on the retrieval request. This reduces the need to make additional API calls to fetch deeper information as most REST APIs require. Then on the update API calls, if the object is only partially expanded then only those portions of the object are updated. The rest of the object that exists on the server is left alone. Using REST expansion will:

Each REST API that supports expansion will have the _expand parameter documented on the API call. The corresponding create/update REST APIs will handle receiving the partially expanded object without any special action on your part.

You will also see the exact same expansion syntax used on the _expand parameter is also used in our webhook configuration to specify the amount of expansion for the objects that you receive notices on.

Here is an example of a real-world _expand parameter from a wordpress plugin.

_expand=pricing,shipping.distribution_centers,content.multimedia.thumbnails[filter(100,100,"png", true),filter(360,360, "png", true)]

The sample expansion above tells the system that the call is interested in:

Basic Item Response

{
    "merchant_item_oid": 875851,
    "merchant_id": "DEMO",
    "merchant_item_id": "Baseball Bat",
    "description": "Wood Baseball Bat",
    "description_translated_text_instance_oid": 649867,
    "last_modified_dts": "2016-08-11T16:14:46-04:00",
    "creation_dts": "2009-01-14T18:30:42-05:00"
}

Expanded Item Response

{
    "merchant_item_oid": 875851,
    "merchant_id": "DEMO",
    "merchant_item_id": "Baseball Bat",
    "description": "Wood Baseball Bat",
    "description_translated_text_instance_oid": 649867,
    "last_modified_dts": "2016-08-11T16:14:46-04:00",
    "creation_dts": "2009-01-14T18:30:42-05:00",
    "pricing": {
        "cost": 5.50
    },
    "shipping": {
        "distribution_centers": [{
            "distribution_center_oid": 29522,
            "distribution_center_code": "DFLT",
            "inventory_level": 4,
            "handles": true,
            "allocated_to_placed_orders": 2,
            "allocated_to_shopping_carts": 0,
            "available_to_allocate": 2
        }]
    },
    "content": {
        "view_url": "http://www.testajax.com/catalog/DEMO/products/facebook/fb-single/Baseball Bat.html",
        "multimedia": [{
            "merchant_item_multimedia_oid": 239393,
            "file_name": "baseballbat.jpg",
            "description": "Baseball Bat",
            "url": "//secure.ultracart.com/itemmultimedia/DEMO/BASEBALL BAT/baseballbat.jpg",
            "type": "Image",
            "code": "default",
            "width": 108,
            "height": 120,
            "cloud_url": "https://s3.amazonaws.com/ultracart/im/E5DECF2DBFEDB40123A559FCAC631600?AWSAccessKeyId\u003d0P4TXH5AKGYC8WHDZFG2\u0026Expires\u003d1472837012\u0026Signature\u003dZ6mQqdhUWl3g1kbD%2B4wTT1AWvRc%3D",
            "cloud_url_expiration": "2016-09-02T13:23:32-04:00",
            "thumbnails": [{
                "height": 100,
                "width": 100,
                "http_url": "http://ultracartthumbs.s3.amazonaws.com/1363101689475/DEMO/0/1/100-100-01C192A2E7695865D44C6C51ECE91A29.jpg",
                "https_url": "https://s3.amazonaws.com/ultracartthumbs/1363101689475/DEMO/0/1/100-100-01C192A2E7695865D44C6C51ECE91A29.jpg",
                "square": true
            }, {
                "height": 360,
                "width": 360,
                "http_url": "http://ultracartthumbs.s3.amazonaws.com/1472069542543/DEMO/0/1/360-360-01C192A2E7695865D44C6C51ECE91A29.jpg",
                "https_url": "https://s3.amazonaws.com/ultracartthumbs/1472069542543/DEMO/0/1/360-360-01C192A2E7695865D44C6C51ECE91A29.jpg",
                "square": true
            }]
        }]
    }
}

Object Identifiers

As with many enterprise application, internal objects are often assign an object identifier, oid for short, that is unique to each object of a given type. Throughout the REST API specification you will see pairs of fields that provide the object identifier as well as the human friendly identifier. Let's take a look at ItemShippingPackageRequirement model. This model contains two fields:

If you're trying to assign a package to an item for shipping then you're going to need to create an ItemShippingPackageRequirement object.
You may not know the oid of that particular package object, but that is OK. You can just specify the name and the system will automatically resolve the oid value. Don't make a value for an OID or set it to zero. You will receive an error back from the server.

Another scenario is removing an identifier to a child object during an update. Take the ItemAutoOrder model for example which has the following fields:

When configured, this setting tells the system to charge the customer with a given item, typically a cancellation fee, when they cancel their auto order.
If you want to remove this setting with a REST API call, you will need to null out BOTH fields before making the update. The oid field is what the system truly cares about, but if you null only that field then the system will resolve the oid using the companion field such as auto_order_cancel_item_id.

Pagination

Some resources in UltraCart are capable of having so many objects that it's not feasible to return them on a single API call. To accommodate these objects in an efficient manner, paging of the result set is used. The response from an API that uses paging will have the following information

If a response indicates that additional records are available in the more field, then a subsequent request should be made with the _offset parameter set to next_offset.

Most API calls will utilize a default result set limit of 100. While this can be increased to reduce round trips, we recommend keeping the limit at the default. UltraCart reserves the right to return a 400 - Bad Request response if the size that you request is larger than we want the system to handle a single chunk. An upper limit on an API can be further reduced at any point in time if it is over 100 at the discretion of our system administrators in order to maintain optimal system performance.

Rate Limiting

For authenticated requests, you can make up to 1,000 requests per hour and 10,000 per day by default. This limit is enforced by authorized application as well as IP address. The algorithm is implemented as a leaky bucket so there is no fixed reset time. If you exceed the maximum number of requests within the time period you will receive a 429/Too Many Requests response from the API call.

Do NOT perform concurrent requests by application or IP to the UltraCart system or you will also receive a 429/Too Many Requests response.

If you need an increase in you rate limit, please contact UltraCart support, but expect a thorough review of your integration and push back to make sure that your integration workflow is optimal before any increase is granted. For example if you are breaching the hourly rate limit, we are going to recommend that you spread the workload out over 24 hours. Make use of Webhooks to receive notifications of changes instead of wasting API calls polling the system. Only perform updates to objects when necessary. Cache the responses within your system locally and update that cache based upon a webhook notification.

Abuse Rate Limits

To protect the quality of service from UltraCart, additional rate limits may apply to some actions. For example, rapidly creating content, polling aggressively instead of using webhooks, making API calls with concurrency, or repeatedly requesting data that is computationally expensive may result in abuse rate limiting.

It is not intended for this rate limit to interfere with any legitimate use of the API. Your normal rate limits should be the only limit you target. Please contact UltraCart Support if your use is affected by this rate limit.

Request IDs

Every request to a REST API returns a X-UltraCart-Request-Id header that contains a unique request ID value. You can log this value and subsequently review the complete request/response log for the API call under the Authorized Applications logging located under Configuration -> Back Office -> Authorized Applications.

UltraCart retains up to 10,000 log requests for API calls for up to 31 days.

Sorting Results

Methods that allow for more than one object to be returned will generally supply a _sort parameter that allows you to specify the order in which the results are returned. For example orders can be sorted by the following fields:

As with most data set sorting routines there is an ascending and descending option. So to sort the result set by billing last name (ascending) followed by billing first name (ascending) you would use the following _sort parameter.

+billing.first_name,+billing.last_name

If you wanted to find the most recent orders then you would sort by the creation_dts in a descending fashion with:

-creation_dts

WARNING: ALWAYS URL encode parameters! If you fail to URL encode the plus character then you are going to receive a bad request error for an improper sort attribute.

Standard Responses

We strive for all our responses to have a standard response envelope. This guarantees that the interaction style for all REST APIs will feel similar. The standard response object will have the following properties.

PropertyData TypeDescription
successbooleanWhether or not the REST API was successful.
errorErrorIf the API call was unsuccessful, this error object will contain further details.
metadataResponseMetadataDetails about the response such as the payload_name and result_set. The result_set will contain information about paged results such as count, offset, limit and a more flag.

Versioning

We strive to provide stable APIs that can operate over a long time period, but still maintain enough flexibility to improve and adapt the API over time. To accomplish stability in the API, we accept a custom HTTP header to indicate which publication date of the API you are requesting.

X-UltraCart-Api-Version: 2017-03-01

The current version of the API is 2017-03-01. As we enhance the API the object model may evolve slightly. By tracking the api version date that your client supports, we can maintain backwards compatibility.

Each language SDK will provide an example of how to add a default header that will be transmitted with each API call to make specifying the API version simple. See the individual resource for more details.

Requests will FAIL if a X-UltraCart-Api-Version is not specified.

Webhooks

A Webhook is an asynchronous HTTPS callback to an external server to notify it of events that the external party is interested in. The external party that is interested in receiving the notification will implement an end-point to receive the JSON based notifications as they occur. Since webhooks are an outbound process from UltraCart to the external party they happen quicker and are far more efficient than polling an API.

All Webhooks are associated with a Resource API such as "item" and are triggered for a defined set of events that the receiver has subscribed to. Each resource will describe the webhooks that are available to subscribe to, the REST model that is delivered in the notification as well as the expansion operations that are also allowed.

For security purposes, we always recommend that your Webhook endpoint URLs be secured with HTTPS. This is not a requirement for certain resource types, such as items, but it is required whenever any customer information is transmitted to your server.

UltraCart expects that integrations will respond within thirty seconds of receiving the webhook payload. Therefore you should favor asynchronous processing of the payload vs synchronous processing whenever possible. By receiving the payload and queuing it so that all the "real work" happens in a background job, you ensure fast response times for the webhook delivery and buffering of your server against a large amount of notices. There are various ways to queue background jobs depending upon your language such as writing the webhook payload to a database table and then processing in a scheduled job or utilizing a message queueing libraries such as Resque (for Ruby), RQ (for Python), or RabbitMQ (for Java) for example. When configuring the Webhook, there are optional limits on the number of event notifications that can be bundled together, the minimum is 10, and the maximum size of the payload (900K/message maximum). The maximum limits allow for further tuning of the amount of work that is delivered to your server per HTTPS POST.

UltraCart currently makes a single concurrent notification at a time to each of the Webhook endpoints. Notifications generally are delivered in and oldest to newest order. All webhooks receive a fair shot of delivery of their notifications each processing cycle. So if one merchant generates a lot of notifications (through an item import for example), the system will make sure that their notification workload does not adversely impact the delivery of notifications for other merchants.

If your server goes down for a brief period of time, UltraCart will queue up the pending notifications and retry them. If your server encounters errors or down time for an extended period of time, UltraCart will begin discarding the older notifications in the queue as newer ones arrive until ultimately the webhook is disabled.

For consistency, each Webhook configuration will determine the API version that the notifications should conform to. By versioning the outbound webhook notices in the same fashion as the inbound API calls, we can guarantee more stability in the API. It also allows you to parse the webhook JSON that you receive into an SDK object.

While UltraCart strives for very fast delivery of Webhook notifications, there are no guarantees on the time frame between the triggering of the event and the actual delivery of the notification. It can be as short as a few milliseconds at times, but you should not build any business workflow that is critically dependant upon the speed of webhook delivery.

If you're still wondering about the importance of Webhooks, look at a real-world example of their use in the Wordpress plugin. When the plugin is first authorized via OAuth 2.0 authentication, it sets up a webhook with three item events (item_create, item_update, and item_delete) so that all changes to the item information are quickly conveyed to the wordpress instance. After the webhook is created, the plugin makes another API call asking UltraCart to reflow all item_update events. UltraCart in an asynchronous and controlled fashion resends all the existing items from the UltraCart account to the wordpress plugin's webhook endpoint. Two API calls setup and trigger the entire process and no polling is required after that point.