ProductName
Integration

Introduction

Our REST API is available at https://api.thetis-ims.com/prod .

Authentication

To access the API you first need to get an access token from our authentication server at https://auth.thetis-ims.com. The authentication scheme is OAuth2 with client credentials. The authentication endpoint is described here.

To authenticate you will need a client id and a secret. We will provide you with both by email. Please contact us at support@thetis-ims.zendesk.com to obtain a client id and a secret.

Authorization

On each request you must provide the access token acquired from the authentication server as ‘Authorization’ header. Furthermore, you must provide a ‘x-api-key’ header. You must generate the value of the ‘x-api-key’ from within the Thetis IMS application. We describe how to do that here.

The ‘x-api-key’ header value is specific to one area within a subscription. You may change the value of the ‘x-api-key’ from one request to another. This is only relevant if you are operating across multiple areas.

Areas are used differently by different subscribers. 3PL providers use areas to separate their customers from one another. Enterprises with multiple geographically separated warehouses use an area for each warehouse.

Limits

For each value of the ‘x-api-key’ header there are two limits attached:

A limit on the number of requests per second: 200

A limit on the number of requests per day: 100000

If these limits are exceeded, further requests are throttled.

Endpoints

Get a list of resources
GET /resource

You may add filter and pagination parameters to this type of endpoints. See further details below.

Get a single resource
GET /resource/{id}
Get a list of subordinate resources
GET /resource/{id}/subordinate-resource
Post a resource
POST /resource
Post a subordinate resource
POST /resource/{id}/subordinate-resource
Put an attribute of a resource
PUT /resource/{id}/attribute
Patch a resource
PATCH /resource/{id}

You should only include those attributes that you want to change.

Not all endpoints are available for all resources. Please consult our Postman documentation to see which endpoints that are available for which resources.

Resources

Below you will find a list of the resources available through the REST API. You may click on an item in the list to get a description of the resource and its attributes.

Our REST API only returns the bare data and no metadata whatsoever.

References from one instance of a resource to instances of other resources are always in the form of the unique id. So, if for instance you have an instance of the ‘globalTradeItems’ resource in hand, and that instance has a ‘productId’ field with a given value, then you may use that value to lookup the related product.

Filters

To filter the instances returned you may provide query parameters like this:

{filter-field}={filter-value}

Our Postman documentation shows which filters are available.

Pagination

All queries return a maximum of 1000 instances. To iterate through a larger set of instances you may provide pagination parameters like this:

maxNumRows=1000&firstRow=2000

With these query parameters your request will return 1000 rows starting with row number 2000.

Our Postman documentation shows several examples of this.

HTTP status codes

We do not use HTTP status codes to convey application errors. All requests that make it to the application will return HTTP status code 200. You therefore must check the body of the response. If it contains a message instead of the expected result, an error has occurred.

The error message contains a message code and a text. You can find several examples of error messages in our Postman documentation.

The use of HTTP status codes in a REST API is a hotly debated subject on the internet. The correct usage depends on whether one consider the application an integrated part of the web-server or a separate layer in the communication stack. Our stance is to consider the application a separate layer on top of the web-server.

Requests that fail to make it to the application layer will return the expected HTTP status codes. If for instance an authentication error occurs, the web server will return status code 403. If an internal error occurred on the web server, it will return status code 500. However, if an internal error occured within the application, the web server will return status code 200, and the response body will contain an error message.

Parsing the response body

When parsing the json response you must be aware that if a field has the value null in Thetis IMS, it might either be present in the response with the value null or it might be absent. In other words: Absence of a field signals that it has the value null.

When parsing the json response you must be aware that it might contain new fields. That is fields that were not described at the time of your implementation. Your parser should silently ignore these fields.

Further documentation

Postman

Our Postman documentation describes the endpoints of the interface and the request and response bodies. You can find it here.

Openapi 3

You can find a Openapi description here. If you copy and paste the content of the file into the editor at editor.swagger.io, you get a complete list of the endpoints available. You can invoke methods from the editor, and you can generate stubs for your integration program.

Authentication example

The following example show how we do authentication from our own client-side Java programs.

    private AuthenticationResponse authenticate() {
        try {
            URL url = new URL(protocol + "://" + authenticationHost  + "/oauth2/token");
            HttpURLConnection con = (HttpURLConnection) url.openConnection();
            try {
                con.setDoOutput(true);
                con.setRequestMethod("POST");
                String credentials = clientId + ":" + clientSecret;
                byte[] ba = credentials.getBytes("UTF-8");
                byte[] encodedCredentials = Base64.getEncoder().encode(ba);
                con.setRequestProperty("Authorization", "Basic " + new String(encodedCredentials));
                con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
                con.connect();
                OutputStream os = con.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");    
                osw.write("grant_type=client_credentials");
                osw.flush();
                osw.close();  
                return mapper.readAsJson(con.getInputStream(), AuthenticationResponse.class);
            } catch (IOException e) {
                return mapper.readAsJson(con.getErrorStream(), AuthenticationResponse.class);
            } finally {
                con.disconnect();
            }
        } catch (MalformedURLException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }