OTTO Market API documentation

Partner API Developers' Guide

The Developers' Guide is targeted at developers and people with technical background who are already a partner of OTTO Market or are interested in becoming a partner. The aim is to help you as a partner of OTTO Market to connect to and to work with the OTTO Partner API. It describes some common implementation patterns and helps you to understand how processes work. Detailed information about the concrete interfaces can be accessed by clicking onto the single tabs.

Table of Contents

Technical Usage of the API

The following documentation describes how to use the API in technical terms. Provided environments are: - Non-live (a test/Sandbox) environment: - Live environment:

Authorization (OAuth2)

In order to fetch an authorization token you must have a registered user with a password. You can use the following cURL command to receive your token. Make sure you include your username and password in the command (without leading and trailing < >). curl -X POST \ https://<environment> \ -H 'Content-Type: application/x-www-form-urlencoded' \ -H 'cache-control: no-cache' \ -d 'username=<YourUsername>&password=<YourPassword>&grant_type=password&client_id=token-otto-api'

The resulting token of the request will look like the following example. The token itself can be extracted from the access_token value. { "access_token": "eyJhbGciOiJSUzI1NiIsInR5jdhstdheSldUIiwia2lkIiA6ICI4T1d6MjhuZ01GbHBURDl5TGtxQkRHMThuYXZNVFgyTWtqNVhkY0RITDBZIn0.eyJqdGkiOiI5OTM1NDk3OS1iNDdhLTQ3MzctOWYyMy0yNTMyMmI5MGVmYmMiLCJleHAiOjE1NTM3NjQ4NjMsIm5iZiI6MCwiaWF0IjoxNTUzNzYxMjYzLCJpc3MiOiJodHRwczovL2VzYi13cy5vdHRvLmRlL3NlYy1hcGkvYXV0aC9yZWFsbXMvcGFydG5lci1hcGktdGVzdCIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiI0MWUwNGQ1OS0xMTk0LTRiYjMtODhkYS1hYjRmNTk2NDkwZGUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwYXJ0bmVyLWFwaSIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjliNjk1ZDA1LTY5YzQtNDkwZS1hZGIzLTc2YWE5NmJmZjA0YyIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoiZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwYXJ0bmVyIjoiMTAwMDYyNCIsIm5hbWUiOiJTb3VsZXdheSIsInByZWZlcnJlZF91c2VybmFtZSI6IjEwMDA2MjQiLCJnaXZlbl9uYW1lIjoiU291bGV3YXkifQ.SleUexNdapaY5RmrVTbKRMiVpRrbNLjIUi7fILsW1hkpqQbX4IQRaSufSt98Ar0OkEmIvZvYPpGVecmjwYvD3YQzBmlcdU0V544Y0h8y01RyxZAYGZbRXfA1kOsFDucnrClCcj1JIaQMU4629wU9OM_SdQaLvfTA2l5prma94RekdWR3S-6DzXqJDtHrrcYS8BsfohkuLdi1U8vPUjwee9lsY3RTa9YZVekH4hFVWMl0Pbwub8jwum6zRjTu-ZAiLhZSnl8mSaMtrJFmkzRi3-s9eN7k0lnLKWGt7JuqZ_vbiJT8ZhHvPur4eLrY02ehF6-lwSUyjWMCzCi5TjBgYg", "expires_in": 3600, "refresh_expires_in": 1800, "refresh_token": "eyJhbGciOiJIUzI1NiIsInCIJdasFSldUIiwia2lkIiA6ICJhZTc1ZTI4Mi0wNTI5LTRjMTktYmE2MS1iNzNjNzk0NDg2MzMifQ.eyJqdGkiOiJmZWE2N2QwZC0xZDRjLTQwMmEtOWEyZi1iMDk4N2U4YWYyMTUiLCJleHAiOjE1NTM3NjMwNjMsIm5iZiI6MCwiaWF0IjoxNTUzNzYxMjYzLCJpc3MiOiJodHRwczovL2VzYi13cy5vdHRvLmRlL3NlYy1hcGkvYXV0aC9yZWFsbXMvcGFydG5lci1hcGktdGVzdCIsImF1ZCI6Imh0dHBzOi8vZXNiLXdzLm90dG8uZGUvc2VjLWFwaS9hdXRoL3JlYWxtcy9wYXJ0bmVyLWFwaS10ZXN0Iiwic3ViIjoiNDFlMDRkNTktMTE5NC00YmIzLTg4ZGEtYWI0ZjU5NjQ5MGRlIiwidHlwIjoiUmVmcmVzaCIsImF6cCI6InBhcnRuZXItYXBpIiwiYXV0aF90aW1lIjowLCJzZXNzaW9uX3N0YXRlIjoiOWI2OTVkMDUtNjljNC00OTBlLWFkYjMtNzZhYTk2YmZmMDRjIiwicmVhbG1fYWNjZXNzIjp7InJvbGVzIjpbIm9mZmxpbmVfYWNjZXNzIiwidW1hX2F1dGhvcml6YXRpb24iXX0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpbIm1hbmFnZS1hY2NvdW50IiwibWFuYWdlLWFjY291bnQtbGlua3MiLCJ2aWV3LXByb2ZpbGUiXX19LCJzY29wZSI6ImVtYWlsIHByb2ZpbGUifQ.NrMqpmzUNK6naLfd6g_4UE9jcuJDYrBDGpzpVyehNc8", "token_type": "bearer", "not-before-policy": 0, "session_state": "9b675d05-69c4-490e-aeb3-76aa96bff05c", "scope": "email profile" }

Calling an Endpoint

All endpoints are secured via authorization. You add the HTTP Authorization -Header with value Bearer ey... and will get access. curl -X GET \ \ -H 'Authorization: Bearer eyJhbGciOiJSUzI1NiIsInR5jdhstdheSldUIiwia2lkIiA6ICI4T1d6MjhuZ01GbHBURDl5TGtxQkRHMThuYXZNVFgyTWtqNVhkY0RITDBZIn0.eyJqdGkiOiI5OTM1NDk3OS1iNDdhLTQ3MzctOWYyMy0yNTMyMmI5MGVmYmMiLCJleHAiOjE1NTM3NjQ4NjMsIm5iZiI6MCwiaWF0IjoxNTUzNzYxMjYzLCJpc3MiOiJodHRwczovL2VzYi13cy5vdHRvLmRlL3NlYy1hcGkvYXV0aC9yZWFsbXMvcGFydG5lci1hcGktdGVzdCIsImF1ZCI6ImFjY291bnQiLCJzdWIiOiI0MWUwNGQ1OS0xMTk0LTRiYjMtODhkYS1hYjRmNTk2NDkwZGUiLCJ0eXAiOiJCZWFyZXIiLCJhenAiOiJwYXJ0bmVyLWFwaSIsImF1dGhfdGltZSI6MCwic2Vzc2lvbl9zdGF0ZSI6IjliNjk1ZDA1LTY5YzQtNDkwZS1hZGIzLTc2YWE5NmJmZjA0YyIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsib2ZmbGluZV9hY2Nlc3MiLCJ1bWFfYXV0aG9yaXphdGlvbiJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJtYW5hZ2UtYWNjb3VudC1saW5rcyIsInZpZXctcHJvZmlsZSJdfX0sInNjb3BlIjoiZW1haWwgcHJvZmlsZSIsImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJwYXJ0bmVyIjoiMTAwMDYyNCIsIm5hbWUiOiJTb3VsZXdheSIsInByZWZlcnJlZF91c2VybmFtZSI6IjEwMDA2MjQiLCJnaXZlbl9uYW1lIjoiU291bGV3YXkifQ.SleUexNdapaY5RmrVTbKRMiVpRrbNLjIUi7fILsW1hkpqQbX4IQRaSufSt98Ar0OkEmIvZvYPpGVecmjwYvD3YQzBmlcdU0V544Y0h8y01RyxZAYGZbRXfA1kOsFDucnrClCcj1JIaQMU4629wU9OM_SdQaLvfTA2l5prma94RekdWR3S-6DzXqJDtHrrcYS8BsfohkuLdi1U8vPUjwee9lsY3RTa9YZVekH4hFVWMl0Pbwub8jwum6zRjTu-ZAiLhZSnl8mSaMtrJFmkzRi3-s9eN7k0lnLKWGt7JuqZ_vbiJT8ZhHvPur4eLrY02ehF6-lwSUyjWMCzCi5TjBgYg'

The expected result has an HTTP 200 code with a probably empty list.

Rate Limiting

Requests are limited to 10 requests per second and client.

Timeouts and Defaults

Name Value Description
request timeout 25s The maximum HTTP request timeout for all interfaces
limit 128 The default for limit query parameter. See Paging. The default limit can be overwritten in specific interfaces.

Common Patterns

Interface Definition

Our REST interface definitions are basically using All interface definitions can be automatically used by you to generate necessary API objects and similar in your chosen implementation language. In order to remain technically extensible and up-to-date, individual interfaces may have been described in new or different definition schemes. We are constantly trying to keep all interfaces technically up to date.


The OTTO Partner API uses different versions for the single endpoints. The version number is included in the URL path. Semantic versioning scheme is used, but only the major version. Breaking changes are only introduced in new major versions. API version is required in all urls.

Endpoints may introduce new optional fields at any time in the request and any new fields in the response. The client must skip all unknown fields.

For every endpoint, a changelog exists which displays the latest released changes and the upcoming unreleased changes. Additionally, an overall Changelog exists with the most exciting changes about the API in general.

Supporting old versions

The OTTO Partner API would continue to support the old version of the API for 6 months from the time of public announcement for the new version of a given API.

Some common headers should be set by clients:

  1. Set the X-Request-Timestamp header within pattern: ^\d{4}-([0]\d|1[0-2])-([0-2]\d|3[01])T(2[0-3]|[01]?\d):[0-5]?\d:[0-5]?\d.[0-9]{1,3}[+-][0-2][0-9]:[0-5][0-9]$
  2. Set Accept to the desired response format e.g. application/json
  3. Set the Content-Type header to define the used format in the request body, only applicable if you send a request body

HTTP Methods

The interfaces describe which HTTP methods are allowed and how to use them. Our basic concern is that basically all HTTP Methods are allowed in the standardized way. Note that these methods should behave as specified by their standardized meaning (idempotency). The following is a description of a few special features, relevant facts or ways to use some of the HTTP methods.

Click to expand for details


POST will update specific fields and returns the result like a GET would do (error response is independent).


PUT will create or replace the whole entity independent of an existing entity.


PATCH will update specific fields and not return data like a GET would do (error response is independent). PATCH body is structured in the same way as PUT and POST (entity body). All fields added into your body will be updated, other fields will not be affected.

example: { "username" : "myusername", "email" : null }

HTTP Status Codes

We are using standardized HTTP status code with a body only if needed (it also just can be empty), but details about that you can find at the concrete interface implementation.

Verb Description
HEAD Can be issued against any resource to get just the HTTP header info.
GET Used for retrieving resources.
POST Used for creating resources.
PATCH Used for updating resources with partial JSON data. For instance, an Issue resource has title and body attributes. A PATCH request may accept one or more of the attributes to update the resource. PATCH is a relatively new and uncommon HTTP verb, so resource endpoints also accept POST requests.
PUT Used for replacing resources or collections. For PUT requests with no body attribute, be sure to set the Content-Length header to zero.
DELETE Used for deleting resources.

Error Message Style

Error messages are returned as content type "application/json;charset=utf-8" in the following format: { "errors": [ { "path": "/orders/1000331", "title": "Invalid Attribute", "code": "490", "detail": "First name must contain at least three characters.", "detail-structured": {...}, "jsonpath": "[@.orderid=='12345']/invoiceAddress/firstname", "logref": "key to find in the log" } ], "warnings": [ { "path": "/orders/1000331", "title": "Warning Attribute", "code": "WRONG_SPELLING", "detail": "Last name should start with big letter.", "detail-structured": {...}, "jsonpath": "[@.orderid=='12345']/invoiceAddress/lastname", "logref": "key to find in the log" } ] }

Field Mandatory Description
path yes called REST path
title yes short description of the error
code no internal error code (number or enum) of your application / domain (do not use the HTTP status codes)
detail no long description of the error, perhaps technical details
detail-structured no technical details in JSON structure
jsonpath no JSON field in request which caused the error
logref no reference key to find more stuff in the log (as example traceId)


All interfaces return a list with resources (orders, shipments...) and a next link if more entries exist. Use the next link to retrieve more entries.

For pagination, the basic query parameter "limit" (e.g. ?limit=10) can be used to define the maximum amount of resulting entities returned per call. The interface itself can reduce the limit lower than your client limit.

An example entity would be: { resources: [ { of the entity if all or some information will be provided directly..., links: [ { href: "/v1/orders/1234", <--- Link to single partner order rel: "self" } ] } ], links: [ { href: "/v1/orders?idGt=1234", <--- Link to next list of ressources. If not present, no more records exist, currently rel: "next" } ] }

Bulk requests

If you send a bulk request for an API endpoint, it will be processed asynchronously at the backend.

Synchronous Answer

Synchronously will be delivered an endpoint to check the asynchronous processing state. HTTP STATUS 202 (Accepted) { "task": { "href": "/interface/foo/123", "id": "123" } }

Check the State of an Endpoint

The client can follow the href to check the state of processing. An example entity would be: { "state": "pending", "message": "is running boy", "progress": "35", "total": "100", "pingAfter": "2019-05-01T13:25:12+0200", "links": [ { "rel": "self", "href": "/foo/bar/123" }, { "rel": "failed", "href": "/foo/bar/123/failed" }, { "rel": "succeeded", "href": "/foo/bar/123/succeeded" } ] }

Fetching files like PDF and CSV

Clients don't have to know the filetype that will be returned from a resource. Resources serving files will have the appropriate file extension in the URL as shown in the example below.

Request Headers GET /SomeInvoice.pdf HTTP/1.1 Accept: */*

Clients can find out the mime-type from the Content-Type header that will be sent in the response (e.g. application/pdf for PDF files and application/csv for CSV files).

Response Headers

HTTP/1.1 200 OK Content-Length: 514493 Content-Type: application/pdf

Imprint | Privacy policy | Datenschutz