diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 0000000..39d42f6
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,30 @@
+name: convert
+
+on:
+ push:
+ tags:
+ - 'v*'
+
+
+jobs:
+ buildrelease:
+ name: Build and release artefacts
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v3
+
+ - name: Convert MD to PDF and HTML
+ run: |-
+ npm install -g md-to-pdf
+ mkdir -p _output
+ find . -name "*.md" ! -name "README.md" ! -name "CONTRIBUTING.md" ! -path "./_output/*" | sort -n | while read file; do cat "$file"; echo "
"; echo; done > ./_output/otto-retail-api-guidelines.md
+ md-to-pdf ./_output/otto-retail-api-guidelines.md
+ md-to-pdf --as-html --config-file ./.github/workflows/config.json ./_output/otto-retail-api-guidelines.md
+
+ - name: Release
+ uses: softprops/action-gh-release@v1
+ with:
+ files: |
+ ./_output/otto-retail-api-guidelines.html
+ ./_output/otto-retail-api-guidelines.pdf
diff --git a/.github/workflows/config.json b/.github/workflows/config.json
new file mode 100644
index 0000000..7df53f7
--- /dev/null
+++ b/.github/workflows/config.json
@@ -0,0 +1,3 @@
+{
+ "css": "body { margin: 15px}"
+}
diff --git a/01_getting-started/01_introduction.md b/01_getting-started/01_introduction.md
new file mode 100644
index 0000000..445c283
--- /dev/null
+++ b/01_getting-started/01_introduction.md
@@ -0,0 +1,16 @@
+# OTTO RETAIL-API - Getting Started
+
+## Introduction
+The OTTO Retail-API uses standard [HTTP semantics](https://httpwg.org/http-core/draft-ietf-httpbis-semantics-latest.html) as well as OAuth 2.0 for authentication and authorization and returns [JSON-encoded](http://www.json.org/) responses.
+We support secure communication and require client applications to implement TLS 1.2 or higher.
+
+With this [endpoint](https://keycloak.apps.otto.de/sec-api/auth/realms/retailapi-prod/.well-known/openid-configuration) for [OAuth 2.0 endpoint discovery](https://tools.ietf.org/html/draft-ietf-oauth-discovery-06)
+you can use the returned information to obtain details about the OAuth 2.0 authorization server, such as endpoints for token and user information, as well as the supported OAuth 2.0 flows.
+
+The OTTO Retail-API sandbox environment allows API testing without affecting or interacting with your live data.
+The base URL for your requests determines whether the request is executed in the production or sandbox environment.
+The following base URLs are available for all resources:
+
+* Production base URL: https://retail-api.otto.de
+* Sandbox environment base URL: https://retail-api-sandbox.otto.de
+
diff --git a/01_getting-started/02_authentication.md b/01_getting-started/02_authentication.md
new file mode 100644
index 0000000..7f56f13
--- /dev/null
+++ b/01_getting-started/02_authentication.md
@@ -0,0 +1,119 @@
+## Authentication
+
+The OTTO Retail-API uses OAuth 2.0 for authentication and authorization on all endpoints and does not handle unauthenticated requests.
+We only support the OAuth 2.0 flow **Client Credentials Grant**.
+
+In order to make requests to the OTTO Retail-API, you first need to obtain an access token for your application.
+
+As proposed in the [RFC 9068 - JSON Web Token (JWT) Profile for OAuth 2.0 Access Tokens](https://datatracker.ietf.org/doc/html/rfc9068), the access tokens used for the OTTO Retail-API are JWTs, as defined in [RFC 7797](https://tools.ietf.org/html/rfc7797).
+
+
+> :warning:
+The grant flow Client Credentials require your client secret.
+Make sure that your client secret is not included in your distributed code, compiled apps, or public JavaScript.
+
+The OTTO Retail-API provides the following token endpoints:
+
+| Endpoint | Description |
+|------------------------------------------------------------------------------------------------| ---------------------------------------------- |
+| https://keycloak.apps.otto.de/sec-api/auth/realms/retailapi-prod/protocol/openid-connect/token | Endpoint for token retrieval. |
+| https://keycloak.apps.otto.de/sec-api/auth/realms/retailapi-prod/protocol/openid-connect/auth | Endpoint for authentication and authorization. |
+
+Although you can expect that the tokens have the TTL (time to live) described below, we still recommend that you always check the actual expiry time by inspecting the `exp` claim of the JWT.
+
+Access token TTL: 5 minutes
+
+### Client Credentials Grant
+
+With the Client Credentials Grant access token, your application receives direct access to all relevant resources that are not tied to specific users.
+See [Client Credentials Grant](https://www.rfc-editor.org/rfc/rfc6749#section-4.4) for details.
+
+#### Obtaining an access token
+
+You receive an access token through a POST request containing your client ID and client secret in the request body.
+Keep in mind that this information is set during the initial client registration process via the OTTO Supplier Connect.
+
+The following table shows the required parameters for this request:
+
+| Parameter | Description |
+| ------------- | -------------------------------------------------------------------------- |
+| grant_type | Use `client_credentials` for this request. |
+| scope | A space-separated list of requested scopes. |
+| client_id | Your client ID. Mandatory if you do not use HTTP basic authentication. |
+| client_secret | Your client secret. Mandatory if you do not use HTTP basic authentication. |
+
+
+Example request:
+
+```http
+POST https://keycloak.apps.otto.de/sec-api/auth/realms/retailapi-prod/protocol/openid-connect/token HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+
+grant_type=client_credentials
+&scope=products orders
+&client_id=
+&client_secret=
+```
+
+Example of a successful token response:
+
+```http
+HTTP/1.1 200 OK
+Content-Type: application/json
+Cache-Control: no-store
+
+{
+ "access_token": "",
+ "token_type": "bearer",
+ "expires_in": 299,
+ "scope": "products orders",
+ "jti": "1e559445-21df-4f01-a9de-e55ab519b2c3"
+}
+```
+
+Here's some info about the access token response properties:
+
+| Property | Description |
+|----------------|----------------------------------------------------------------------------------------------------------------|
+| `access token` | Contains the access token, that you need to include in all further API requests in the `Authorization` header. |
+| `token_type` | Identifies the type of the token. |
+| `exp` | Specifies the timestamp after which the access token expires. |
+| `scope` | Contains a space-separated list of all granted scopes. |
+| `jti` | Contains a unique identifier of the access token. |
+
+
+#### Making authorized requests
+
+To make an authorized request to the OTTO Retail-API, add the `Authorization` header containing your access token to the HTTP request.
+You can only access the resources with the scopes for which you initially registered your client.
+
+Example request:
+
+```http
+GET /products/ HTTP/1.1
+Authorization: Bearer
+Accept: application/hal+json;profile="/product/product+v1"
+```
+
+If a request fails, the API returns an error response with an HTTP status code, and an error object with `error` and `error_description` parameters:
+
+```http
+HTTP/1.1 401 Unauthorized
+Content-Type: application/problem+json
+Cache-Control: no-store
+
+{
+ "type": "about:blank",
+ "title": "Unauthorized",
+ "status": 401,
+ "detail": "Authentication is required, but has failed or has not yet been provided."
+}
+```
+
+The API responds as follows:
+
+| Response | Possible cause and solution |
+|------------------------------| ------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| **Code**: 401 UNAUTHORIZED | A possible cause might be a missing authorization header or incorrect credentials. |
+| **Code**: 403 FORBIDDEN | Access to the requested resource is not allowed, because the access token is invalid or expired.
A possible solution is refreshing the access token. |
+
diff --git a/01_getting-started/03_scopes.md b/01_getting-started/03_scopes.md
new file mode 100644
index 0000000..4e1c776
--- /dev/null
+++ b/01_getting-started/03_scopes.md
@@ -0,0 +1,15 @@
+## Scopes
+
+We protect access to our resources and restrict access to the OTTO Retail-API by using OAuth 2.0 scopes.
+Scopes allow you to specify which permissions your client application requires.
+
+Currently, all scopes are automatically assigned to your client with your initial request for API access.
+Find more information on how to get API access [here](https://github.com/otto-de/retail-api-hub-documentation).
+
+Here is an overview of all available business scopes:
+
+**Production:**
+- products
+
+**Sandbox:**
+- products-sandbox
diff --git a/02_about-the-api/01_api-operations.md b/02_about-the-api/01_api-operations.md
new file mode 100644
index 0000000..c1acf15
--- /dev/null
+++ b/02_about-the-api/01_api-operations.md
@@ -0,0 +1,21 @@
+# About the API
+
+## API operations
+
+To build a REST request, combine the respective HTTP method with the following information:
+
+- OTTO Retail-API base URL
+- Resource URI with replaced path parameters
+- Valid access token
+- Request headers (operation-specific)
+- Request body (operation-specific)
+
+For example:
+
+```http
+POST /products/ HTTP/1.1
+Host: https://retail-api.otto.de
+Authorization: Bearer
+Content-Type: application/hal+json;profile="/product/product+v1""
+Accept: application/hal+json;profile="/product/product+v1""
+```
diff --git a/02_about-the-api/02_http-methods.md b/02_about-the-api/02_http-methods.md
new file mode 100644
index 0000000..6a086a4
--- /dev/null
+++ b/02_about-the-api/02_http-methods.md
@@ -0,0 +1,12 @@
+## HTTP methods
+
+We are compliant with the standardized HTTP semantics and use the HTTP request methods `GET`, `POST`, `PUT`, `PATCH`, `DELETE` and `OPTIONS` throughout the API.
+
+| Method | CRUD | Description |
+| :-------: | :-------------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `GET` | Read | Retrieve either a single or a collection resource. Successful `GET` requests return `200 OK`. For a collection resource, `GET` requests also return `200 OK` if the collection is empty. If a single or collection resource is missing, the API returns `404 Not Found` or `410 Gone`.
In case of a `404 Not Found`, check the structure of your query and the name of the requested endpoint and resource. |
+| `POST` | Create | Create a single resource on a collection resource endpoint. Successful `POST` requests either return `200 OK` if the resource already exists, or `201 Created` if a new resource was created. In case of `201 Created` the `Location` header of the response contains the URI of the new resource. The request returns `202 Accepted` after it was accepted but not yet completed. In exceptional cases the request returns `204 No Content` with a `Location` header containing the URI of the new resource.
In error cases the request returns `422 Unprocessable Entity` for semantically malformed or `400 Bad Request` for syntactically malformed requests. |
+| `PATCH` | Update/Modify | Update parts of a single resource. Successful `PATCH` requests return `200 OK` with a response body, or `204 No Content` if a resource was updated. |
+| `PUT` | Update/Replace | Update or replace an entire resource. Successful `PUT` requests return `200 OK` with a response body. The request returns `201 Created` if the resource was created, or `204 No Content` if a resource was updated. |
+| `DELETE` | Delete | Delete a resource. Successful `DELETE` requests usually return `204 No Content` without a response body. In rare cases, a delete request returns `200 OK`. Failed `DELETE` requests return `404 Not Found` if the resource cannot be found, or `410 Gone` if the resource has already been deleted before. |
+| `OPTIONS` | Inspect Methods | Inspect the available HTTP methods of a given endpoint. `OPTIONS` responses usually contain either a comma-separated list of methods in the `Allow` header, or a structured list of link templates. |
diff --git a/02_about-the-api/03_status-codes.md b/02_about-the-api/03_status-codes.md
new file mode 100644
index 0000000..dd5d7cd
--- /dev/null
+++ b/02_about-the-api/03_status-codes.md
@@ -0,0 +1,57 @@
+## Status codes
+
+Every OTTO Retail-API call returns an HTTP status code to indicate success or failure of a request.
+
+### Success
+
+For successful requests, the OTTO Retail-API returns the following HTTP status codes:
+
+| Status code | Description |
+| ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
+| `200 OK` | The HTTP request succeeded. |
+| `201 Created` | A `POST` or `PUT` request successfully created a new resource. The response provides the URI of the new resource in the `Location` header. |
+| `202 Accepted` | The API accepted the request and will process it asynchronously. |
+| `204 No Content` | The server successfully fulfilled the requested operation, but does not return a response body. |
+
+### Redirection
+
+The OTTO Retail-API returns the following HTTP status codes when the availability or location of a resource has changed, or when a resource has not been updated.
+
+| Status code | Description |
+| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `301 Moved Permanently` | The resource is no longer available under the requested path. This and all future requests must be directed to the specified URI. |
+| `303 See Other` | The response to a `POST`, `PUT`, `PATCH`, or `DELETE` request is available under another URI using a `GET` method. |
+| `304 Not Modified` | The requested resource does not need to be resent. It is an implicit redirect to a cached resource. The resource has not been modified since the date or version passed via request headers `If-Modified-Since` or `If-None-Match`. |
+| `307 Temporary Redirect` | The response to the request is temporarily available via another URI using the same method of the initial request. |
+| `308 Permanent Redirect` | The response to the request is permanently available via another URI using the same method of the initial request. |
+
+### Client error
+
+In case of failed requests, the OTTO Retail-API returns the following HTTP status codes:
+
+| Status code | Description | Possible cause and solution |
+| ---------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
+| `400 Bad Request` | Request is malformed, syntactically incorrect or violates the schema. | The API was not able to validate the request. Possible causes for this condition: The API cannot convert the payload data to the underlying data type, or the data is not in the expected data format or does not contain all required properties. |
+| `401 Unauthorized` | User authentication failed. | The request requires a valid user authentication. Either the request header does not provide an access token or the access token has expired and needs to be refreshed. |
+| `403 Forbidden` | Request is valid but does not have sufficient rights. | The API refuses access to the requested resource most likely due to insufficient rights. Re-authenticating does not solve this. A possible cause is an incorrect value of the scope property of the access token. |
+| `404 Not Found` | The requested resource does not exist. | Possible causes for a `404` status code are a malformed query structure or a misspelled name of the requested resource. |
+| `405 Method Not Allowed` | The API endpoint does not support the requested HTTP method. | The API does not support the requested method for the target resource. This status occurs, for example, after sending a `POST` or `PUT` request to a read-only resource. The supported methods are available in the endpoint documentation. |
+| `406 Not Acceptable` | The API does not support the requested media type. | The API cannot use the requested media type to return the response payload. This error might occur, for example, if the client sends an `Accept: application/xml` request header, but the API can only generate an `application/json` response. Possible causes can be a request targeting an outdated API version or media type. |
+| `409 Conflict` | The API cannot complete the request due to a conflict with the current state of the resource. | An update operation for a resource fails because the resource already was updated since it was retrieved by the client. A possible cause for this response is, when a client requests the same action for the same resource on two different registered devices. |
+| `410 Gone` | The requested resource is no longer available. | A possible cause for this status response is a malformed request structure. |
+| `412 Precondition Failed` | The precondition defined by the request failed. | The API denies access to the target resource, for example, if an edit conflict between multiple simultaneous updates occurs. This might also appear if the `If-Match` header does not match the resource's `ETag`. |
+| `413 Payload Too Large` | The request payload exceeds the limit of the API. | The request header or body exceeds the defined limit. This might happen for requests with a large `JWT` containing many scopes or a large `HTTP body`. |
+| `415 Unsupported Media Type` | The API does not support the media type of the request payload. | The API refuses to accept the `PUT`, `PATCH`, or `DELETE` request because the payload format is not supported or malformed. Ensure your request body contains a content type and is syntactically and semantically correct. |
+| `422 Unprocessable Entity` | The API cannot complete the requested action. | Indicates a logically invalid request body. The server understands the content type of the request entity and the syntax is correct. However, the server was unable to process the contained instructions, for example, due to semantically incorrect data such as a date of birth that lies in the future. |
+| `428 Precondition Required` | The API requires the request to be conditional. | The API requires the request to include a precondition header, such as `If-Unmodified-Since` or `If-Match`. Without this header, the API cannot determine if the client has the same version of the resource. To resolve this condition, first find out the current version of the resource by sending a `GET` or `HEAD` request, and then reading either the `E-tag` or `Last-Modified` headers. Finally, add this information as a precondition header to the next update request. |
+| `429 Too Many Requests` | Too many requests. Blocked due to rate limiting. | The client has sent too many requests in a given time. Make sure that your implementation provides a rate limit for the requests. Our API allows a daily rate of 100,000 requests. |
+
+### Server error
+
+For server-side errors, the OTTO Retail-API returns the following status codes:
+
+| Status code | Description |
+| --------------------------- | ------------------------------------------------------------------------------------ |
+| `500 Internal Server Error` | The server encountered an unexpected condition that prevents fulfilling the request. |
+| `501 Not Implemented` | The server does not support the functionality required to fulfill the request. |
+| `503 Service Unavailable` | The server is (temporarily) not able to handle the request. |
diff --git a/02_about-the-api/04_error-responses.md b/02_about-the-api/04_error-responses.md
new file mode 100644
index 0000000..f5df63e
--- /dev/null
+++ b/02_about-the-api/04_error-responses.md
@@ -0,0 +1,58 @@
+## Error responses
+
+If an API returns an error, the response body contains a [problem detail encoded in json](https://www.rfc-editor.org/rfc/rfc7807).
+This section contains the structure of the used problem detail types.
+
+### Problem detail object
+
+Every problem detail type has the following properties:
+
+```json-schema
+{
+ "type": "object",
+ "children": {
+ "type": {
+ "type": "string",
+ "required": true,
+ "description": "See [RFC7807, Section 3.1.](https://www.rfc-editor.org/rfc/rfc7807#section-3.1) and [RFC7807, Section 4.2.](https://www.rfc-editor.org/rfc/rfc7807#section-4.2)",
+ "example": "about:blank"
+ },
+ "title": {
+ "type": "string",
+ "required": true,
+ "description": "See [RFC7807, Section 3.1.](https://www.rfc-editor.org/rfc/rfc7807#section-3.1)",
+ "example": "Not Found"
+ },
+ "status": {
+ "type": "number",
+ "required": true,
+ "description": "See [RFC7807, Section 3.1.](https://www.rfc-editor.org/rfc/rfc7807#section-3.1)",
+ "example": 404
+ },
+ "detail": {
+ "type": "string",
+ "required": false,
+ "description": "See [RFC7807, Section 3.1.](https://www.rfc-editor.org/rfc/rfc7807#section-3.1)",
+ "example": "Could not find requested resource. Please check if the provided URI is correct."
+ },
+ "instance": {
+ "type": "string",
+ "required": false,
+ "description": "See [RFC7807, Section 3.1.](https://www.rfc-editor.org/rfc/rfc7807#section-3.1)",
+ "example": "https://retail-api.otto.de/products/d8d3d27e-ce16-4920-83dc-f5ee0791a5ab"
+ }
+ }
+}
+```
+
+### Example problem detail object
+
+```json
+{
+ "type": "about:blank",
+ "title": "Forbidden",
+ "status": 403,
+ "detail": "You are not allowed to view account details of others.",
+ "instance": "/account/12345/"
+}
+```
diff --git a/02_about-the-api/05_headers.md b/02_about-the-api/05_headers.md
new file mode 100644
index 0000000..da666e2
--- /dev/null
+++ b/02_about-the-api/05_headers.md
@@ -0,0 +1,29 @@
+## Headers
+
+Our APIs require the use of certain HTTP headers.
+
+### Request headers
+
+To ensure that your API requests are processed successfully, we encourage you to always include the headers as listed in the table below.
+
+Depending on the API, you may encounter different supported media types, such as `application/json`, `application/hal+json`, `application/merge-patch+json`, or `text/uri-list`.
+See the "Request Headers" section of each operation in the API Reference for endpoint-specific request headers.
+
+| Header | Type | Description |
+| :-------------- | :----- |:---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| `Accept` | String | The media type acceptable for the response body. Required for requests that have a response with a body. Can be one of the media types listed above in conjunction with a [profile parameter](10_profiles.md) including the profile URI of a resource. For example: `application/hal+json;profile="/products/product+v1"`. |
+| `Authorization` | String | The OAuth 2.0 bearer token to authorize the request for accessing the API. Required for all requests.
For example: Bearer ``. |
+| `Host` | String | The target host of the request. Required for all requests. For the production environment use `retail-api.otto.de`, for the sandbox environment use `retail-api-sandbox.otto.de`. |
+| `Content-Type` | String | The media type of the request body. Required when a request body contains data. Can be one of the media types listed above in conjunction with a [profile parameter](10_profiles.md) including the profile URI of a resource. For example: `application/hal+json;profile="/products/product+v1"`. |
+
+### Response headers
+
+After processing a request, the OTTO Retail-API returns an HTTP response that uses standardized HTTP headers.
+The table below summarizes the most common HTTP response headers that your client application may encounter when communicating with our REST API.
+
+| Header | Type | Description |
+| :--------------- | :----- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Content-Length` | Number | The length of the returned response body content in bytes. |
+| `Content-Type` | String | The media type of the returned response body. Reflects the `Accept` header of the associated sent request, unless the server was not able to fulfill the client's demand. Can be a combination of `application/json` or `application/hal+json` and a [profile parameter](10_profiles.md) with the profile URI of a resource. |
+| `Date` | String | The timestamp of the response in [HTTP-date format](https://datatracker.ietf.org/doc/html/rfc9110#section-6.6.1). For example: `Thu, 7 Jul 2022 16:30:00 GMT`. |
+| `Location` | String | The URI of a resource. This response header is usually sent after creating a new resource. |
diff --git a/02_about-the-api/06_pagination.md b/02_about-the-api/06_pagination.md
new file mode 100644
index 0000000..5bfb0ea
--- /dev/null
+++ b/02_about-the-api/06_pagination.md
@@ -0,0 +1,74 @@
+## Pagination
+
+When querying a collection resource, you receive multiple resources at once instead of a single resource item.
+A page-based pagination approach divides the result set of a request into pages of a certain size.
+Each API sets their default values for `pageSize`, `minimum` and `maximum` independently.
+
+You can either use the default values, or adjust the values of the query parameters that are described below to tailor the result to your custom processing patterns.
+See the "Parameters" section of each operation in the API Reference for endpoint-specific default values.
+
+Parameter set for pagination:
+
+| Parameter | Example values | Example | Description |
+| :--------- | :------------- | :------------- | :---------------------------------------------------------------------------------------------------------------------------------- |
+| `page` | `0..n` | `?page=0` | The page that should be returned. The example returns the first page. Note that page counting starts at value 0 for the first page. |
+| `pageSize` | `1..n` | `?pageSize=10` | The number of items a returned page should contain. The example returns 10 elements. |
+
+Every response body of a collection resource includes the object `_page`, which contains the values of the used parameters with property names that differ from the query parameter names.
+
+Hypermedia APIs return collection resources with an additional object `_links`.
+This object contains a map of links using the pagination parameters and `prev` and `next`, pointing to the previous and next page of the collection.
+Using these links, the values of your request are automatically applied to the subsequent requests.
+
+### Example request
+
+This request combines the query parameters `page` and `pageSize` and requests page one of the collection resource /products to include two items:
+
+```http
+GET /products?page=1&pageSize=2 HTTP/1.1
+Host: retail-api.otto.de
+Authorization: Bearer
+otto-ecuuid: string
+Accept: application/hal+json;profile="/products/product+v1"
+```
+
+### Example response body
+
+The response body to the request above embeds two resource objects inside the array `item`.
+The pagination parameters and values are applied to the link relations inside the object `_links`, and are reflected in the object `_page`.
+
+```json
+{
+ "_embedded": {
+ "item": [
+ {
+ "id": "393693-121040",
+ "salesId": "927793906233",
+ "quantity": 2,
+ "delivery": {...}
+ },
+ {
+ "id": "393693-121041",
+ "salesId": "927793906233",
+ "quantity": 1,
+ "delivery": {...}
+ }
+ ]
+ },
+ "_links": {
+ "self": {
+ "href": "https://retail-api.otto.de/products?page=1&pageSize=2"
+ },
+ "prev": {
+ "href": "https://retail-api.otto.de/products?page=0&pageSize=2"
+ },
+ "next": {
+ "href": "https://retail-api.otto.de/products?page=2&pageSize=2"
+ }
+ },
+ "_page": {
+ "size": 2,
+ "number": 1
+ }
+}
+```
diff --git a/02_about-the-api/07_hypermedia.md b/02_about-the-api/07_hypermedia.md
new file mode 100644
index 0000000..028f5ba
--- /dev/null
+++ b/02_about-the-api/07_hypermedia.md
@@ -0,0 +1,51 @@
+## Hypermedia
+
+We use [JSON Hypertext Application Language (HAL)](https://datatracker.ietf.org/doc/html/draft-kelly-json-hal) to represent our API resources with additional hypermedia information, and to connect them in a consistent way using [links](https://datatracker.ietf.org/doc/html/rfc5988).
+
+A HAL resource object returned by our API has:
+
+- a `_links` property, containing a map of links that allows you to navigate from the returned resource object to its related API resources.
+- an optional `_embedded` property, containing additional resource objects, for example, when querying a collection resource.
+
+You can use the `_links` map instead of composing URIs yourself, or speculating if further related resources exist.
+The links inside this map are each identified by a link relation type (rel), that defines the semantics of the relation between two resources.
+
+Example of a `_links` map:
+
+```json
+{
+ "_links": {
+ "self": {
+ "href": "https://retail-api.otto.de/products/S0P0509Y",
+ "type": "application/hal+json",
+ "profile": "/products/product+v1"
+ }
+ }
+}
+```
+
+A rel such as `self` points to the current resource.
+
+When you query a collection resource, the API returns a resource object with the `_embedded` property, containing additional resource objects besides the one you requested.
+Apart from collection resources, some other resources also support the embedding of related resources via the request parameter `embedded`.
+For each resource, our API reference provides documentation of the supported request parameters and example responses.
+
+Example of embedded resource objects:
+
+```json
+{
+ "links": {...},
+ "_embedded": {
+ "item": [
+ {
+ "id": "3538941240",
+ "salesOrderId": "929906233",
+ "fulfillmentStatus": "DELIVERED",
+ "orderDate": "2021-01-15T00:00:00.000Z",
+ "product": {...}
+ },
+ {...}
+ ]
+ }
+}
+```
diff --git a/02_about-the-api/08_versioning.md b/02_about-the-api/08_versioning.md
new file mode 100644
index 0000000..1745b84
--- /dev/null
+++ b/02_about-the-api/08_versioning.md
@@ -0,0 +1,23 @@
+## Versioning
+
+We version each resource representation independently by its media type instead of maintaining a single global version number for the entire OTTO Retail-API landscape.
+We use the [`profile`](https://datatracker.ietf.org/doc/html/rfc6906) parameter to further describe the resource representation in the media type.
+This allows us to keep different versions of the same REST resource, and make them identifiable with a version suffix `+v{version}` in the profile path:
+
+`/products/product+v1`
+
+In case we change a resource representation in a non-compatible way, we iterate the version number:
+
+`/products/product+v2`
+
+You can specify the resource version on a request by using a `profile` parameter in the `Accept` header.
+
+We try to maintain backwards compatibilty, but in some cases, changes to a resource require the introduction of a new version.
+These cases might include, but are not limited to:
+
+- Addition or removal of enumerated fields
+- Change of mandatory properties
+- Change the name of request/response properties
+- Change the datatype of a property
+
+You can find an overview of all available profiles and more detailed information about the usage of profiles in your requests in the [Profiles](10_profiles.md) section.
diff --git a/02_about-the-api/09_deprecation.md b/02_about-the-api/09_deprecation.md
new file mode 100644
index 0000000..6c23b83
--- /dev/null
+++ b/02_about-the-api/09_deprecation.md
@@ -0,0 +1,27 @@
+## Deprecation
+
+As part of the API lifecycle it might be necessary to phase out an API element, such as a resource [profile](10_profiles.md), a query parameter, or an API endpoint.
+This can happen for a variety of reasons, including outdated resource properties, security issues, or when a business case is no longer supported.
+
+Along with the deprecation of a resource profile, if we do not remove it completely, we also introduce a new version of it.
+For each endpoint operation, the OTTO Retail-API reference also displays the currently active profile version URL.
+We only maintain the latest version of a profile and strongly encourage new API users to _not_ implement outdated versions.
+Continue for [more information about versioning](08_versioning.md).
+
+After deprecation announcement, we will work together with our API consumers to discover a migration strategy, and to agree on deprecation and sunset schedules.
+During the deprecation phase we will further maintain the deprecated API element and monitor its usage.
+We may shutdown the deprecated API element after all API consumers have successfully migrated, but no later than the sunset date.
+
+During the deprecation phase you can determine if an API element is deprecated, by actively monitoring the HTTP response headers that your API client receives:
+
+| Header | Description |
+| :-----------: | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `Deprecation` | The `Deprecation` header (see draft: [RFC Deprecation HTTP Header](https://datatracker.ietf.org/doc/html/draft-dalal-deprecation-header)) indicates if the accessed API element is or will be deprecated. If the API element is deprecated, the header contains the value `true`, otherwise it contains a timestamp marking the start of the deprecation phase. |
+| `Sunset` | The optional `Sunset` header (see: [RFC 8594](https://datatracker.ietf.org/doc/html/rfc8594#section-3)) contains a single timestamp, indicating the date after which consumers may no longer use the deprecated API element. After the sunset date, the API element may be removed without further notice. |
+
+Example responses:
+
+```http
+Deprecation: Sun, 31 Dec 2024 23:59:59 GMT
+Sunset: Sun, 31 Dez 2025 23:59:59 GMT
+```
diff --git a/02_about-the-api/10_profiles.md b/02_about-the-api/10_profiles.md
new file mode 100644
index 0000000..c5895b1
--- /dev/null
+++ b/02_about-the-api/10_profiles.md
@@ -0,0 +1,6 @@
+## Profiles
+
+The OTTO Retail-API uses profiles (see: [RFC 6906](https://datatracker.ietf.org/doc/html/rfc6906)) not only to version each resource representation and make them identifiable with a profile URL, but also to provide more detailed documentation of a resources’ structure and properties.
+
+Here is an overview of all available profiles:
+- /products/product+v1
diff --git a/03_api_guidelines/000_index.md b/03_api_guidelines/000_index.md
new file mode 100644
index 0000000..b34923c
--- /dev/null
+++ b/03_api_guidelines/000_index.md
@@ -0,0 +1,37 @@
+# OTTO API Guidelines
+
+Our APIs are a valuable part of our business assets, as with APIs we generate the corresponding operating values.
+Ideally, by applying the API guidelines, all APIs look as if they were created by a single team, thus providing API consumers with a homogeneous, easy-to-use product.
+This facilitates a great developer experience and the ability to quickly compose complex business processes.
+
+With this in mind, we trust that our teams build APIs that are:
+
+- self-explanatory
+- easy to use and robust
+- of high quality
+- consistent
+- transparently versioned
+- RESTful with respect to REST APIs
+
+## How to read the guidelines
+
+This guide is a living document and will be revised over time as new rules are added or existing rules are modified.
+
+The guidelines are structured into individual rules that use the key words "MUST", "MUST NOT", "SHOULD", "SHOULD NOT", and "MAY".
+These keywords are to be interpreted as described in [RFC2119](https://www.ietf.org/rfc/rfc2119.txt).
+In this document, such keywords are highlighted at the beginning of each section in uppercase letters and are color-coded.
+
+Disclaimer
+Code examples may be incomplete and/or may violate the rules described in the guidelines. Examples are intentionally kept simple to make them more accessible and easier to comprehend. They are always correct in their context, but not necessarily outside of it.
+
+Common examples for this are:
+
+- omitted headers such as `Authorization`
+- omitted (mandatory) properties in JSON responses
+
+## Attribution
+
+At this point we would like to send Kudos to Zalando SE whose Tech Team did a great job crafting the [Zalando RESTful API Guidelines](https://opensource.zalando.com/restful-api-guidelines/#).
+As much of the content resonates with what we do at OTTO, their well-prepared document inspired us and in certain parts provided a basis when crafting the OTTO API Guidelines.
+
+The Zalando RESTful API Guidelines are published under the [Creative Commons Attribution 4.0 International License](https://github.com/zalando/restful-api-guidelines/blob/main/LICENSE) (CC BY 4.0). For further notes on these OTTO API Guidelines’ license under CC BY 4.0, please refer to the [Creative Commons Attribution 4.0 International Public License](https://creativecommons.org/licenses/by/4.0/legalcode).
diff --git a/03_api_guidelines/010_CORE-PRINCIPLES/010_API-design.md b/03_api_guidelines/010_CORE-PRINCIPLES/010_API-design.md
new file mode 100644
index 0000000..83a0392
--- /dev/null
+++ b/03_api_guidelines/010_CORE-PRINCIPLES/010_API-design.md
@@ -0,0 +1,27 @@
+# API design
+
+API design involves many aspects such as architectural styles, API governance, backend capabilities, performance, and such.
+There are many constraints and compromises to be considered.
+With our API design we want to create value for the customer and provide a good developer experience.
+
+## REST APIs
+
+For our REST APIs, we've decided to apply the RESTful principle to all kind of application components.
+REST resources are identified via URIs and can be manipulated via standardized CRUD operations using different representations, and hypermedia.
+RESTful APIs come with less rigid client/server coupling and are more suitable for an ecosystem of (core) services providing a platform of APIs to build diverse business services.
+
+In summary:
+
+- We prefer REST-based APIs with JSON payloads.
+- We prefer systems to be truly RESTful.
+
+References:
+- [Build APIs You Won’t Hate](https://www.amazon.de/Build-APIs-You-Wont-Hate/dp/0692232699)
+- [Irresistable APIs: Designing web APIs that developers will love](https://www.amazon.de/Irresistible-APIs-Designing-that-developers/dp/1617292559)
+- [Architectural Styles and the Design of Network-Based Software Architectures](https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm)
+
+## Asynchronous APIs
+
+With our asynchronous APIs, we aim for low coupling between services, i.e. to remove the need for services to actively send queries via synchronous APIs.
+This reduces latency and simplifies changing services in insolation.
+By using events, we provide a mechanism, that allows consumers to subscribe to events of their interest, whereas we use commands for actions to be executed by a specific recipient.
diff --git a/03_api_guidelines/010_CORE-PRINCIPLES/020_API-as-a-product.md b/03_api_guidelines/010_CORE-PRINCIPLES/020_API-as-a-product.md
new file mode 100644
index 0000000..baecea4
--- /dev/null
+++ b/03_api_guidelines/010_CORE-PRINCIPLES/020_API-as-a-product.md
@@ -0,0 +1,17 @@
+# API as a product
+
+When looking at APIs, the focus is mostly on the technical implementation, whereas the business perspective is often overlooked.
+But exactly in the business context more and more services are being created.
+Therefore, we need to understand our API as a product and not just look at it as a pure code base.
+Just like any other product, our API has consumers, it is subject to continuous development, it strives for high quality standards, and flexible delivery of features.
+In addition, an API needs to deliver value such as efficiency and scalability, a flexible business model, shorter time to market, as well as lower development and maintenance costs.
+
+From a business perspective, every API transaction has a value, whether it is data generation, integrating with third-parties, or direct revenue generation.
+We treat our API as a business value generator that gives API consumers a great experience to integrate with, while at the same time generating revenue.
+
+Hence, the design of our APIs is based on the "API as a product" principle:
+
+- Our API is a product and we are responsible for it.
+- We provide our consumers with a homogeneous, easy-to-use API.
+- We advocate for our user's needs.
+- We actively improve and maintain API consistency.
diff --git a/03_api_guidelines/010_CORE-PRINCIPLES/030_API-scope.md b/03_api_guidelines/010_CORE-PRINCIPLES/030_API-scope.md
new file mode 100644
index 0000000..e42f895
--- /dev/null
+++ b/03_api_guidelines/010_CORE-PRINCIPLES/030_API-scope.md
@@ -0,0 +1,23 @@
+# API scope
+
+APIs can be assigned attributes to define certain non-functional requirements.
+Here's what this exactly means in the context of the OTTO API.
+
+Basically APIs can be described with the following attributes:
+
+| Attribute | Description |
+| --------- | --------------------------------------------------------------------------------------------------------------- |
+| public | No network access restrictions, world-wide reachable. |
+| private | Network access restrictions, e.g. firewall or egress SecurityGroups required. |
+| open | No authorization/authentication required, anonymous access. |
+| closed | Authorization/authentication required, different scopes for fine-grained permissions. |
+| published | Service Level Agreements apply, such as established versioning, changelog, and documentation processes. |
+| internal | Less strict Service Level Agreements, such as no established versioning, changelog, or documentation processes. |
+
+The scope of the OTTO API ranges between a public and a private API.
+The operational and organisational requirements such as guidelines, governance, documentation, and stability are similar to those of a public API.
+The scope, level of detail, and content of the endpoints are not intended for public or anonymous use.
+Access to data and company assets is only granted to selected and predictable API consumers.
+This approach enables a targeted and managed development of API clients and products.
+
+The OTTO API corresponds to the attributes **public**, **closed**, and **published**.
diff --git a/03_api_guidelines/010_CORE-PRINCIPLES/040_Contract-first.md b/03_api_guidelines/010_CORE-PRINCIPLES/040_Contract-first.md
new file mode 100644
index 0000000..fcb3471
--- /dev/null
+++ b/03_api_guidelines/010_CORE-PRINCIPLES/040_Contract-first.md
@@ -0,0 +1,18 @@
+# Contract first
+
+There are repeated discussions about the "API First" development paradigm, and many well-known software development companies follow this approach.
+The definition and understanding are not consistent though, and we have learned that the "API First" approach does not work well for us.
+But "Contract First" does even better.
+
+In a nutshell, Contract First implies that we start out establishing a contract and then share it with our consumer.
+The contract includes what the request and response communication is expected to be.
+Once the contract is in place, the backend team can start developing the API whereas the consumer can start working on an application to consume it.
+
+Specifically we have decided to follow the principle "UI First, API Second" based on some thoughts that [Stefan Tilkov posted on Twitter](https://twitter.com/stilkov/status/1250355396864176132).
+This implies that we do not approach the API design from the backend point of view, but from the direction of a specific visual representation of the intended feature.
+
+What are the advantages of Contract First for us?
+
+- Since coding happens based on the contract, the backend team and the consumer are clear about the communication approach and details. Hence, development on backend and consumer side can happen at the same time.
+
+- The backend team and the consumer have an idea of each others' expectations. As a result, if cross-team testing is not possible due to different paces of development, stub software can be used to mock the other's behavior, all based on the contract.
diff --git a/03_api_guidelines/010_CORE-PRINCIPLES/050_Quality-standards.md b/03_api_guidelines/010_CORE-PRINCIPLES/050_Quality-standards.md
new file mode 100644
index 0000000..f01164d
--- /dev/null
+++ b/03_api_guidelines/010_CORE-PRINCIPLES/050_Quality-standards.md
@@ -0,0 +1,62 @@
+# Quality standards
+
+As already mentioned, [the scope of the OTTO API](./030_API-scope.md) ranges between a public and a private API.
+Nevertheless, when it comes to quality, we strive for the standards of a public API.
+If our API needs to be public by tomorrow, external users should then be able to consume our API immediately.
+What's more, a consistent understanding of quality standards facilitates the development of further endpoints and the evolution of the OTTO API as a product without unnecessary consultation between all parties involved.
+
+Our understanding of quality covers the following aspects:
+
+## Robustness
+All implementations of our API follow the [Robustness Principle](https://en.wikipedia.org/wiki/Robustness_principle), as it is essential for the evolution of APIs.
+Future changes to interfaces cannot be anticipated in advance, so aspects such as backward compatibility, loose coupling, and the elimination of the need to synchronize different services are of crucial importance.
+This is especially applicable for microservice environments where dependencies between services should be kept to a minimum.
+
+Be conservative in what you do, be liberal in what you accept from others.
+
+## Consistency
+Our API is essentially developed by independent, autonomous functional teams.
+However, we strive for a uniform presentation to the outside world.
+The API should give the impression that it was developed by a single team.
+This consistency covers several facets such as documentation, naming conventions, code examples, common data structures, pagination, governance, authentication, and error codes.
+
+## Reliability
+If our API infrastructure is not reliable, consumers will not build trust, and engagement will not increase.
+API reliability extends beyond uptime.
+We do not limit our evaluation to availability, but also include aspects such as fluctuations in response times or behavior with an increasing number of concurrent API clients.
+
+We avoid unannounced changes and prevent outages to the best of our knowledge.
+When having to choose between consistency (always return even in case of an error) and availability (in doubt return stale content), we prefer availability. Even to the detriment of consistency.
+Our endpoints must always return a response, whether the requested operation succeeds or fails.
+
+## Security
+Security is not a marginal topic, but an integral part of all software projects, and thus also of APIs.
+
+Not all vulnerabilities will be preventable.
+However, a good rule of thumb is to prepare for the worst case scenario that everyone is out to get our data.
+We leverage industry-standard technologies for encryption, authentication, and authorization.
+
+We are conservative in exposing our data and the [Principle of least privilege](https://en.wikipedia.org/wiki/Principle_of_least_privilege) is applied to allow API clients only enough access to perform the required tasks.
+In addition, we strive to include only the least amount of data necessary to respond to any API call and secure our applications against the [OWASP Top 10 Threats](https://owasp.org/www-project-top-ten/).
+
+We also restrict the rate limit to specific resources to prevent misuse.
+
+## Performance
+We identify and analyze key metrics for different groups of interest.
+The bandwidth of possible metrics ranges from purely technical information such as uptime, latencies, and error rates to business insights such as SDK, version adoption, as well as Time to First Hello World (TTFHW), or API usage growth.
+
+## Documentation & Support
+We help both vendors during development and users of our API with the integration by offering suitable ways of exchange and support.
+As the primary resource for explaining our API and its capabilities, documentation must be as accessible to the audience as possible.
+We provide all consumers of our API with comprehensive, professional, up-to-date, and complete information.
+
+## Communication
+We always keep both developers and consumers of our API informed through appropriate channels.
+Changes and [deprecations](../030_REST-GUIDELINES/050_Compatibility/040_Deprecation/000_index.md) are communicated regularly and actively.
+Therefore, we establish different synchronous and asynchronous communication channels to support developers and consumers.
+
+## Developer Experience
+API consumers should have fun using our API.
+Our goal is to provide seamless experience to developers when writing software, and to increase their efficiency.
+API consumers should be comfortable using our API in their programming language of choice, finding the functionality they need, as well as using the output.
+We give developers the right tools to help them succeed and aim to provide an as short as possible TTFHW.
diff --git a/03_api_guidelines/010_CORE-PRINCIPLES/060_Documentation.md b/03_api_guidelines/010_CORE-PRINCIPLES/060_Documentation.md
new file mode 100644
index 0000000..8c6eacf
--- /dev/null
+++ b/03_api_guidelines/010_CORE-PRINCIPLES/060_Documentation.md
@@ -0,0 +1,51 @@
+# Documentation
+
+Our [quality standards](./050_Quality-standards.md) define all the values that are important to us.
+What's more, we aim to take care of clearly structured documentation, provide our audience with code examples, and make sure they have a great time using our API.
+Here's what that means:
+
+## Clear structure
+**Usability**
+
+- A user-friendly navigation makes it easy to discover the API and find all relevant information.
+- The sidebar is cleary structured and easy to navigate.
+- API endpoints and examples are shown in context.
+
+**Getting started**
+
+- Basic information is available at one central place, such as info about HTTP methods, API operations, request/response headers, versioning, pagination, or errors.
+- A short and simple guide provides an overview of the most likely tasks to perform with the API.
+- Users can get in touch with us via a contact form.
+
+**Tutorials**
+With step-by-step walkthroughs we'll cover specific functionality that can be implemented with the API.
+
+**Familiarize users with the API**
+We'll cater for experienced users that already have an idea of the endpoints to be used, and at the same time provide the respective structure and information for inexperienced users who need a thorough introduction and/or example use cases.
+
+**Discoverable and easy to digest**
+
+- All information is easily discoverable, easy to digest, and prepared in a way that the user can effectively work with it.
+- We'll be consistent with our tone of voice, terminology, attribute names, API endpoint design, requests and responses, and counting.
+- The layout supports accordingly, e.g. with syntax highlighting or multi-column layout.
+
+## Code examples
+**Default values**
+Request and response examples that belong to every endpoint documentation have meaningful default values that follow a specific story.
+
+**Code examples and schemas**
+Every endpoint documentation comes with examples and also provides schemas listing the available attributes with explanatory text.
+
+**Automated API reference documentation**
+API reference documentation is created and published automatically, see [MUST provide API specification using OpenAPI](@guidelines/R000003).
+
+## Consistency and accessibility
+
+- Documentation is provided in American English (EN-US), as US spelling has become the standard in APIs. Also endpoints, properties, and default values are provided in American English.
+- Users can search the documentation.
+- The sidebar is available at all times so that the documentation can be easily browsed. All the endpoints can be accessed via the sidebar.
+- Code examples and explanatory text are visually separated.
+
+## Efficient and refined
+The API is well-documented and up-to-date.
+Users can flawlessly integrate and are informed about recent changes via a revision history.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/000_index.md
new file mode 100644
index 0000000..de8c5bd
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/000_index.md
@@ -0,0 +1,3 @@
+# Basics
+
+This section contains basic rules and concepts that lay the groundwork for API type-specific rules.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/010_must-follow-contract-first-approach.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/010_must-follow-contract-first-approach.md
new file mode 100644
index 0000000..dcae353
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/010_must-follow-contract-first-approach.md
@@ -0,0 +1,14 @@
+---
+type: MUST
+id: R000001
+---
+
+# follow Contract First approach
+
+When a new API is being developed, we follow the [Contract First approach](../../../010_CORE-PRINCIPLES/040_Contract-first.md).
+This requires the following aspects:
+
+- We define API contracts first before coding the implementation using a [standard specification language](@guidelines/R000003).
+- We get early review feedback from peers and API consumers.
+
+By defining API contracts outside of the code, we aim to facilitate early review feedback and a development discipline that focuses service interface design on a profound understanding of the domain and the required functionality.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/020_should-develop-ui-first-api-second.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/020_should-develop-ui-first-api-second.md
new file mode 100644
index 0000000..5343bb4
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/020_should-develop-ui-first-api-second.md
@@ -0,0 +1,10 @@
+---
+type: SHOULD
+id: R000002
+---
+
+# develop UI first, API second
+
+While the development of additional endpoints is crucial to establish a comprehensive and vital API ecosystem, we do not want to build endpoints upfront without the appropriate use cases.
+In a first step, you should focus on implementing an appropriate UI to identify the requirements and quality factors of the API.
+Only in a second step, we provide an API, that is suitable to implement more clients, having similar requirements as the first UI use case.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/030_must-write-apis-using-american-english.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/030_must-write-apis-using-american-english.md
new file mode 100644
index 0000000..43f0a2d
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/030_must-write-apis-using-american-english.md
@@ -0,0 +1,9 @@
+---
+type: MUST
+id: R000004
+---
+
+# write APIs using American English
+
+The API description as well as the overall documentation must be written in American English.
+We use standard American spelling.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/044_must-use-https.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/044_must-use-https.md
new file mode 100644
index 0000000..2b45f62
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/044_must-use-https.md
@@ -0,0 +1,11 @@
+---
+type: MUST
+id: R000046
+reviewType: automatic
+---
+
+# use TLS
+
+All API communication must be secured via Transport Level Security (TLS) formerly known as Secure Sockets Layer (SSL).
+
+This means that HTTP communication must be made over TLS, resulting in HTTPS communication.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/045_must-ensure-implementation-is-compliant-to-openapi-specification.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/045_must-ensure-implementation-is-compliant-to-openapi-specification.md
new file mode 100644
index 0000000..2fa6b14
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/045_must-ensure-implementation-is-compliant-to-openapi-specification.md
@@ -0,0 +1,15 @@
+---
+type: MUST
+id: R000076
+---
+
+# ensure implementation complies with the contract
+
+The contract defined in the specification (i.e. OpenAPI or AsyncAPI) is binding.
+API providers must ensure that the implementation complies with the agreed specification.
+Ideally, compliance tests are part of the build pipeline.
+
+Use
+
+- unit tests to validate the API against the specification
+- Consumer Driven Contract (CDC) tests for a more inclusive and consumer-oriented approach.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/050_should-involve-technical-writer.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/050_should-involve-technical-writer.md
new file mode 100644
index 0000000..faf89eb
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/050_should-involve-technical-writer.md
@@ -0,0 +1,9 @@
+---
+type: SHOULD
+id: R000006
+---
+
+# involve technical writer
+
+Any description that has been provided by developers in the OpenAPI specification should undergo a copy editing and proofreading process by a technical writer.
+As explanations may be too difficult for the audience to understand, may not be sufficiently described or may contain inconsistent terminology, all texts should be edited by a technical writer.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/060_may-provide-api-user-guide.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/060_may-provide-api-user-guide.md
new file mode 100644
index 0000000..814ee36
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/060_may-provide-api-user-guide.md
@@ -0,0 +1,16 @@
+---
+type: MAY
+id: R000005
+---
+
+# provide API user guide
+
+In order to improve the developer experience of API consumers, especially of engineers that are less experienced in using the OTTO API, it is good practice to provide an API user guide along with the API reference (provided via the API spec).
+A helpful API user guide typically describes aspects such as:
+
+- API scope, purpose, and use cases
+- Concrete examples of API usage
+- Error handling information and solution support
+- Architectural context and major dependencies, including illustrations and flow charts
+
+The user guide is created by a [technical writer](R000006) in a central repository, agreed with the development teams, and published online together with the API reference.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/070_must-provide-contact-informaton.md b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/070_must-provide-contact-informaton.md
new file mode 100644
index 0000000..06b3e12
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/010_Basics/010_Basics/070_must-provide-contact-informaton.md
@@ -0,0 +1,8 @@
+---
+type: MUST
+id: R000078
+---
+
+# provide contact information
+
+An API contract must contain the contact information of the team owning the respective specification.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/000_index.md
new file mode 100644
index 0000000..02ed5a2
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/000_index.md
@@ -0,0 +1 @@
+# JSON
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/000_index.md
new file mode 100644
index 0000000..cbec012
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/000_index.md
@@ -0,0 +1 @@
+# Naming conventions
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/010_should-use-camel-case-for-property-names.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/010_should-use-camel-case-for-property-names.md
new file mode 100644
index 0000000..3b253f0
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/010_should-use-camel-case-for-property-names.md
@@ -0,0 +1,28 @@
+---
+type: SHOULD
+id: R004010
+---
+
+# use camelCase for property names
+
+Property names of JSON objects should be formatted in camelCase.
+
+DO
+
+````json
+{
+ "name": "John",
+ "jobDescription": "product manager",
+ "vacationDays": 37
+}
+````
+
+DON'T
+
+````json
+{
+ "NAME": "John",
+ "job-description": "product manager",
+ "vacationdays": 37
+}
+````
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/020_must-use-same-semantics-for-null-and-absent-properties.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/020_must-use-same-semantics-for-null-and-absent-properties.md
new file mode 100644
index 0000000..66db1a5
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/020_must-use-same-semantics-for-null-and-absent-properties.md
@@ -0,0 +1,27 @@
+---
+type: MUST
+id: R004020
+---
+
+# use same semantics for null and absent properties
+
+If a property is `nullable` and `not required`, a property `null` value and an absent property must be considered semantically equivalent.
+
+So this object with `null property value`:
+
+```json
+{
+ "name": "John",
+ "age": null
+}
+```
+
+should be considered semantically equivalent to this object with `absent property`:
+
+```json
+{
+ "name": "John"
+}
+```
+
+`Note`{ label } `PATCH` endpoints are an exception to this rule (see [MUST use HTTP methods correctly](R000007)). Regarding the example above, a `PATCH` request with the first object would set the `name` to `John` and the `age` to `null`, whereas a request with the second object would only modify the `name`.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/030_should-omit-optional-properties.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/030_should-omit-optional-properties.md
new file mode 100644
index 0000000..aad4f9f
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/030_should-omit-optional-properties.md
@@ -0,0 +1,25 @@
+---
+type: SHOULD
+id: R004021
+---
+
+# omit optional properties
+
+Although [null and absent properties are semantically equivalent](R004020), optional properties should be omitted instead of null whenever applicable.
+
+DO
+
+```json
+{
+ "paymentMethod": "INVOICE_SINGLE"
+}
+```
+
+DON'T
+
+```json
+{
+ "paymentMethod": "INVOICE_SINGLE",
+ "installments": null
+}
+```
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/040_must-always-return-JSON-objects-as-top-level-data-structure.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/040_must-always-return-JSON-objects-as-top-level-data-structure.md
new file mode 100644
index 0000000..ed64511
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/040_must-always-return-JSON-objects-as-top-level-data-structure.md
@@ -0,0 +1,23 @@
+---
+type: MUST
+id: R004030
+reviewType: automatic
+---
+
+# always return JSON objects as top-level data structure
+
+The top-level data structure of your JSON response should always be a JSON object and not, for example, an array.
+
+DO
+
+```json
+{
+ "searchSuggestions": ["gaming pc", "gaming laptop", "gaming monitor"]
+}
+```
+
+DON'T
+
+```json
+["gaming pc", "gaming laptop", "gaming monitor"]
+```
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/050_should-represent-maps-as-objects-with-keys-being-properties.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/050_should-represent-maps-as-objects-with-keys-being-properties.md
new file mode 100644
index 0000000..1c836a3
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/050_should-represent-maps-as-objects-with-keys-being-properties.md
@@ -0,0 +1,53 @@
+---
+type: SHOULD
+id: R004040
+---
+
+# represent maps as objects with keys being their property names
+
+Strive to model your schema consumer-agnostic. That implies:
+
+- don't expect your consumer to use a certain technology, library or framework
+- don't fulfill consumer-specific requirements such as indexing data, as other consumers have different requirements.
+
+DON'T
+
+```json
+{
+ "availableVariantsByColor": [
+ {
+ "key": "red",
+ "value": ["L", "XL"]
+ },
+ {
+ "key": "blue",
+ "value": ["S", "XL"]
+ },
+ {
+ "key": "green",
+ "value": ["L"]
+ }
+ ]
+}
+```
+
+This example violates both of the above rules because:
+
+- the data is grouped by color. Another consumer might require the data to be grouped by size
+- the dictionary representation of data uses a custom meta-schema instead of native json objects.
+
+DO
+
+```json
+{
+ "availableVariants": [
+ { "color": "red", "size": "L" },
+ { "color": "red", "size": "XL" },
+ { "color": "blue", "size": "S" },
+ { "color": "blue", "size": "XL" },
+ { "color": "green", "size": "L" }
+ ]
+}
+```
+
+If the consumer is not able to create a backend for the frontend, the API provider can provide a subresource e.g. `[...]/available-variants`, which allows filtering and sorting in different ways.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/060_should-pluralize-array-names.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/060_should-pluralize-array-names.md
new file mode 100644
index 0000000..1591555
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/060_should-pluralize-array-names.md
@@ -0,0 +1,32 @@
+---
+type: SHOULD
+id: R004050
+---
+
+# pluralize array names
+
+Arrays should have pluralized names whereas objects should be named in singular.
+
+DO
+
+````json
+{
+ "imageData": {
+ "imageBrand": "i.otto.de/i/otto/2212",
+ "imageShop": "i.otto.de/i/otto/86"
+ },
+ "keys": ["ffe6372af30", "d8e6372af40"]
+}
+````
+
+DON'T
+
+````json
+{
+ "images": {
+ "imageBrand": "i.otto.de/i/otto/2212",
+ "imageShop": "i.otto.de/i/otto/86"
+ },
+ "keyCollection": ["ffe6372af30", "d8e6372af40"]
+}
+````
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/070_should-not-use-null-for-empty-arrays.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/070_should-not-use-null-for-empty-arrays.md
new file mode 100644
index 0000000..0e34dff
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/070_should-not-use-null-for-empty-arrays.md
@@ -0,0 +1,24 @@
+---
+type: SHOULD NOT
+id: R004060
+---
+
+# use null for empty arrays
+
+Arrays should be empty and not null if there is no data to provide.
+
+DO
+
+````json
+{
+ "entries": []
+}
+````
+
+DON'T
+
+````json
+{
+ "entries": null
+}
+````
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/080_should-support-filtering-of-fields-using-common-query-parameter.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/080_should-support-filtering-of-fields-using-common-query-parameter.md
new file mode 100644
index 0000000..dbe89ed
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/080_should-support-filtering-of-fields-using-common-query-parameter.md
@@ -0,0 +1,18 @@
+---
+type: SHOULD
+id: R004070
+---
+
+# support filtering of fields using common query parameter
+
+To reduce potential load on the server and reduce the payload size, you can use the `fields` query parameter to specify the set of properties you are interested in and that will be included in the response.
+You should also support filtering of nested properties.
+
+Examples:
+
+- `fields=(name)`: include only field `name`
+- `fields=(name,id)`: include field `name` and `id`
+- `fields=(name,friends(id,name))`: include field `name` and `friends`, with `friends` only having `id` and `name` properties
+
+References:
+- [MUST stick to conventional query parameters](R000049)
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/090_must-represent-enumerations-as-strings.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/090_must-represent-enumerations-as-strings.md
new file mode 100644
index 0000000..469a98a
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/090_must-represent-enumerations-as-strings.md
@@ -0,0 +1,17 @@
+---
+type: MUST
+id: R004080
+---
+
+# represent enumerations as strings
+
+An enumeration is a human readable representation of data.
+Therefore, strings are a good data type choice for enumerations.
+
+Example:
+
+````json
+{
+ "clientStatus": "NOT_ACTIVE"
+}
+````
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/100_must-format-enumerations-in-upper-snake-case.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/100_must-format-enumerations-in-upper-snake-case.md
new file mode 100644
index 0000000..a61aa49
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/010_Naming-conventions/100_must-format-enumerations-in-upper-snake-case.md
@@ -0,0 +1,26 @@
+---
+type: MUST
+id: R004090
+---
+
+# format enumerations in UPPER_SNAKE_CASE
+
+In order to easily distinguish between values and properties, it is best practice to write enumerations in UPPER_SNAKE_CASE format.
+
+DO
+
+````json
+{
+ "eventType": "EMAIL",
+ "clientStatus": "STOPPED_AFTER_ERROR"
+}
+````
+
+DON'T
+
+````json
+{
+ "eventType": "Email",
+ "clientStatus": "stoppedAfterError"
+}
+````
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/000_index.md
new file mode 100644
index 0000000..8179ad8
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/000_index.md
@@ -0,0 +1 @@
+# Canonical data types
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/010_must-use-common-data-formats.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/010_must-use-common-data-formats.md
new file mode 100644
index 0000000..9e8a6ea
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/010_must-use-common-data-formats.md
@@ -0,0 +1,77 @@
+---
+type: MUST
+id: R100071
+---
+
+# use common data formats
+
+Use standard data formats as defined in
+
+- [OpenAPI Specification: Data Types](http://spec.openapis.org/oas/v3.0.3#data-types)
+- [JSON Schema: Built-in formats](https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.7.3)
+
+The following is a non-exhaustive table of common formats.
+
+Format names starting with `otto:` are not defined by OpenAPI or JSON Schema and are specific to the OTTO organisation.
+They represent formats that are not covered or are extensions of existing ones.
+
+| type | format | spec | example | comment | |
+| ------- | --------------------- | -------------------------------------- | -------------------------------------- | ------------------------------- | --------------------------- |
+| integer | int32 | | | signed 32 bits |
+| integer | int64 | | | | signed 64 bits (a.k.a long) |
+| number | float | | | | |
+| number | double | | | | |
+| string | | | | | |
+| string | byte | | | base64 encoded characters | |
+| string | binary | | | any sequence of octets | |
+| boolean | | | | | |
+| string | date | [RFC3339] - `full-date` | `2020-06-16` | see also [date rule][rule-date] | |
+| string | date-time | [RFC3339] - `date-time` | `2020-06-16T04:05:06Z` | see also [date rule][rule-date] | |
+| string | time | [RFC3339] - `full-time` | `04:05:06Z` | see also [date rule][rule-date] | |
+| string | duration | [RFC3339] - `duration` | `P1DT12H` (1 day 12 hours) | | |
+| string | password | | `passw0rd` | a hint for processing/display | |
+| string | email | [RFC5322][rfc5322] | `example@example.com` | internationalized email | |
+| string | idn-email | [RFC5322][rfc5322] | | | |
+| string | hostname | [RFC1123][rfc1123], [RFC5891][rfc5891] | `www.otto.de` | internationalized hostname | |
+| string | idn-hostname | [RFC1123][rfc1123], [RFC5890][rfc5890] | | | |
+| string | ipv4 | [RFC2673][rfc2673] | `127.0.0.1` | | |
+| string | ipv6 | [RFC2673][rfc2673] | `0:0:0:0:0:0:0:1` | | |
+| string | uri | [RFC3986][rfc3986] | `http://otto.de` | | |
+| string | uri-reference | [RFC3986][rfc3986] | | | |
+| string | uri-template | [RFC6570][rfc6570] | `http://api.otto.de/users/{userId}` | | |
+| string | iri | [RFC3987][rfc3987] | | internationalized URI | |
+| string | iri-reference | [RFC3987][rfc3987] | | internationalized URI-reference | |
+| string | uuid | [RFC4122][rfc4122] | `f81d4fae-7dec-11d0-a765-00a0c91e6bf6` | | |
+| string | json-pointer | [RFC6901][rfc6901] | `/foo/0` | | |
+| string | relative-json-pointer | [DRAFT json-pointer][json-pointer] | `1/nested/objects` | | |
+| string | regex | [ECMA-262][ecma-262] | `[a-f]+[0-9]*` | | |
+| string | otto:country-code | [ISO 3166-1-alpha2][iso3166-1-alpha2] | `DE`, `GB` | | |
+| string | otto:language-code | [ISO 639-1][iso639-1], [BCP 47][bcp47] | `de`, `de-DE`, `en`, `en-US` | | |
+| string | otto:currency-code | [ISO 4217][iso4217] | `EUR`, `USD`, `CHF` | | |
+
+These format names are intended to be used in the OpenAPI specification provided by the service.
+
+
+References:
+- [MUST provide API specification using OpenAPI](@guidelines/R000003)
+- [MUST provide OpenAPI specification for profiles](@guidelines/R100067)
+
+[rule-date]: ./020_must-use-common-date-and-time-format.md
+[rfc3339]: https://tools.ietf.org/html/rfc3339#section-5.6
+[rfc5322]: https://tools.ietf.org/html/rfc5322#section-3.4.1
+[rfc6531]: https://tools.ietf.org/html/rfc6531
+[rfc1123]: https://tools.ietf.org/html/rfc1123#section-2.1
+[rfc5891]: https://tools.ietf.org/html/rfc5891#section-4.4
+[rfc5890]: https://tools.ietf.org/html/rfc5890#section-2.3.2.3
+[rfc2673]: https://tools.ietf.org/html/rfc2673#section-3.2
+[rfc3986]: https://tools.ietf.org/html/rfc3986
+[rfc3987]: https://tools.ietf.org/html/rfc3987
+[rfc6901]: https://tools.ietf.org/html/rfc6901#section-5
+[json-pointer]: https://tools.ietf.org/html/draft-handrews-relative-json-pointer-02
+[ecma-262]: https://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf
+[rfc6570]: https://tools.ietf.org/html/rfc6570
+[rfc4122]: https://tools.ietf.org/html/rfc4122
+[iso3166-1-alpha2]: https://www.iso.org/iso-3166-country-codes.html
+[iso639-1]: https://www.loc.gov/standards/iso639-2/php/English_list.php
+[bcp47]: https://tools.ietf.org/html/bcp47
+[iso4217]: https://www.currency-iso.org/en/home/tables/table-a1.html
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/020_must-use-common-date-and-time-format.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/020_must-use-common-date-and-time-format.md
new file mode 100644
index 0000000..917999a
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/020_Canonical-data-types/020_must-use-common-date-and-time-format.md
@@ -0,0 +1,36 @@
+---
+type: MUST
+id: R100072
+---
+
+# use common date and time format
+
+Use the `full-date`, `date-time` or `full-time` format as defined in [RFC3339][rfc3339].
+
+Examples:
+
+`full-date`:
+
+- `2020-06-16`
+- `1986-12-01`
+
+`date-time`:
+
+- `2020-06-16T04:05:06Z`
+- `2020-10-05T11:23:09+02:00`
+- `1986-12-01T05:12:55.12Z`
+
+Use `date-time` in UTC without time zone (e.g. `2020-06-16T12:53:11Z`).
+
+In the [OpenAPI specification][openapi-specification-data-types] `full-date` corresponds to `date`, `date-time` corresponds to `date-time`.
+In the [JSON Schema specification][json-schema-spec-defined-formats] `full-time` corresponds to `time`.
+
+HTTP headers must use the date format recommended by the HTTP specification [RFC7231][rfc7231] (e.g. `Sun, 06 Nov 1994 08:49:37 GMT`).
+
+References:
+- [MUST use common data formats](@guidelines/R100071)
+
+[rfc3339]: https://tools.ietf.org/html/rfc3339#section-5.6
+[json-schema-spec-defined-formats]: https://json-schema.org/draft/2019-09/json-schema-validation.html#rfc.section.7.3
+[openapi-specification-data-types]: http://spec.openapis.org/oas/v3.0.3#data-types
+[rfc7231]: https://tools.ietf.org/html/rfc7231#section-7.1.1.1
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/000_index.md
new file mode 100644
index 0000000..326718a
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/000_index.md
@@ -0,0 +1 @@
+# Identifiers
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/010_should-not-use-lid-to-identify-customers.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/010_should-not-use-lid-to-identify-customers.md
new file mode 100644
index 0000000..9f1999f
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/010_should-not-use-lid-to-identify-customers.md
@@ -0,0 +1,11 @@
+---
+type: SHOULD NOT
+id: R100074
+---
+
+# use lId (or loginId) to identify customers
+
+The lId (or loginId) was introduced for one specific, limited usecase and is a suboptimal way to identify logged in customers.
+On a technical level one customer can have a multitude of different lIds.
+
+It is also not trivially possible for endpoints or clients derive the customer the lId refers to without knowledge of a common secret which is privileged knowledge.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/020_should-use-customerid-to-identify-customers.md b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/020_should-use-customerid-to-identify-customers.md
new file mode 100644
index 0000000..59b6b64
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/020_JSON/030_Identifiers/020_should-use-customerid-to-identify-customers.md
@@ -0,0 +1,14 @@
+---
+type: SHOULD
+id: R100078
+---
+
+# use customerId to identify customers
+
+The `customerId` is the recommended way to identify logged in customers. It replaces the `ec-uuid`.
+
+In HTTP headers, the `customerId` should be named consistently `X-Customer-Id`.
+
+For the time being, the `sub`-claim of the JWT still contains the `ec-uuid` for tokens granted through the [authorization code grant flow](R000052).
+
+An example is provided in the [OAuth2 section](../../../030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/000_index.md).
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/000_index.md
new file mode 100644
index 0000000..e8f9ddf
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/000_index.md
@@ -0,0 +1,13 @@
+# Compatibility
+
+As long as applications are used, they are subject to change. As applications change, it is likely that the APIs they use or provide will also change occasionally. So that in a distributed system landscape not all applications involved in a communication via an API have to be updated at the same time, it is important to keep changes to the API as transparent as possible for all parties involved in the communication. _Transparency_ in this context means that despite the change, the existing communication parties can continue to communicate without any problems even with the partners who have already implemented the change.
+
+According to this definition, the term _compatibility_ refers solely to the exchange of messages _on the wire_. Further interpretations, such as the API's specification file itself and its possible processing on the tool side (e.g. code generators), are explicitly excluded. However, API providers are of course free to give their consumers further guarantees that go beyond compatibility _on the wire_.
+
+This section deals with topics, such as [compatible API evolution](./010_Compatible-changes/000_index.md), introduction of [new API components](./020_Preview/000_index.md) and finally retiring [obsoleted API components](./030_Deprecation/000_index.md).
+
+The general rules for compatibility included in this section are independent of the API type.
+Versioning and other compatibility rules specific to REST and Event APIs are documented in their respective sections:
+
+- [Compatibility for REST APIs](../../030_REST-GUIDELINES/050_Compatibility/000_index.md)
+- [Compatibility for Event APIs](../../040_EVENT-GUIDELINES/050_Compatibility/index.md)
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/000_index.md
new file mode 100644
index 0000000..451cdcf
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/000_index.md
@@ -0,0 +1,3 @@
+# Compatible changes
+
+Changing existing APIs in a compatible way makes it easier for both API providers and consumers. Providers will have fewer API versions to maintain, while consumers have less need to migrate to a new API version.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/010_should-prefer-compatible-extensions.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/010_should-prefer-compatible-extensions.md
new file mode 100644
index 0000000..16bf8cb
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/010_should-prefer-compatible-extensions.md
@@ -0,0 +1,15 @@
+---
+type: SHOULD
+id: R000028
+---
+
+# prefer compatible extensions
+
+API providers should always prefer to extend APIs in a compatible way. The following rules provide guidance on how to evolve APIs in a backward-compatible way:
+
+- Refer to [best practices (internal link)](https://github.com/otto-ec/ottoapi_guidelines/blob/main/content/references/REST/compatibility.md)] when adding new fields
+- Never change the semantic of fields (e.g. changing the semantic from customer-number to customer-id, as both are different unique customer keys)
+- Input fields may have constraints (e.g. patterns, formats, lengths or business rules, if any are documented alongside the spec) being validated via server-side logic. Never change the validation logic to be more restrictive and make sure that all constraints are clearly explained in the spec documentation and error response description.
+- Enum ranges can be reduced when used as input parameters only if the server is ready to accept and process old range values as well. However, a 422 validation error response with an indication of why the old value is no longer accepted is fine. The enum range can be reduced if it is used as an output parameter.
+- Enum ranges should not be extended when used for output parameters. Clients often interpret the enum type as a closed set of values and might break when receiving new values. However, enum ranges can be extended when used for input parameters.
+- Use extensible enums if enums are likely to be extended due to business requirements (see [SHOULD use extensible enums](@guidelines/R000035)).
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/020_must-not-break-backward-compatibility.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/020_must-not-break-backward-compatibility.md
new file mode 100644
index 0000000..91b62d8
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/020_must-not-break-backward-compatibility.md
@@ -0,0 +1,21 @@
+---
+type: MUST NOT
+id: R000027
+---
+
+# break backward compatibility
+
+API specifications establish a contract between providers and consumers and cannot be broken by unilateral decisions.
+Providers can change their API specifications, but have to ensure their changes won't break existing consuming clients.
+Consumers usually have independent release cycles for their clients, focusing more on stability and avoiding changes that do not add value.
+
+There are two ways to change APIs without breaking them:
+
+- Follow the rules for compatible extensions.
+- Introduce new API versions and still support older versions.
+
+We strongly encourage using compatible API extensions and discourage versioning.
+The guidelines for API providers ([SHOULD prefer compatible extensions](@guidelines/R000028)) and consumers ([MUST prepare consumers to accept compatible API extensions](@guidelines/R000029)) enable us (having Postel’s Law in mind) to make compatible changes without versioning.
+
+There is a difference between incompatible and breaking changes. Breaking changes break existing clients, when deployed into operation.
+However, in specific controlled situations, it is possible to deploy incompatible changes in a non-breaking way if no consuming client is using or plans to use the affected API aspects (see also [Deprecation](../030_Deprecation/000_index.md)).
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/030_must-prepare-consumers-to-accept-compatible-api-extensions.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/030_must-prepare-consumers-to-accept-compatible-api-extensions.md
new file mode 100644
index 0000000..a187cc2
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/030_must-prepare-consumers-to-accept-compatible-api-extensions.md
@@ -0,0 +1,16 @@
+---
+type: MUST
+id: R000029
+---
+
+# prepare consumers to accept compatible API extensions
+
+API consumers should apply the robustness principle:
+
+- Be conservative with API inputs and avoid exploiting definition deficits. For example, do not pass megabytes of content for an input string that has no defined maximum length.
+- Be tolerant of processing and reading data from API output.
+
+More specifically, API consumers must be prepared for compatible API extensions of API providers:
+
+- Be tolerant with unknown fields in the payload (see also Martin Fowler’s post about ["TolerantReader"](http://martinfowler.com/bliki/TolerantReader.html)).
+- Be prepared that `x-extensible-enum` output types may deliver new values; either be agnostic or provide default behavior for unknown values (see [SHOULD use extensible enums](@guidelines/R000035)).
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/040_should-use-extensible-enums.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/040_should-use-extensible-enums.md
new file mode 100644
index 0000000..9915792
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/040_should-use-extensible-enums.md
@@ -0,0 +1,48 @@
+---
+type: SHOULD
+id: R000035
+---
+
+# use extensible enums
+
+Enums (represented by `enum` keyword) are not extensible in JSON schema. Adding a new enum value is considered as a breaking change if used in responses.
+
+Clients need to be prepared that new enum values may be added to an enum without creating a new version. The extension property `x-extensible-enum` has been introduced to clearly signal this intention. The `x-extensible-enum` property contains an open list of values. Each value may have the following properties:
+
+| Property | Required | Default value | Description |
+| ----------- | -------- | ------------- | -------------------------------------------------------------------- |
+| value | yes | n/a | The extensible enum value. Must adhere to the specified type. |
+| description | yes | n/a | Describes the semantic meaning of the value. |
+| deprecated | no | false | A boolean value specifying the deprecation state of this enum value. |
+| preview | no | false | A boolean value specifying the preview state of this enum value. |
+
+`x-extensible-enum` should be used instead of `enum` unless the following applies:
+
+- The service providing the API owns the enum values. It is part of its domain knowledge.
+- The enum represents a closed set in the business domain that will never be extended, even in the future.
+
+Example usage:
+
+```yaml
+PaymentType:
+ type: string
+ description: Describes the payment further.
+ x-extensible-enum:
+ - value: CREDIT_CARD
+ description: Credit card payment
+ - value: INVOICE
+ description: Payment by the customer by bank transfer.
+ deprecated: true
+ - value: DIRECT_DEBIT
+ description: Direct debit from a bank account.
+ preview: true
+```
+
+Do not use the `enum` keyword in combination with `x-extensible-enum`.
+
+Note that the "x-extensible-enum" extension property is ignored by most tools. When API clients need to process the different values, the logic must be added manually. This results in extra work for the consumers, but guarantees that automatically generated clients do not break when adding new values.
+
+References:
+- [SHOULD prefer compatible extensions](@guidelines/R000028)
+- [`enum` in JSON Schema](http://json-schema.org/understanding-json-schema/reference/generic.html#enumerated-values)
+- [Zalando's rule for `x-extensible-enum`](https://opensource.zalando.com/restful-api-guidelines/#112)
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/020_Preview/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/020_Preview/000_index.md
new file mode 100644
index 0000000..2629f60
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/020_Preview/000_index.md
@@ -0,0 +1,3 @@
+# Preview of API changes
+
+One of the main consequences of [contract first](../../../010_CORE-PRINCIPLES/040_Contract-first.md) is that agreed API specifications are published that are not yet or not fully implemented. To make this transparent for all API consumers, there must be the possibility to mark corresponding parts in the API specification as such.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/020_Preview/010_must-not-rely-on-preview.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/020_Preview/010_must-not-rely-on-preview.md
new file mode 100644
index 0000000..a47fb2f
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/020_Preview/010_must-not-rely-on-preview.md
@@ -0,0 +1,9 @@
+---
+type: MUST NOT
+id: R000077
+appliesTo: client
+---
+
+# rely on API components marked as preview
+
+API specification components marked as preview are intended to inform API consumers about upcoming changes or additions. Details of both the specification and implementation are subject to change and, in case of doubt, will not be used productively, so a productive application should not rely on their availability and reliability. If an API consumer relies on appropriately marked API components, they must check with the API provider to find out when these changes will take effect, and only then can they go live with their own updated API client.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/000_index.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/000_index.md
new file mode 100644
index 0000000..4334178
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/000_index.md
@@ -0,0 +1,7 @@
+# Deprecation of obsolete API versions and components
+
+Sometimes it is necessary to phase out an API, an API version or an API feature.
+For example, a property is no longer supported, or a whole business functionality is supposed to be removed.
+As long as consumers still use API features, removal of these is a breaking change and not allowed.
+The following deprecation rules have to be applied to ensure that the necessary consumer changes and actions are well communicated and aligned using _deprecation_ and _sunset_ schedules.
+The deprecation phase precedes the final sunset date.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/010_must-obtain-approval-of-consumers-before-api-shutdown.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/010_must-obtain-approval-of-consumers-before-api-shutdown.md
new file mode 100644
index 0000000..d3d4dfb
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/010_must-obtain-approval-of-consumers-before-api-shutdown.md
@@ -0,0 +1,10 @@
+---
+type: MUST
+id: R000054
+---
+
+# obtain approval of consumers before API shutdown
+
+Before shutting down an API, an API version or feature, the API provider must ensure that all consumers have given their consent on a sunset date.
+The API provider should help consumers to migrate to a potential new API or API feature by providing a migration manual and clearly stating the timeline for replacement availability and sunset (see also [SHOULD add `Deprecation` and `Sunset` header to responses](@guidelines/R000069)).
+Once all API consumers have migrated their affected clients, the API provider may shut down the deprecated API feature.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/020_must-collect-external-partner-consent-on-deprecation-time-span.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/020_must-collect-external-partner-consent-on-deprecation-time-span.md
new file mode 100644
index 0000000..a2c3d1e
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/020_must-collect-external-partner-consent-on-deprecation-time-span.md
@@ -0,0 +1,9 @@
+---
+type: MUST
+id: R000066
+---
+
+# collect external partner consent on deprecation time span
+
+If the API is actively consumed, the API provider must define a reasonable time span that the API will be maintained after having announced deprecation.
+All consumers must state consent with this after-deprecation-life-span, that means the minimum time span between official deprecation and first possible sunset, **before** they are allowed to use the API.
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/030_must-reflect-deprecation-in-api-specifications.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/030_must-reflect-deprecation-in-api-specifications.md
new file mode 100644
index 0000000..e3b45d5
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/030_must-reflect-deprecation-in-api-specifications.md
@@ -0,0 +1,20 @@
+---
+type: MUST
+id: R000067
+---
+
+# reflect deprecation in specifications
+
+The deprecation of API elements must be part of the specification (e.g. OpenAPI or AsyncAPI). Each specification format allows for different elements to be deprecated.
+
+The API provider must set `deprecated: true` for the affected element and add further explanation to the `description` section of the API specification.
+
+If an API version or feature is deprecated, the API provider must:
+
+- specify a sunset date in the description
+- document in detail what consumers should use instead
+- document how to migrate.
+
+References:
+- [OpenAPI deprecated attribute for Schema Object](https://swagger.io/specification/#schema-object)
+- [AsyncAPI deprecated attribute for Schema Object](https://www.asyncapi.com/docs/specifications/v2.3.0#schemaObject)
diff --git a/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/040_must-not-start-using-deprecated-apis.md b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/040_must-not-start-using-deprecated-apis.md
new file mode 100644
index 0000000..62d1009
--- /dev/null
+++ b/03_api_guidelines/020_GENERAL-GUIDELINES/030_Compatibility/030_Deprecation/040_must-not-start-using-deprecated-apis.md
@@ -0,0 +1,9 @@
+---
+type: MUST NOT
+id: R000071
+appliesTo: client
+---
+
+# not start using deprecated APIs
+
+Consumers must not start using deprecated APIs, API versions or API features.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/001_Contract/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/001_Contract/000_index.md
new file mode 100644
index 0000000..a278f27
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/001_Contract/000_index.md
@@ -0,0 +1,3 @@
+# Contract
+
+This section describes the rules specific to the contract of REST APIs. Also consider the rules defined in [Basics](../../020_GENERAL-GUIDELINES/010_Basics/000_index.md).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/001_Contract/010_OpenAPI-specification/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/001_Contract/010_OpenAPI-specification/000_index.md
new file mode 100644
index 0000000..e69de29
diff --git a/03_api_guidelines/030_REST-GUIDELINES/001_Contract/010_OpenAPI-specification/010_must-provide-api-specification-using-openapi-for-rest-apis.md b/03_api_guidelines/030_REST-GUIDELINES/001_Contract/010_OpenAPI-specification/010_must-provide-api-specification-using-openapi-for-rest-apis.md
new file mode 100644
index 0000000..4d4f8b2
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/001_Contract/010_OpenAPI-specification/010_must-provide-api-specification-using-openapi-for-rest-apis.md
@@ -0,0 +1,12 @@
+---
+type: MUST
+id: R000003
+---
+
+# provide API specification using OpenAPI for REST APIs
+
+We use the OpenAPI specification as a standard to define API specification files.
+Every API must be described using the OpenAPI specification.
+
+The API description format used must be [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification).
+We will extend it according to our needs by using vendor tags in order to describe the functionality that we require.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/001_Contract/010_OpenAPI-specification/030_must-use-semantic-versioning-in-openapi-specification-files.md b/03_api_guidelines/030_REST-GUIDELINES/001_Contract/010_OpenAPI-specification/030_must-use-semantic-versioning-in-openapi-specification-files.md
new file mode 100644
index 0000000..28a7227
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/001_Contract/010_OpenAPI-specification/030_must-use-semantic-versioning-in-openapi-specification-files.md
@@ -0,0 +1,21 @@
+---
+type: MUST
+id: R000064
+---
+
+# use semantic versioning in OpenAPI specification files
+
+In order to generate meaningful changelogs and version numbers, OpenAPI specification files need to follow [semantic versioning](https://semver.org).
+
+```yaml
+openapi: 3.0.3
+
+# [...]
+info:
+ title: My Product API
+ description: Provides basic product information.
+ contact:
+ name: FT X
+ email: FTX-DEV@otto.de
+ version: 1.0.0
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/000_index.md
new file mode 100644
index 0000000..17257a2
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/000_index.md
@@ -0,0 +1 @@
+# Authorization
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/000_index.md
new file mode 100644
index 0000000..650d648
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/000_index.md
@@ -0,0 +1,108 @@
+# OAuth 2.0
+
+The API uses [OAuth 2.0](https://oauth.net/2/) for authorization.
+For the implementation we try to comply with the standards as much as possible.
+Here's some general information.
+
+## Discovery
+
+The OTTO API provides an [endpoint](https://api.otto.de/.well-known/openid-configuration) that can be used for [OAuth 2.0 endpoint discovery](https://tools.ietf.org/html/draft-ietf-oauth-discovery-06).
+Clients can use the returned information to obtain details about the OAuth 2.0 authorization server such as the token and userinfo endpoints as well as the supported OAuth 2.0 flows.
+
+## Client Management
+
+OAuth clients and scopes are managed through [Herakles](https://olymp.live.shozu.cloud.otto.de/#/herakles/) (internal link).
+
+
+## JSON Web Token
+
+As [proposed by the OAuth working group](https://tools.ietf.org/html/draft-ietf-oauth-access-token-jwt-07) the access tokens used for the OTTO API are JSON Web Tokens (JWT) as defined in [RFC 7797](https://tools.ietf.org/html/rfc7797).
+
+In short: JWTs are [URL safe base64](https://tools.ietf.org/html/rfc4648#section-5) encrypted JSON documents that encode a
+
+- cryptographic algorithm & token type
+- payload (containing, among other things, the expiration date and scope(s) of the token) and
+- signature to allow decentralized verification of said payload
+
+`Note`{ label } You can find examples, a validator and a collection of libraries for different languages as well as runtime environments at [jwt.io](https://jwt.io/).
+
+### Example Token
+
+The JSON content parts of the decoded token look like this:
+
+**Header**
+
+```json
+{
+ "alg": "RS256", // algorithm used for signature
+ "kid": "public:0235e46d-c7d0-42a4-8f69-c1cb127608e8", // the signing key id
+ "typ": "JWT"
+}
+```
+
+**Payload**
+
+```json
+{
+ "aud": ["https://api.otto.de"],
+ "client_id": "f3b9910a-08ea-4b6b-895a-261674e573b9", // OAuth client ID that requested the token
+ "exp": 1591892081, // epoch time at which the token expires
+ "ext": {},
+ "iat": 1591888481, // epoch time the token was issued at
+ "iss": "https://api.otto.de/", // issuer of the token
+ "jti": "6f76d949-fad5-4634-ba4f-b7ebf9d32ade", // (unique) ID of the token itself
+ "nbf": 1591888481, // epoch time the token must not be accepted before
+ "scp": ["otto.read"], // the scope the token is granting access to
+ "sub": "8d0c8242d4654d41858e150f5ef5b3deccd749d3" // (if applicable) the subject of the token, in this case a customer
+}
+```
+
+## Large Bearer Tokens
+Requesting a large number of scopes will result in large Bearer Tokens. Servers might reject requests containing an `Authorization` header that is larger than 4kB with `413 Payload Too Large` status code.
+
+## JSON Web Key Set
+
+With [JSON Web Key Set (JWKS)](https://tools.ietf.org/html/rfc7517), an API can specify the keys it uses to sign its JSON Web Tokens.
+For all keys in use it specifies, among other things:
+
+- the key type (e.g. RSA, EC)
+- the intended use of the key (e.g. encryption or signing)
+- the key ID
+- the specific cryptographic algorithm used
+- the key itself
+
+For a full list of parameters see [RFC7517, Section 4](https://tools.ietf.org/html/rfc7517#section-4).
+
+An API publishes the keys it uses at `.well-known/jwks.json`.
+This allows both clients and endpoints to easily validate the keys used to sign tokens.
+Even the API provider can use it to easily rotate keys without manual overhead for API clients or endpoint providers.
+
+You can find the key set for the OTTO API at [https://api.otto.de/.well-known/jwks.json](https://api.otto.de/.well-known/jwks.json).
+
+## Refresh Tokens
+
+Once an access token expires or is about to expire, clients might still need access to OAuth 2.0 protected resources.
+Usually this means that the user will be forced to grant permission by re-authenticating.
+
+To solve this, OAuth 2.0 introduced [refresh tokens](https://tools.ietf.org/html/rfc6749#section-1.5) as part of the access token response.
+A refresh token allows an application to obtain a new access token in the background without prompting the user for login credentials and thus not interrupting the user journey.
+Typical clients that need a refresh token are mobile and web applications that want to keep the user authenticated for longer than the lifetime of the default access token without having to regularly re-authenticate the user.
+
+`Note`{ label } A refresh token can only be used once and must be replaced after usage.
+
+In order to refresh an access token, a client needs to extract the `refresh_token` attribute that comes as part of the JSON response when requesting an access token, and store it for later usage.
+When the access token is about to expire the client will use the grant type `refresh_token` (instead of `authorization_code` or `client_credentials`) to fetch a new token.
+
+Example:
+
+```http request
+POST /oauth2/token HTTP/1.1
+Host: api.otto.de
+
+grant_type=refresh_token
+&refresh_token=xxxxxxxxxxx
+&client_id=xxxxxxxxxx
+&client_secret=xxxxxxxxxx
+```
+
+The response to the refresh token grant is the same as when issuing an access token. You can optionally issue a new refresh token in the response, or if you don’t include a new refresh token, the client assumes the current refresh token will continue to be valid.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/010_must-secure-endpoints-with-oauth2.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/010_must-secure-endpoints-with-oauth2.md
new file mode 100644
index 0000000..1f4e1cb
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/010_must-secure-endpoints-with-oauth2.md
@@ -0,0 +1,8 @@
+---
+type: MUST
+id: R000051
+---
+
+# secure endpoints with OAuth 2.0
+
+Every API endpoint needs to be secured using OAuth 2.0.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/020_must-use-authorization-grant.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/020_must-use-authorization-grant.md
new file mode 100644
index 0000000..676eadd
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/020_must-use-authorization-grant.md
@@ -0,0 +1,23 @@
+---
+type: MUST
+id: R000052
+reviewType: automatic
+---
+
+
+
+# use Authorization Grant
+
+Authorization Grant is a credential representing the resource owner's authorization (to access its protected resources) used by the client to obtain an access token.
+
+The OTTO API supports two grant types:
+
+- [Authorization Code](https://oauth.net/2/grant-types/authorization-code/)
+- [Client Credentials](https://oauth.net/2/grant-types/client-credentials/)
+
+`Note`{ label } The [Resource Owner Password Credentials](https://oauth.net/2/grant-types/password/) grant type is not supported.
+
+The grant type to be used depends on the use cases outlined in the following rules.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/030-should-use-authorization-code-grant-for-confidential-clients.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/030-should-use-authorization-code-grant-for-confidential-clients.md
new file mode 100644
index 0000000..e3330ed
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/030-should-use-authorization-code-grant-for-confidential-clients.md
@@ -0,0 +1,8 @@
+---
+type: SHOULD
+id: R000056
+---
+
+# use Authorization Code Grant for confidential clients
+
+The [Authorization Code](https://oauth.net/2/grant-types/authorization-code) grant type should be used by confidential clients to exchange an authorization code for access token and optional refresh token.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/040-should-use-client-credentials-grant-for-machine-to-machine-authorization.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/040-should-use-client-credentials-grant-for-machine-to-machine-authorization.md
new file mode 100644
index 0000000..14591a9
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/040-should-use-client-credentials-grant-for-machine-to-machine-authorization.md
@@ -0,0 +1,8 @@
+---
+type: SHOULD
+id: R000057
+---
+
+# use Client Credentials Grant for machine to machine authorization
+
+The [Client Credentials](https://oauth.net/2/grant-types/client-credentials) grant should be used for machine-to-machine authorization to obtain an access token **outside of the context of a user**.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/050_must-use-pkce-for-mobile-and-javascript-apps.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/050_must-use-pkce-for-mobile-and-javascript-apps.md
new file mode 100644
index 0000000..d490b5b
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/050_must-use-pkce-for-mobile-and-javascript-apps.md
@@ -0,0 +1,14 @@
+---
+type: MUST
+id: R000053
+appliesTo: client
+---
+
+# use Proof Key for Code Exchange (PKCE) for mobile and JavaScript apps
+
+[PKCE](https://oauth.net/2/pkce) ([RFC 7636](https://tools.ietf.org/html/rfc7636)) is an extension to the Authorization Code flow to prevent certain attacks and to be able to securely perform the OAuth 2.0 exchange especially for public clients.
+Clients must use SHA256 to encrypt the code challenge and set the `code_challenge_method` parameter to `S256`.
+
+Tip:
+PKCE can be applied to any OAuth 2.0 client and is not restricted to public clients.
+
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/060_must-not-use-implicit-grant-flow.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/060_must-not-use-implicit-grant-flow.md
new file mode 100644
index 0000000..1347f43
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/060_must-not-use-implicit-grant-flow.md
@@ -0,0 +1,11 @@
+---
+type: MUST NOT
+id: R000055
+appliesTo: client
+---
+
+# use Implicit Grant flow
+
+The [Implicit Grant](https://oauth.net/2/grant-types/implicit) flow was a simplified OAuth flow previously recommended for native apps and JavaScript apps where the access token was returned immediately without an extra authorization code exchange step.
+
+It is not recommended to use the implicit flow (and some servers prohibit this flow entirely) due to the inherent risks of access tokens being returned in an HTTP redirect without confirmation that they were received by the client.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/070_must-use-bearer-authentication.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/070_must-use-bearer-authentication.md
new file mode 100644
index 0000000..dd9d3a7
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/010_OAuth-2.0/070_must-use-bearer-authentication.md
@@ -0,0 +1,18 @@
+---
+type: MUST
+id: R000021
+appliesTo: client
+---
+
+# use Bearer Authentication
+
+Clients resending HTTP requests to the OTTO API must use the `Authorization` header to submit their JWT token to the server using the [Bearer Token](https://tools.ietf.org/html/rfc6750#section-2.1) scheme.
+
+Example:
+
+```plaintext
+GET /api/orders HTTP/1.1
+
+Host: api.otto.de
+Authorization: Bearer {JWT Token}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/000_index.md
new file mode 100644
index 0000000..25cd451
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/000_index.md
@@ -0,0 +1 @@
+# Scopes
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/010_must-define-and-assign-permissions-by-using-scopes.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/010_must-define-and-assign-permissions-by-using-scopes.md
new file mode 100644
index 0000000..4f3a6c5
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/010_must-define-and-assign-permissions-by-using-scopes.md
@@ -0,0 +1,26 @@
+---
+type: MUST
+id: R000047
+---
+
+# define and assign permissions by using scopes
+
+Endpoints must define permissions to protect access to their resources.
+Each endpoint must define at least one OAuth 2.0 scope using the defined [naming conventions](R000048).
+
+## Granting permission to public resources
+
+Resources can be classified as _public_.
+This is in the responsibility of the resource owner.
+The OTTO website can serve as a reference for public resources.
+Data that can be accessed there without further login can be defined as public.
+
+For example:
+
+- Product data
+- Deal of the day
+
+However, even endpoints providing public resources [must be secured with OAuth 2.0](R000051).
+To harmonize the access to public resources we defined the special scope `otto.read`, which can be used to secure those resources.
+
+Every resource that **cannot be clearly** classified as public has to be considered as private and is not allowed to use the `otto.read` scope.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/020_shoud-adhere-to-scope-naming-conventions.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/020_shoud-adhere-to-scope-naming-conventions.md
new file mode 100644
index 0000000..283e94b
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/020_Scopes/020_shoud-adhere-to-scope-naming-conventions.md
@@ -0,0 +1,53 @@
+---
+type: SHOULD
+id: R000048
+reviewType: automatic
+---
+
+# adhere to scope naming conventions
+
+OAuth 2.0 scopes represent permissions for different resources.
+Scopes might consist of two parts:
+
+- **Required**: `resource`. The resource for the permission, for example `brands`.
+- **Optional**: `permission`. The action that can be performed on those resources, for example `read` or `write`.
+
+To keep a consistent naming pattern, scopes should be constructed according to the following scheme.
+
+```text
+{resource}.{permission}
+```
+
+`Note`{ label } A scope without explicit permissions grants access to the whole resource.
+
+## Rules
+
+The following additional rules apply for scope names:
+
+- Must only include alphanumeric characters, lowercase letters or the special characters `_` or `-`.
+- Must be delimited with dots.
+- Must be attributable to a resource.
+- Must not include internal product team names as `resource`.
+- `resource` should be pluralized when referring to collections and singular for singleton resources.
+
+## Examples
+
+DO
+
+```plaintext
+products
+products.read
+products.write
+orders
+orders.read
+orders.cancel
+```
+
+DON'T
+
+```text
+Products
+opal.products
+opal.products.read
+product.availability
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/000_index.md
new file mode 100644
index 0000000..80a877f
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/000_index.md
@@ -0,0 +1 @@
+# Tokens
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/010_must-validate-json-web-token.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/010_must-validate-json-web-token.md
new file mode 100644
index 0000000..931bfee
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/010_must-validate-json-web-token.md
@@ -0,0 +1,17 @@
+---
+type: MUST
+id: R000050
+---
+
+# validate JSON Web Token
+
+Each endpoint must validate the JWT that the API client has passed along as the access token for its request.
+
+This includes:
+
+- the cryptographic signature of the token
+- the expiration date of the token
+- the scopes encoded in the token (if they match the endpoint)
+- that the subject (`sub`-claim) has sufficient rights to access a user-specific resource. This is especially important for tokens that have been granted using the OAuth 2.0 authorization code flow.
+
+If either of these are not valid the request is to be denied with an appropriate [status code](../../010_HTTP/030_Status-codes/000_index.md) and [error message](../../040_Errors/010_Error-handling/000_index.md).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/020_must-not-validate-audience-of-the-json-web-token.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/020_must-not-validate-audience-of-the-json-web-token.md
new file mode 100644
index 0000000..78b841e
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/020_must-not-validate-audience-of-the-json-web-token.md
@@ -0,0 +1,11 @@
+---
+type: MUST NOT
+id: R000075
+---
+
+# validate audience of the JSON Web Token
+
+The JWT generated by the OAuth 2.0 Server contains an `aud` field.
+The endpoint has to ignore the field and the possible values of this field.
+
+`Note`{ label } Reserved for future use.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/030_must_validate_JWT_based_on_keys in_JWKS_at_all_endpoints.md b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/030_must_validate_JWT_based_on_keys in_JWKS_at_all_endpoints.md
new file mode 100644
index 0000000..353f2b2
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/005_Authorization/030_Tokens/030_must_validate_JWT_based_on_keys in_JWKS_at_all_endpoints.md
@@ -0,0 +1,11 @@
+---
+type: MUST
+id: R000058
+---
+
+# validate JWT based on keys in JWKS at all endpoints
+
+Each endpoint must validate the JWT used by clients for their requests based on the keys provided by the APIs JWKS mechanism.
+This ensures the keys can be rotated easily and minimizes manual efforts for key exchange.
+
+`Note`{ label } Many libraries already support fetching keys from the API host transparently, if configured to do so.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/000_index.md
new file mode 100644
index 0000000..03fe6a2
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/000_index.md
@@ -0,0 +1 @@
+# HTTP
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/000_index.md
new file mode 100644
index 0000000..8f83418
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/000_index.md
@@ -0,0 +1 @@
+# Methods
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/010_must-use-http-methods-correctly.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/010_must-use-http-methods-correctly.md
new file mode 100644
index 0000000..a0ec716
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/010_must-use-http-methods-correctly.md
@@ -0,0 +1,117 @@
+---
+type: MUST
+id: R000007
+---
+
+# use HTTP methods correctly
+
+We are compliant with the standardized HTTP method semantics described as follows:
+
+`GET` requests are used to **read** either a single or a collection resource.
+
+- For individual resources, `GET` requests will usually generate a `404 Not Found` if the resource does not exist.
+- For collection resources, `GET` requests may return either `200 OK` (if the collection is empty) or `404 Not Found` (if the collection is missing).
+- `GET` requests must NOT have a request body payload (see `GET With Body`).
+
+`Note`{ label } `GET` requests on collection resources should provide sufficient [filter](@guidelines/R000049) and [pagination](@guidelines/R000049) mechanisms.
+
+
+## GET with body
+APIs sometimes need to provide extensive structured request information with `GET`, that may conflict with the size limits of clients, load balancers, and servers.
+As our APIs must be standard compliant (body in `GET` must be ignored on server side), API designers have to check the following two options:
+
+1. `GET` with URL encoded query parameters: if it is possible to encode the request information in query parameters, respecting the usual size limits of clients, gateways, and servers, this should be the first choice.
+ The request information can either be provided via multiple query parameters or by a single structured URL encoded string.
+2. `POST` with body content: if a `GET` with URL encoded query parameters is not possible, a `POST` with body content must be used.
+ In this case the endpoint must be documented with the hint `GET with body` to transport the `GET` semantic of this call.
+
+
+Encoding the lengthy structured request information using header parameters is not an option.
+From a conceptual point of view, the semantic of an operation should always be expressed by the resource names, as well as the involved path and query parameters, that means, by everything that goes into the URL.
+Request headers are reserved for general context information.
+In addition, size limits on query parameters and headers are not reliable and depend on clients, gateways, server, and actual settings.
+Thus, switching to headers does not solve the original problem.
+
+## PUT
+`PUT` requests are used to **update** (in rare cases to create) **entire** resources – single or collection resources.
+The semantic is best described as _"please put the enclosed representation at the resource mentioned by the URL, replacing any existing resource."_.
+
+- `PUT` requests are usually applied to single resources, and not to collection resources, as this would imply replacing the entire collection.
+- `PUT` requests are usually robust against non-existence of resources by implicitly creating before updating.
+- On successful `PUT` requests, the server will **replace the entire resource** addressed by the URL with the representation passed in the payload (subsequent reads will deliver the same payload).
+- Successful `PUT` requests will usually generate `200 OK` or `204 No Content` (if the resource was updated – with or without actual content returned), and `201 Created` (if the resource was created).
+
+`Important:`{ label="warning" } It is best practice to prefer `POST` over `PUT` for creation of (at least top level) resources.
+This leaves the resource ID under control of the service and allows to concentrate on the update semantic using `PUT` as follows.
+
+In the rare cases where `PUT` is also used for resource creation, the resource IDs are maintained by the client and passed as a URL path segment.
+Putting the same resource twice is required to be idempotent and to result in the same single resource instance (see [MUST fulfill common method properties](@guidelines/R000008)).
+
+To prevent unnoticed concurrent updates and duplicate creations when using `PUT`, you [SHOULD consider to support `ETag` together with `If-Match`/`If-None-Match` header](@guidelines/R000060) to allow the server to react on stricter demands that expose conflicts and prevent lost updates.
+
+## POST
+`POST` requests are idiomatically used to **create** single resources on a collection resource endpoint, but other semantics on single resources endpoint are equally possible.
+The semantic for collection endpoints is best described as _"please add the enclosed representation to the collection resource identified by the URL"_.
+
+- On a successful `POST` request, the server will create one or multiple new resources and provide their URI/URLs in the response.
+- Successful `POST` requests will usually generate `200 OK` (if resources have been updated), `201 Created` with [`Location`](https://tools.ietf.org/html/rfc7231#section-7.1.2) header (if resources have been created), `202 Accepted` (if the request was accepted but has not been finished yet), and exceptionally `204 No Content` with [`Location`](https://tools.ietf.org/html/rfc7231#section-7.1.2) header (if the actual resource is not returned).
+
+`POST` should be used for scenarios that cannot be covered by the other methods sufficiently.
+In such cases, make sure to document the fact that `POST` is used as a workaround (see `GET With Body`).
+
+Resource IDs related to `POST` requests are created and managed by the server and returned with the response payload and/or as part of the URL in the [`Location`](https://tools.ietf.org/html/rfc7231#section-7.1.2) header.
+
+Posting the same resource twice is **not** required to be idempotent (check [MUST fulfill common method properties](@guidelines/R000008)) and may result in multiple resources.
+However, you [SHOULD consider to design `POST` and `PATCH` idempotent](@guidelines/R000009) to prevent this.
+
+## PATCH
+
+`PATCH` requests are used to **update parts** of single resources, i.e. where only a specific subset of resource fields should be replaced.
+The semantic is best described as _"please change the resource identified by the URL according to my change request"_.
+The semantic of the change request is not defined in the HTTP standard and must be described in the API specification by using suitable media types.
+
+- `PATCH` requests are usually applied to single resources as patching an entire collection is challenging.
+- `PATCH` requests are usually not robust against non-existence of resource instances.
+- On successful `PATCH` requests, the server will update parts of the resource addressed by the URL as defined by the change request in the payload.
+- Successful `PATCH` requests will usually generate `200 OK` or `204 No Content` (if resources have been updated with or without updated content returned).
+
+As implementing `PATCH` correctly is a bit tricky, we strongly suggest to choose one and only one of the following patterns per endpoint, unless forced by a backwards compatible change. In preferred order:
+
+1. Use [`PUT`](#put) with complete objects to update a resource as long as feasible (i.e. do not use `PATCH` at all).
+2. Use [`PATCH`](#patch) with partial objects to only update parts of a resource, whenever possible. (This is basically [JSON Merge Patch](https://tools.ietf.org/html/rfc7396), a specialized media type `application/merge-patch+json` (sent as `Content-Type` request header) that is a partial resource representation.)
+3. Use [`PATCH`](#patch) with [JSON Patch](https://tools.ietf.org/html/rfc6902), a specialized media type `application/json-patch+json` (sent as `Content-Type` request header) that includes instructions on how to change the resource.
+4. Use [`POST`](#post) (with a proper description of what is happening) instead of [`PATCH`](#patch), if the request does not modify the resource in a way defined by the semantics of the media type.
+
+In practice [JSON Merge Patch](https://tools.ietf.org/html/rfc7396) quickly turns out to be too limited, especially when trying to update single objects in large collections (as part of the resource).
+In this cases [JSON Patch](https://tools.ietf.org/html/rfc6902) can show its full power while still showing readable patch requests (see also [JSON patch vs. merge](http://erosb.github.io/post/json-patch-vs-merge-patch)).
+
+Patching the same resource twice is **not** required to be idempotent (check [MUST fulfill common method properties](@guidelines/R000008)) and may result in a changing result. However, you [SHOULD consider to design `POST` and `PATCH` idempotent](@guidelines/R000009) to prevent this.
+
+`Note:`{ label } To prevent unnoticed concurrent updates when using `PATCH` you [SHOULD consider to support `ETag` together with `If-Match`/`If-None-Match` header](@guidelines/R000060) to allow the server to react on stricter demands that expose conflicts and prevent lost updates.
+Refer to [SHOULD consider to design `POST` and `PATCH` idempotent](@guidelines/R000009) for details and options.
+
+## DELETE
+`DELETE` requests are used to **delete** resources.
+The semantic is best described as _"please delete the resource identified by the URL"_.
+
+- `DELETE` requests are usually applied to single resources, not on collection resources, as this would imply deleting the entire collection.
+- Successful `DELETE` requests will usually generate `200 OK` (if some representation of the deleted resource is returned) or `204 No Content` (if no content is returned).
+ - Depending on the `Access` header of the `DELETE` request, not only a representation of the deleted resource could be returned. Think of returning the whole shopping cart after `DELETE`ing only one lineitem.
+- Failed `DELETE` requests will usually generate `404 Not Found` (if the resource cannot be found) or `410 Gone` (if the resource was already deleted before).
+
+After deleting a resource with `DELETE`, a `GET` request on the resource is expected to either return `404 Not Found` or `410 Gone` depending on how the resource is represented after deletion.
+The resource must not be accessible on its endpoint after this operation.
+
+## HEAD
+`HEAD` requests are used to **retrieve** the header information of single resources and resource collections.
+
+- `HEAD` has exactly the same semantics as `GET`, but returns headers only, no body.
+
+`Note:`{ label } `HEAD` is particular useful to efficiently lookup whether large resources or collection resources have been updated in conjunction with the [`ETag`](https://tools.ietf.org/html/rfc7232#section-2.3) header.
+
+## OPTIONS
+`OPTIONS` requests are used to **inspect** the available operations (HTTP methods) of a given endpoint.
+
+- `OPTIONS` responses usually either return a comma separated list of methods in the `Allow` header or a structured list of link templates.
+
+`Note:`{ label } `OPTIONS` is rarely implemented, though it could be used to self-describe the full functionality of a resource.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/020_must-fulfill-common-method-properties.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/020_must-fulfill-common-method-properties.md
new file mode 100644
index 0000000..283ac54
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/020_must-fulfill-common-method-properties.md
@@ -0,0 +1,33 @@
+---
+type: MUST
+id: R000008
+---
+
+# fulfill common method properties
+
+Request methods in RESTful services can be:
+
+- [safe](https://tools.ietf.org/html/rfc7231#section-4.2.1) - the operation semantic is defined to be read-only, meaning it must not have _intended side effects_, i.e. changes, to the server state.
+- [idempotent](https://tools.ietf.org/html/rfc7231#section-4.2.2) - the operation has the same _intended effect_ on the server state, independently whether it is executed once or multiple times.
+ `Note:`{ label } This does not require that the operation is returning the same response or status code. Especially executing a `DELETE` twice might yield a `200 OK` followed by a `404 Not Found` or even `410 Gone`.
+- [cacheable](https://tools.ietf.org/html/rfc7231#section-4.2.3) - to indicate that responses are allowed to be stored for future reuse.
+ In general, requests to safe methods are cacheable, if no current or authoritative response from the server is required.
+
+Requests can result in numerous server actions such as logging, accounting, collecting metrics, pre-fetching, etc. Clients, however, cannot expect or be held accountable for these _side effects_.
+Some server actions, such as rate limiting, may also cause a server-side state change and produce a different response code as a result. This behavior would still allow the methods to be considered safe or idempotent.
+
+Method implementations must fulfill the following basic properties according to [RFC 7231](https://tools.ietf.org/html/rfc7231):
+
+| Method | Safe | Idempotent | Cacheable |
+| --------- | ---- | ---------- | --------- |
+| `GET` | ✔ | ✔ | ✔ |
+| `HEAD` | ✔ | ✔ | ✔ |
+| `POST` | ✗ | ✗ [^1] | ✗ [^2] |
+| `PUT` | ✗ | ✔ | ✗ |
+| `PATCH` | ✗ | ✗ [^3] | ✗ |
+| `DELETE` | ✗ | ✔ | ✗ |
+| `OPTIONS` | ✔ | ✔ | ✗ |
+
+[^1]: No, but you [SHOULD consider to design `POST` and `PATCH` idempotent](@guidelines/R000009).
+[^2]: May, but only if the specific `POST` endpoint is `safe`. `Note:`{ label } Not supported by most caches.
+[^3]: No, but you [SHOULD consider to design `POST` and `PATCH` idempotent](@guidelines/R000009).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/030_should-consider-to-design-post-and-patch-idempotent.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/030_should-consider-to-design-post-and-patch-idempotent.md
new file mode 100644
index 0000000..ccc9cd6
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/030_should-consider-to-design-post-and-patch-idempotent.md
@@ -0,0 +1,62 @@
+---
+type: SHOULD
+id: R000009
+---
+
+# consider to design `POST` and `PATCH` idempotent
+
+In many cases it is helpful or even necessary to design `POST` and `PATCH` [idempotent](@guidelines/R000008) for clients to expose conflicts and prevent resource duplication (a.k.a. zombie resources) or lost updates, for example, if the same resources may be created or changed in parallel or multiple times.
+To design an idempotent API endpoint owners should consider to apply one of the following two patterns.
+
+- A resource specific **conditional key** provided via `If-Match` header in the request. The key is generally a meta information of the resource, for example, a _hash_ or _version number_, often stored with it. It allows to detect concurrent creations and updates to ensure idempotent behavior (see [SHOULD consider to support `ETag` together with `If-Match`/`If-None-Match` header](@guidelines/R000060)).
+- A resource specific **secondary key** provided as a resource property in the request body. The _secondary key_ is stored permanently in the resource. It allows to ensure idempotent behavior by looking up the unique secondary key in case of multiple independent resource creations from different clients.
+
+To decide which pattern is suitable for your use case, please consult the following table showing the major properties of each pattern:
+
+| | Conditional Key | Secondary Key |
+| ------------------------------------- | --------------- | ------------- |
+| Applicable with | `PATCH` | `POST` |
+| HTTP Standard | ✔ | ✗ |
+| Prevents duplicate (zombie) resources | ✔ | ✔ |
+| Prevents concurrent lost updates | ✔ | ✗ |
+| Supports safe retries | ✔ | ✔ |
+| Can be inspected (by intermediaries) | ✔ | ✗ |
+| Usable without previous `GET` | ✗ | ✔ |
+
+`Note:`{ label } The patterns applicable to `PATCH` can be applied in the same way to `PUT` and `DELETE` providing the same properties.
+
+The most important pattern to design `POST` idempotent for creation is to introduce a resource specific **secondary key** provided in the request body, to eliminate the problem of duplicate (a.k.a zombie) resources.
+Keep in mind that when creating a new resource using `POST` the resource identifier is created on the server-side, therefore the secondary key has to be provided by the client to resolve possible conflicts.
+
+The secondary key is stored permanently in the resource as an _alternate key_ or _combined key_ (if consisting of multiple properties) guarded by a uniqueness constraint enforced server-side, that is visible when reading the resource.
+The best and often naturally existing candidate is a _unique foreign key_, that points to another resource having _one-to-one_ relationship with the newly created resource, e.g. a parent process identifier.
+
+An example for a secondary key might be the e-mail address on a user resource:
+
+```sh
+POST /users HTTP/1.1
+
+{
+ "mail": "api@otto.de",
+ "name": "Api User"
+}
+
+# The response might never arrive at the client...
+201 Created
+Location: /users/12345
+
+# ...so the client retries the request...
+POST /users HTTP/1.1
+
+{
+ "mail": "api@otto.de",
+ "name": "Api User"
+}
+
+# ...resulting in a conflict, because the resource has already been created for the given secondary key "mail".
+
+409 Conflict
+```
+
+When using the secondary key pattern all subsequent retries should fail with status code `409 Conflict`.
+We suggest to avoid `200 OK` here unless you make sure, that the delivered resource is the original one implementing a well defined behavior. Using `204 No Content` without content would be a similar well-defined option.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/040_may-use-patch-with-json-patch-test-operation-for-concurrency-control.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/040_may-use-patch-with-json-patch-test-operation-for-concurrency-control.md
new file mode 100644
index 0000000..a7b8b3d
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/010_Methods/040_may-use-patch-with-json-patch-test-operation-for-concurrency-control.md
@@ -0,0 +1,38 @@
+---
+type: MAY
+id: R000059
+---
+
+# use `PATCH` with JSON Patch `test` operation for concurrency control
+
+In a situation where partial updates on different properties of an entity are common, chances of running into an optimistic locking situation increase with the number of concurrent updates, even if embracing [SHOULD use `ETag` together with `If-Match`/`If-None-Match` header for concurrency control](@guidelines/R000060). Performing a partial update using `PATCH` with media type `application/json-patch+json` (see [RFC 6902](https://tools.ietf.org/html/rfc6902)) can guard against unnoticed concurrent updates of properties relevant for the particular update.
+
+JSON Patch offers a [`test` operation](https://tools.ietf.org/html/rfc6902#section-4.6) that allows a server to reject a partial update, if the condition defined by the client cannot be met.
+
+Example:
+
+```http
+PATCH /products/123 HTTP/1.1
+Content-Type: application/json-patch+json
+[
+ { "op": "test", "path": "description", "value": "An old description" },
+ { "op": "replace", "path": "description", "value": "A new description" }
+]
+
+HTTP/1.1 200 OK
+ETag: "sadfgerlasdgjrgg"
+{ "id": "123", "description": "A new description", ... }
+```
+
+Or in an optimistic locking situation:
+
+```http
+PATCH /products/123 HTTP/1.1
+Content-Type: application/json-patch+json
+[
+ { "op": "test", "path": "description", "value": "An old description" },
+ { "op": "replace", "path": "description", "value": "A new description" }
+]
+
+HTTP/1.1 409 Conflict
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/000_index.md
new file mode 100644
index 0000000..24e106b
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/000_index.md
@@ -0,0 +1,68 @@
+# Headers
+
+## List of headers
+
+## Headers
+
+The list of headers is not supposed to be exhaustive, but contains the most common headers used in the context of the API.
+We do not prohibit the use of headers that are not listed below.
+HTTP/1.1-related headers, for example, `Connection`, are not explicitly listed.
+
+| Header Name | Description | Part of Request | Part of Response |
+| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------: | :--------------: |
+| `Accept` | Used for content negotiation, indicates which content types the client understands in a response. Refer to [SHOULD use `Accept` and `Content-Type` headers with profile parameter](@guidelines/R000030). | ✔ | ✗ |
+| `Accept-Encoding` | Used for content negotiation, a client advertises which content encoding algorithms it understands in a response. Possible values are `gzip`, `compress`, `deflate`, `identity`, and `br`. | ✔ | ✗ |
+| `Allow` | Contains the set of methods supported by a resource. This header must be set when responding with `405 Method Not Allowed`. Example: `Allow: GET, PUT, HEAD`. | ✗ | ✔ |
+| `Authorization` | Includes the credentials for accessing a given resource. Refer to [MUST use Bearer Authentication](@guidelines/R000021). | ✔ | ✗ |
+| `Content-Encoding` | Indicates the content encoding used for the response body. Refer to `Accept-Encoding`. | ✗ | ✔ |
+| `Content-Length` | The size of the request payload or response body in bytes. | ✔ | ✔ |
+| `Content-Type` | Indicates the media type of a resource. Describes the payload format of requests and the content type of responses. Required for `PUT` and `POST` requests. Refer to [SHOULD use `Accept` and `Content-Type` headers with profile parameter](@guidelines/R000030) | ✔ | ✔ |
+| `Date` | Contains the timestamp of the request (client) and response (server) respectively. The timestamp format must follow [RFC 7231](https://tools.ietf.org/html/rfc7231#section-7.1.1.1) | ✔ | ✔ |
+| `ETag` | Used for [caching](@guidelines/R000010) and [concurrency control](@guidelines/R000060). | ✗ | ✔ |
+| `Forwarded` | Contains information from the client side of proxy servers that is altered or lost when a proxy is involved. This can be the original `Host` requested by a client, for example to [generate absolute URLs in links](@guidelines/R100032). Refer to [RFC 7239](https://tools.ietf.org/html/rfc7239). | ✔ | ✗ |
+| `Host` | Contains the hostname (and non-default port) of the client's request. Example: `Host: api.otto.de` | ✔ | ✗ |
+| `If-Match` | Used for [caching](@guidelines/R000010) and [concurrency control](@guidelines/R000060). | ✔ | ✗ |
+| `If-None-Match` | Used for [caching](@guidelines/R000010) and [concurrency control](@guidelines/R000060). | ✔ | ✗ |
+| `Location` | Contains the redirect URL. This URL must be fully qualified. | ✗ | ✔ |
+| `Retry-After` | Used for rate limiting. Refer to [MUST use code 429 with headers for rate limits](@guidelines/R000014). | ✗ | ✔ |
+| `Server` | The header describes the software used by the server that handled the request. | ✗ | ✔ |
+| `User-Agent` | Used by a client to identify itself to the server. It should include a unique, human-readable identifier, optionally suffixed by a version string reflecting different software releases of the client. Example: [`User-Agent: otto-ready/v2.3.1`](@guidelines/R000025) | ✔ | ✗ |
+| `X-RateLimit-Limit` | Used for rate limiting. Refer to [MUST use code 429 with headers for rate limits](@guidelines/R000014). | ✗ | ✔ |
+| `X-RateLimit-Remaining` | Used for rate limiting. Refer to [MUST use code 429 with headers for rate limits](@guidelines/R000014). | ✗ | ✔ |
+| `X-RateLimit-Reset` | Used for rate limiting. Refer to [MUST use code 429 with headers for rate limits](@guidelines/R000014). | ✗ | ✔ |
+
+References:
+- [MUST NOT use link headers for JSON representations](@guidelines/R100034)
+
+## Header fields
+
+## ETag
+The RFC 7232 `ETag` header field in a response provides the entity tag of a selected resource. The entity tag is an opaque identifier for versions and representations of the same resource over time, regardless whether multiple versions are valid at the same time.
+An entity tag consists of an opaque **quoted** string, possibly prefixed by a weakness indicator (refer to [RFC 7232 Section 2.3](https://tools.ietf.org/html/rfc7232#section-2.3)).
+The contents of an `ETag: ` header is either:
+
+ a) a hash of the response body,
+
+ b) a hash of the last modified field of the entity, or
+
+ c) a version number or identifier of the entity version.
+
+Example: `W/"xy"`, `"5"`, `"5db68c06-1a68-11e9-8341-68f728c1ba70"`
+
+## If-Match
+The RFC 7232 `If-Match` header field in a request requires the server to only operate on the resource that matches at least one of the provided entity-tags.
+This allows clients to express a precondition that prevents the method from being applied if there have been any changes to the resource (refer to [RFC 7232 Section 3.1](https://tools.ietf.org/html/rfc7232#section-3.1)).
+
+Example: `"5"`, `"7da7a728-f910-11e6-942a-68f728c1ba70"`
+
+## If-None-Match
+The RFC 7232 `If-None-Match` header field in a request requires the server to only operate on the resource if it does **not** match any of the provided entity-tags. If the provided entity-tag is `*`, it is required that the resource does not exist at all (refer to [RFC 7232 Section 3.2](https://tools.ietf.org/html/rfc7232#section-3.2)).
+
+Example: `"7da7a728-f910-11e6-942a-68f728c1ba70"`, `*`
+
+## Location
+The `Location` header includes a fully qualified URL. This URL [must also be absolute](@guidelines/R100032) and respect any `Forwarded` header.
+Use this for two use cases:
+
+- Redirection: When answering a request with a `3xx` status code, the header value should point to where the resource moved.
+- Creation: When succesfully creating a resource via `POST`, you should tell a client the final location of that resource using the `Location` header. If a resource was created via `PUT` the client is already aware of the resource location, in this instance you should not set the `Location` header.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/010_may-use-etag-header-for-caching-resources.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/010_may-use-etag-header-for-caching-resources.md
new file mode 100644
index 0000000..f76e366
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/010_may-use-etag-header-for-caching-resources.md
@@ -0,0 +1,67 @@
+---
+type: MAY
+id: R000010
+---
+
+# use `ETag` header for caching resources
+
+Using the `ETag` response header in combination with the `If-None-Match` request header is a powerful tool for caching resources.
+This approach offers a solution where other caching headers (e.g. `Cache-Control` or `Expires`) hint at a _stale_ resource on the client side.
+
+When implementing `ETag` for caching, also "[SHOULD use `ETag` together with `If-Match`/`If-None-Match` header for concurrency control](@guidelines/R000060)" applies, see below "pitfalls".
+
+```sh
+GET /products/abc123 HTTP/1.1
+
+# Server sends ETag with requested resource
+200 OK
+ETag: "5db68c06-1a68-11e9-8341-68f728c1ba70"
+{/* big payload */}
+
+# Client passes ETag in `If-None-Match` header on subsequent requests
+GET /products/abc123 HTTP/1.1
+If-None-Match: "5db68c06-1a68-11e9-8341-68f728c1ba70"
+
+# Server compares ETag values, indicates that the client version is up to date.
+# The payload is not transmitted again.
+304 Not Modified
+
+# Down the line the resource has been changed, the client requests it again
+GET /products/abc123 HTTP/1.1
+If-None-Match: "5db68c06-1a68-11e9-8341-68f728c1ba70"
+
+# Server compares Etag values, determines that the clients version is stale.
+# The GET request is fully excuted, the payload and updated ETag are transmitted.
+200 OK
+ETag: "8341-5db68c06-68f728c1ba70-1a68-11e9"
+{/* big payload */}
+```
+
+The semantic is best described as: _"please give me the representation of the current state of the resource, if the state changed compared to the version I already know about."_
+
+The purpose of the value is to indicate a change in the underlying resource.
+One must differentiate between _weakly_ and _strongly_ validating entity tags:
+
+- A _strong_ entity tag indicates a byte-by-byte equality if matching and should be the **default**.
+- A _weak_ entity tag, marked by a `W/` prefix, only indicates semantic equality of the underlying resource. It should be the **fallback** if generating a strong tag is unfeasible, e.g. due to performance reasons.
+
+There are [several pitfalls](https://www.mnot.net/blog/2007/08/07/etags) to consider when implementing the `ETag` header correctly:
+
+- A strong `ETag` value must change when the representation of an entity changes, so it has to be sensitive to `Content-Type`, `Content-Encoding` and other response characteristics in order to be compliant with [RFC 7232](https://tools.ietf.org/html/rfc7232#section-2.3).
+- Using `gzip` compression will include a timestamp in your compressed resource representation, resulting in a different `ETag` value when compressed at another time even though the resource has not changed at all.
+- Handing out `ETag` headers for caching also implies, that your API also supports concurrency control/optimistic locking via `ETag`. This might add unwanted development and operational overhead.
+- You might find yourself doing a bunch of (CPU-bound) work on the server only to validate incoming `If-None-Match` request headers. In this case using `ETag` will only save network bandwidth, while still incurring compute costs, dwarfing the actual returns expected from implementing `ETag`.
+- `ETag` for collection resources are nontrivial to implement (see below).
+
+## Caching collection resources
+
+Caching via the `ETag` and `If-None-Match` header may also be applicable for collection resources, though the semantics are not as straightforward as for single entities.
+While it is easy to determine whether a single underlying entity changed, it is nonobvious when the state of a whole collection changed.
+A collection may be viewed as changed when:
+
+- a single entity of the given collection changed
+- or the order of the collection items changed
+- or the number of items in the collection changed.
+
+A _shallow_ comparison might be useful for some clients, while a _deep_ comparison could be necessary for use cases with stronger requirements.
+No general rule can be derived, the behavior needs be defined on a case-by-case basis for the given application.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/020_should-use-etag-together-with-if-match-if-none-match-header-for-concurrrency-control.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/020_should-use-etag-together-with-if-match-if-none-match-header-for-concurrrency-control.md
new file mode 100644
index 0000000..65b434a
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/020_should-use-etag-together-with-if-match-if-none-match-header-for-concurrrency-control.md
@@ -0,0 +1,95 @@
+---
+type: SHOULD
+id: R000060
+---
+
+# use `ETag` together with `If-Match`/`If-None-Match` header for concurrency control
+
+When creating or updating resources it may be necessary to expose conflicts and to prevent the 'lost update' or 'initially created' problem.
+Following [RFC 7232 "HTTP: Conditional Requests"](https://tools.ietf.org/html/rfc7232), this can be best accomplished by supporting the [`ETag`](https://tools.ietf.org/html/rfc7232#section-2.3) header together with the [`If-Match`](https://tools.ietf.org/html/rfc7232#section-3.1) or [`If-None-Match`](https://tools.ietf.org/html/rfc7232#section-3.2) conditional header.
+
+## Updating resources without 'lost update' problem
+To expose conflicts between concurrent update operations via `PUT`, `POST`, or `PATCH`, the `If-Match: ` header can be used to enable the server to check whether the version of the updated entity is conforming to the requested [``](https://tools.ietf.org/html/rfc7232#section-2.3).
+If no matching entity is found, the operation is supposed to respond with status code `412 - Precondition Failed`.
+
+Example:
+
+```http
+GET /orders HTTP/1.1
+
+HTTP/1.1 200 OK
+{
+ "items": [
+ { "id": "O0000042" },
+ { "id": "O0000043" }
+ ]
+}
+```
+
+```http
+GET /orders/O0000042 HTTP/1.1
+
+HTTP/1.1 200 OK
+ETag: "osjnfkjbnkq3jlnksjnvkjlsbf"
+{ "id": "BO0000042", ... }
+```
+
+```http
+PUT /orders/O0000042 HTTP/1.1
+If-Match: "osjnfkjbnkq3jlnksjnvkjlsbf"
+{ "id": "O0000042", ... }
+
+HTTP/1.1 204 No Content
+```
+
+Or, if there was an update since the `GET` and the entity’s `ETag` has changed:
+
+```http
+PUT /orders/O0000042 HTTP/1.1
+If-Match: "osjnfkjbnkq3jlnksjnvkjlsbf"
+{ "id": "O0000042", ... }
+
+HTTP/1.1 412 Precondition failed
+```
+
+## Creating resources without 'initially created' problem
+Besides other use cases, `If-None-Match: *` can be used in a similar way to expose conflicts in resource creation.
+If any matching entity is found, the operation is supposed to respond with status code `412 Precondition Failed`.
+
+Example:
+
+```http
+GET /orders HTTP/1.1
+
+HTTP/1.1 200 OK
+{
+ "items": [
+ { "id": "O0000042" }
+ ]
+}
+```
+
+```http
+PUT /orders/O0000042 HTTP/1.1
+If-None-Match: *
+{ "id": "O0000042", ... }
+
+HTTP/1.1 412 Precondition Failed
+```
+
+## Enforce conditional requests
+In order to enforce the usage of conditional requests, the server is supposed to answer with status code `428 Precondition Required` in case of clients omitting the `If-Match`/`If-None-Match` request header.
+
+Example:
+
+```http
+PUT /orders/O0000042 HTTP/1.1
+{ "id": "O0000042", ... }
+
+HTTP/1.1 428 Precondition Required
+```
+
+Using `HEAD` instead of `GET` in order to just fetch the most current `ETag` value is always an option to save bandwidth!
+
+References:
+- [MAY use `ETag` header for caching resources](@guidelines/R000010)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/030_should-honor-available-etag-header-on-subsequent-modifications.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/030_should-honor-available-etag-header-on-subsequent-modifications.md
new file mode 100644
index 0000000..e586bd3
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/030_should-honor-available-etag-header-on-subsequent-modifications.md
@@ -0,0 +1,10 @@
+---
+type: SHOULD
+id: R000074
+---
+
+# honor available `ETag` header on subsequent modifications
+
+In addition to the normal payload, an optional `ETag` header can be part of the response to a `GET` or `HEAD` request.
+
+A client should use the `ETag` response header value of a prior request as `If-Match: ` request header on subsequent `PUT`, `PATCH` or `POST` requests for making modifications to a resource. This also applies for services, that introduced the `ETag` header with the sole intention of [improving cachability](@guidelines/R000010).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/040_should-not-use-last-modified-and-if-unmodified-since-headers-for-concurrency-control.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/040_should-not-use-last-modified-and-if-unmodified-since-headers-for-concurrency-control.md
new file mode 100644
index 0000000..44bcc2b
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/040_should-not-use-last-modified-and-if-unmodified-since-headers-for-concurrency-control.md
@@ -0,0 +1,16 @@
+---
+type: SHOULD NOT
+id: R000072
+---
+
+# use `Last-Modified` and `If-Unmodified-Since` headers for concurrency control
+
+APIs should not use the `Last-Modified` header to achieve concurrency control.
+The header only provides a time resolution of one second, which is too coarse for most use cases.
+You might be able to use this header in certain less constraint cases.
+
+If you choose to implement this behavior nevertheless, you should communicate this to clients by responding with `428 Precondition Required` for requests that do not contain the corresponding `If-Unmodified-Since` header.
+
+References:
+- [SHOULD follow concurrenct update pattern with `If-Modified-Since` header](@guidelines/R000073)
+- [SHOULD use `ETag` together with `If-Match`/`If-None-Match` header for concurrency control](@guidelines/R000060)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/050_should-follow-concurrenct-update-pattern-with-if-umodified-since-header.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/050_should-follow-concurrenct-update-pattern-with-if-umodified-since-header.md
new file mode 100644
index 0000000..8b0f885
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/020_Headers/050_should-follow-concurrenct-update-pattern-with-if-umodified-since-header.md
@@ -0,0 +1,17 @@
+---
+type: SHOULD
+id: R000073
+appliesTo: client
+---
+
+# follow concurrent update pattern with `If-Unmodified-Since` header
+
+If an API implements concurrency control via the `Last-Modified` header, clients should follow this pattern.
+This means, a client should send a received `Last-Modified` timestamp using the `If-Unmodified-Since` header.
+This allows the server to verify the conditional request.
+
+If you do not provide the header, the server may respond with `428 Precondition Required`.
+
+References:
+- [SHOULD NOT use `Last-Modified` and `If-Unmodified-Since` headers for concurrency control](@guidelines/R000072)
+- [SHOULD use `ETag` together with `If-Match`/`If-None-Match` header for concurrency control](@guidelines/R000060)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/000_index.md
new file mode 100644
index 0000000..1ad8b77
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/000_index.md
@@ -0,0 +1 @@
+# Status codes
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/010_must-specify-success-and-error-responses.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/010_must-specify-success-and-error-responses.md
new file mode 100644
index 0000000..5ead1b3
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/010_must-specify-success-and-error-responses.md
@@ -0,0 +1,31 @@
+---
+type: MUST
+id: R000011
+---
+
+# specify success and error responses
+
+APIs should define the functional, business view and abstract from implementation aspects.
+Success and error responses are a vital part to define how an API is used correctly.
+
+Therefore, you must define **all** success and service specific error responses in your API specification.
+Both are part of the interface definition and provide important information for service clients to handle standard as well as exceptional situations.
+
+`Note:`{ label } In most cases it is not useful to document all technical errors, especially if they are not under control of the service provider. Thus unless a response code conveys application-specific functional semantics or is used in a non-standard way that requires additional explanation, multiple error response specifications can be combined using the following pattern:
+
+See [Error Handling](../../040_Errors/010_Error-handling/000_index.md) for more details.
+
+```yaml
+responses:
+ ...
+ default:
+ description: error occurred - see status code and problem object for more information.
+ content:
+ "application/problem+json":
+ schema:
+ $ref: 'https://api.otto.de/problem/schema.yaml#/Problem'
+```
+
+API designers should also think about a **troubleshooting board** as part of the associated online API documentation.
+It provides information and handling guidance on application-specific errors and is referenced via links from the API specification.
+This can reduce service support tasks and contribute to service client and provider performance.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/020_must-use-standard-http-status-codes.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/020_must-use-standard-http-status-codes.md
new file mode 100644
index 0000000..1bc7c13
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/020_must-use-standard-http-status-codes.md
@@ -0,0 +1,69 @@
+---
+type: MUST
+id: R000012
+---
+
+# use standard HTTP status codes
+
+You must only use standardized HTTP status codes consistently with their intended semantics.
+You must not invent new HTTP status codes.
+
+RFC standards define ~60 different HTTP status codes with specific semantics (mainly [RFC7231](https://tools.ietf.org/html/rfc7231#section-6) and [RFC 6585](https://tools.ietf.org/html/rfc6585)) — and there are upcoming new ones, for example, [draft legally-restricted-status](https://tools.ietf.org/html/draft-tbray-http-legally-restricted-status-05).
+Refer to the overview of all error codes at [Wikipedia](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) or via also including 'unofficial codes', for example, used by popular web servers like Nginx.
+
+Below we list the most commonly used and best understood HTTP status codes, consistent with their semantic in the RFCs.
+APIs should only use these to prevent misconceptions that arise from less commonly used HTTP status codes.
+
+As long as your HTTP status code usage is well covered by the semantic defined here, you should not describe it to avoid an overload with common sense information and the risk of inconsistent definitions. Only if the HTTP status code is not in the list below or its usage requires additional information aside the well defined semantic, the API specification must provide a clear description of the HTTP status code in the response.
+
+
+## Success codes
+
+| Status Code | Meaning | Methods |
+| :--------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :------------------------------- |
+| `200 OK` | This is the standard success response. | |
+| `201 Created` | Returned on successful entity creation. You are free to return either an empty response or the created resource in conjunction with the `Location` header (readers can find more details in Common headers. _Always_ set the `Location` header when the client needs to know the URI of the newly created resource. | `POST`, `PUT` |
+| `202 Accepted` | The request was successful and will be processed asynchronously. | `POST`, `PUT`, `PATCH`, `DELETE` |
+| `204 No Content` | No response body. | `PUT`, `PATCH`, `DELETE` |
+
+
+## Redirection codes
+
+| Code | Meaning | Methods |
+| :----------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------- |
+| `301 Moved Permanently` | This request and all future requests should be directed to the given URI. | `` |
+| `303 See Other` | The response to the request can be found under another URI using a `GET` method. | `POST`, `PUT`, `PATCH`, `DELETE` |
+| `304 Not Modified` | Indicates that a conditional `GET` or `HEAD` request would have resulted in `200` response if it were not for the fact that the condition evaluated to false, i.e. resource has not been modified since the date or version passed via request headers [`If-Modified-Since`](https://tools.ietf.org/html/rfc7232#section-3.3) or [`If-None-Match`](https://tools.ietf.org/html/rfc7232#section-3.2). | `GET`, `HEAD` |
+| `307 Temporary Redirect` | The response to the request can be temporarily found under another URI using the same method of the initial request. | `` |
+| `308 Permanent Redirect` | The response to the request can be permanently found under another URI using the same method of the initial request. | `` |
+
+
+## Client side error codes
+
+| Code | Meaning | Methods |
+| :--------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------------------------- |
+| `400 Bad Request` | Indicates a syntactically malformed request. | `` |
+| `401 Unauthorized` | The users must log in (this often means "Unauthenticated"). | `` |
+| `403 Forbidden` | The user is not authorized to use this resource. | `` |
+| `404 Not Found` | The requested resource could not be found. | `` |
+| `405 Method Not Allowed` | The method is not supported, refer to [OPTIONS](@guidelines/R000007). | `` |
+| `406 Not Acceptable` | Resource can only generate content not acceptable according to the Accept headers sent in the request. | `` |
+| `409 Conflict` | Request cannot be completed due to conflict, e.g. when two clients try to create the same resource or if there are concurrent, conflicting updates. | `POST`,`PUT`,`PATCH`,`DELETE` |
+| `410 Gone` | Resource does not exist any longer, e.g. when accessing a resource that has intentionally been deleted. | `` |
+| `412 Precondition Failed` | Returned for conditional requests, e.g. [`If-Match`](https://tools.ietf.org/html/rfc7232#section-3.1) if the condition failed. Used for optimistic locking. | `PUT`,`PATCH`,`DELETE` |
+| `413 Payload Too Large` | Request headers or body exceed a defined limit. This might happen for large JWT containing many scopes or large HTTP bodies. | `` |
+| `415 Unsupported Media Type` | E.g. client sends request body without content type. | `POST`,`PUT`,`PATCH`,`DELETE` |
+| `422 Unprocessable Entity` | Indicates a logically invalid request body. The server understands the content type of the request entity and the syntax is correct. However, the server was unable to process the contained instructions, for example, due to an inappropriate server state. | `POST`,`PUT`,`PATCH`,`DELETE` |
+| `428 Precondition Required` | Server requires the request to be conditional, e.g. to make sure that the "lost update problem" is avoided (refer to [SHOULD consider to support `ETAG` together with If-Match/If-None-Match header](@guidelines/R000060)). | `` |
+| `429 Too Many Requests` | The client does not consider rate limiting and sent too many requests (refer to [MUST use code 429 with headers for rate limits](@guidelines/R000014)). | `` |
+
+
+## Server side error codes
+
+| Code | Meaning | Methods |
+| :-------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------ |
+| `500 Internal Server Error` | A generic error indication for an unexpected server execution problem (here, client retry may be sensible) | `` |
+| `501 Not Implemented` | Server cannot fulfill the request (usually implies future availability, e.g. new feature). | `` |
+| `503 Service Unavailable` | Service is (temporarily) not available (e.g. if a required component or downstream service is not available) — client retry may be sensible. If possible, the service should indicate how long the client should wait by setting the [`Retry-After`](https://tools.ietf.org/html/rfc7231#section-7.1.3) header. | `` |
+| | |
+
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/030_must-use-most-specific-http-status-code.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/030_must-use-most-specific-http-status-code.md
new file mode 100644
index 0000000..6a87556
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/030_must-use-most-specific-http-status-code.md
@@ -0,0 +1,8 @@
+---
+type: MUST
+id: R000013
+---
+
+# use most specific HTTP status code
+
+You must use the most specific HTTP status code when returning information about your request processing status or error situations.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/040_must-use-code-429-with-headers-for-rate-limits.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/040_must-use-code-429-with-headers-for-rate-limits.md
new file mode 100644
index 0000000..5bc6b84
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/040_must-use-code-429-with-headers-for-rate-limits.md
@@ -0,0 +1,27 @@
+---
+type: MUST
+id: R000014
+reviewType: automatic
+---
+
+# use code 429 with headers for rate limits
+
+APIs that intend to manage the request rate of clients must use the `429 Too Many Requests` response code, if the client exceeded the request rate (refer to [RFC 6585](https://tools.ietf.org/html/rfc6585)).
+Such responses must also contain header information providing further details to the client.
+There are two approaches a service can take for header information:
+
+- Return a [`Retry-After`](https://tools.ietf.org/html/rfc7231#section-7.1.3) header indicating how long the client ought to wait before making a follow-up request. The Retry-After header can contain a HTTP date value to retry after or the number of seconds to delay. Either is acceptable but APIs should prefer to use a delay in seconds.
+- Return a trio of `X-RateLimit` headers. These headers (described below) allow a server to express a service level in the form of a number of allowing requests within a given window of time and when the window is reset.
+
+The `X-RateLimit` headers are:
+
+- `X-RateLimit-Limit`: The maximum number of requests that the client is allowed to make in this window.
+- `X-RateLimit-Remaining`: The number of requests allowed in the current window.
+- `X-RateLimit-Reset`: The relative time in seconds when the rate limit window will be reset.
+ `Note`{ label } This is different to GitHub and Twitter’s usage of a header with the same name which is using UTC epoch seconds instead.
+
+The reason to allow both approaches is that APIs can have different needs.
+Retry-After is often sufficient for general load handling and request throttling scenarios and notably, does not strictly require the concept of a calling entity such as a tenant or named account.
+In turn this allows resource owners to minimize the amount of state they have to carry with respect to client requests.
+The 'X-RateLimit' headers are suitable for scenarios where clients are associated with pre-existing account or tenancy structures.
+`X-RateLimit` headers are generally returned on every request and not just on a 429, which implies the service implementing the API is carrying sufficient state to track the number of requests made within a given window for each named entity.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/050_must-set-user-agent.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/050_must-set-user-agent.md
new file mode 100644
index 0000000..17ee779
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/030_Status-codes/050_must-set-user-agent.md
@@ -0,0 +1,14 @@
+---
+type: MUST
+id: R000025
+appliesTo: client
+---
+
+# set user agent request header
+
+Clients must set the `User-Agent` header when performing requests against the OTTO API in the format `{client-identifier}/{client-version}`. This allows requests to be correlated with the specific client and release version, which can be used to troubleshoot failed requests for a new version of the client application.
+
+Examples:
+
+- `acme-product-indexer/v1.0.0`
+- `otto-alexa-skill/v2.3.0`
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/000_index.md
new file mode 100644
index 0000000..47986cc
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/000_index.md
@@ -0,0 +1,3 @@
+# Caching
+
+**Note:** The OTTO API does not provide any caching capabilities by itself. Caching must be implemented by the backends.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/10_should-adhere-to-caching-best-practices.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/10_should-adhere-to-caching-best-practices.md
new file mode 100644
index 0000000..8aff557
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/10_should-adhere-to-caching-best-practices.md
@@ -0,0 +1,18 @@
+---
+type: SHOULD
+id: R006010
+---
+
+# adhere to caching best practices
+
+For consistent cache handling amongst services, adhere to the best practices shown below:
+
+- Avoid client side and transparent web caching.
+ - Read [RFC 7234](https://tools.ietf.org/html/rfc7234) before adding any client or proxy cache.
+- Since all endpoints are [authorized via OAuth2](../../005_Authorization/020_Scopes/010_must-define-and-assign-permissions-by-using-scopes.md), the default `Cache-Control` header should be `Cache-Control: private, must-revalidate` with a `max-age` value between some seconds to some hours.
+- Use the `Cache-Control` (HTTP 1.1) header instead of the `Pragma` (HTTP 1.0) header.
+- Consider using the `ETag` header when caching.
+ - See: [MAY use `ETag` header for caching resources](@guidelines/R000010) and [SHOULD use `ETag` together with `If-Match`/`If-None-Match` header for concurrency control](@guidelines/R000060)
+- Avoid the `Last-Modified` header when possible.
+ - See: [SHOULD NOT use `Last-Modified` and `If-Unmodified-Since` headers for concurrency control](../010_Methods/040_may-use-patch-with-json-patch-test-operation-for-concurrency-control.md)
+- Avoid the `Expires` header to prevent redundant and ambiguous definition of cache lifetime.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/20_must-document-cacheable-get-head-and-post-endpoints.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/20_must-document-cacheable-get-head-and-post-endpoints.md
new file mode 100644
index 0000000..d3b2e03
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/20_must-document-cacheable-get-head-and-post-endpoints.md
@@ -0,0 +1,39 @@
+---
+type: MUST
+id: R006020
+---
+
+# document cacheable `GET`, `HEAD` and `POST` endpoints
+
+To clearly document that a `GET`, `HEAD` or `POST` endpoint implements any kind of caching, the support of caching headers (`Cache-Control`, `Vary`, `Etag`) must be declared in the response.
+
+## Example OpenAPI Spec documentation fragment
+
+```yaml
+paths:
+ "/products":
+ get:
+ operationId: products-read
+ summary: This endpoint will return a collection of products.
+ description: |
+ Load a collection of products.
+ responses:
+ 200:
+ description: Successfully load products
+ headers:
+ Cache-Control:
+ description: >
+ Indicates if this response is cacheable.
+ See [RFC 7234](https://tools.ietf.org/html/rfc7234#section-5.2.2) for possible values.
+ schema:
+ type: string
+ content:
+ 'application/json+hal;profile="https://api.otto.de/portal/profiles/products/products+v1"':
+ schema:
+ "$ref": "#/components/schemas/LoadProductsV1Response"
+```
+
+See:
+
+- [MAY use `ETag` header for caching resources](@guidelines/R000010)
+- [SHOULD use `ETag` together with `If-Match`/`If-None-Match` header for concurrency control](@guidelines/R000060)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/30_should-avoid-vary-header-for-caching.md b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/30_should-avoid-vary-header-for-caching.md
new file mode 100644
index 0000000..9a540bc
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/010_HTTP/040_Caching/30_should-avoid-vary-header-for-caching.md
@@ -0,0 +1,13 @@
+---
+type: SHOULD
+id: R006030
+---
+
+# avoid `Vary` header for caching
+
+The `Vary` header as specified in [RFC7231#section-7.1.4](https://tools.ietf.org/html/rfc7231#section-7.1.4) is difficult to setup in order to support correct caching. For example, implementing secondary key calculation as described in [RFC7234#section-4.1](https://tools.ietf.org/html/rfc7234#section-4.1) has a high potential for mistakes. Whenever possible, use the `ETag` header instead of `Vary` for caching.
+
+See:
+
+- [MAY use `ETag` header for caching resources](@guidelines/R000010)
+- [SHOULD use `ETag` together with `If-Match`/`If-None-Match` header for concurrency control](@guidelines/R000060)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/000_index.md
new file mode 100644
index 0000000..3fbe632
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/000_index.md
@@ -0,0 +1,9 @@
+# Hypermedia
+
+Besides the best practices for [compatible API evolutions](../../020_GENERAL-GUIDELINES/030_Compatibility/010_Compatible-changes/000_index.md), there are other guidelines to facilitate business changes without impacting consumers.
+
+To achieve this, API contracts should not contain or publish explicit or implicit business rules, such as the conditions under which a resource is usable. These rules would then be part of the API contract, and any incompatible change to these rules (e.g. a stricter interpretation) would break API clients.
+
+Instead, API responses should include information about when certain contextually relevant resources are accessible and thus usable. This information is commonly referred to as hypermedia.
+
+This section deals with topics such as [when hypermedia needs to be implemented](@guidelines/R000033), [which hypermedia standard to use](@guidelines/R000036), details about how to use [hypermedia links](./020_Links/000_index.md), [link relations](./030_Link-relation-types/000_index.md) and finally [profiles](./040_Profiles/000_index.md) to support [versioning](../050_Compatibility/020_Versioning/000_index.md).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/000_index.md
new file mode 100644
index 0000000..c3c547b
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/000_index.md
@@ -0,0 +1,7 @@
+# Maturity level
+
+[Richardson Maturity Model](https://martinfowler.com/articles/richardsonMaturityModel.html) is a well received way to categorize APIs according to REST architectural constraints.
+
+The last level of this model requires a constraint called HATEOAS (Hypermedia As The Engine Of Application State). This allows API providers to fully control consumer behavior with their responses, so in extreme cases they could even be implemented completely generically. While not practical most of the time, aspects of this last stage can be used to make consumers more independent of business changes to an API.
+
+Hypermedia is based on the linking of resources that allows consumers to interact with the server with little to no prior knowledge. The links used for this purpose allow navigation without side effects between resources, as well as operations with side effects on resources that are interpreted differently depending on the domain.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/010_must-implement-rest-maturity-level-2.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/010_must-implement-rest-maturity-level-2.md
new file mode 100644
index 0000000..c7753af
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/010_must-implement-rest-maturity-level-2.md
@@ -0,0 +1,23 @@
+---
+type: MUST
+id: R000032
+---
+
+# implement REST maturity level 2
+
+For all our APIs, we strive for a good implementation of [REST Maturity Level 2](https://martinfowler.com/articles/richardsonMaturityModel.html#level2) as it enables us to build resource-oriented APIs that make full use of HTTP methods and status codes.
+This is reflected in many rules of our guidelines, such as:
+
+- [MUST use nouns to represent resources](@guidelines/R000016)
+- [MUST use HTTP methods correctly](@guidelines/R000007)
+- [MUST use standard HTTP status codes](@guidelines/R000012)
+
+Although this is not HATEOAS, it should not prevent you from designing proper link relations in your APIs.
+
+If you do so, you should use application/hal+json as representation format, because:
+
+- Later publication of the API will be easier if HAL is used from the beginning.
+- Implementing API clients is easier if different parts of the API behave the same and if the same format is used for different purposes.
+
+References:
+- Internet Draft [JSON Hypertext Application Language](https://tools.ietf.org/html/draft-kelly-json-hal-08)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/020_must-implement-rest-maturity-level-3-for-transitional-apis.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/020_must-implement-rest-maturity-level-3-for-transitional-apis.md
new file mode 100644
index 0000000..a25c547
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/020_must-implement-rest-maturity-level-3-for-transitional-apis.md
@@ -0,0 +1,35 @@
+---
+type: MUST
+id: R000033
+---
+
+# implement REST maturity level 3 for transitional APIs
+
+Hypermedia must be implemented for [unsafe resource operations](@guidelines/R000008) (e.g. `POST`) that will cause client errors (`4xx`) depending on one of the below mentioned criteria. If one or more of the criteria apply to the cause of error, [REST Maturity Level 3](https://martinfowler.com/articles/richardsonMaturityModel.html#level3) must be implemented in order to:
+
+- allow clients to reason about the availability of the unsafe resource operation (e.g. for UI button enabling/disabling) before actually invoking it
+- prevent duplication of business logic on API provider and consumer side, making business logic changes even harder.
+
+## Criteria for the error cause
+
+### State of the resource
+
+Unsafe resource operations will fail depending on the state of the resource itself.
+
+`Example`{ label } _Cancellation of an order is only possible as long as it is not shipped.
+When error responses are solely caused by the caller's request entity and/or parameter(s), the implementation of hypermedia links is not necessary._
+
+### Authorization
+
+Unsafe resource operations will fail depending on the [authorization](../../005_Authorization/000_index.md) of the calling identity.
+
+`Example`{ label } _Rating products is only available to customers with a certain reputation._
+
+### Time
+
+Unsafe resource operations will fail depending on the time the resource is accessed.
+
+`Example`{ label } _Vouchers are only valid for 2 weeks, after that period their usage will lead to errors, though the voucher itself has not changed it's state_
+
+References:
+- [Unsafe operations](https://datatracker.ietf.org/doc/html/rfc7231#section-4.2.1)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/030_must-use-hal-to-implement-REST-maturity-level-3.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/030_must-use-hal-to-implement-REST-maturity-level-3.md
new file mode 100644
index 0000000..795da26
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/010_Maturity-level/030_must-use-hal-to-implement-REST-maturity-level-3.md
@@ -0,0 +1,18 @@
+---
+type: MUST
+id: R000036
+---
+
+# use HAL (Hypertext Application Language) to implement REST maturity level 3
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+Since a variety of hypermedia formats exists, we decided to use HAL when a hypermedia implementation is required for the following reasons:
+
+- The simplicity compared to other formats ensures quick familiarization with the format.
+- Every `application/json` entity is a valid `application/hal+json` entity. This gives us the possibility to start with any given JSON API and later decide to add hyperlinks and embedded resources in a non-breaking way.
+
+References:
+- Internet Draft [JSON Hypertext Application Language](https://tools.ietf.org/html/draft-kelly-json-hal-08)
+- List of [hypermedia formats](https://gtramontina.com/h-factors/) and their H-Factors
+- [H-Factors](http://amundsen.com/hypermedia/hfactor/) by Amundsen
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/000_index.md
new file mode 100644
index 0000000..32616bf
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/000_index.md
@@ -0,0 +1,5 @@
+# Links
+
+Hypermedia links embedded in an HTTP response allow API providers to communicate dynamic facts, such as business rule outcomes, to consumers independent of any static OpenAPI interface documentation.
+
+This means that the reasons for these facts do not need to be explicitly stated in the static documentation and therefore do not need to be implemented by consumers. In addition, consumers are not dependent on them, which makes any change much easier.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/010_must-use-absolute-urls.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/010_must-use-absolute-urls.md
new file mode 100644
index 0000000..59fcf05
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/010_must-use-absolute-urls.md
@@ -0,0 +1,53 @@
+---
+type: MUST
+id: R100032
+---
+
+# use absolute URLs
+
+Links to other resources must always use full, absolute hrefs. If a client supplies
+a [`Forwarded` request header](@guidelines/R000044), the
+header value must be used for generating absolute URLs.
+
+The `Forwarded` header may contain the directives `host` and `proto`. The `host` directive contains the `Host` request
+field as received by the proxy that forwarded the request. The `proto` directive contains the protocol that was used
+to make the request to the proxy (usually `http` or `https`). For the construction of absolute URLs based on the
+`Forwarded` Header, the service also needs to take into account the path under which the service is made available
+to the client by the reverse proxy.
+
+Motivation:
+
+Exposing any form of relative URI (no matter if the relative URI uses an absolute or relative path)
+introduces avoidable client side complexity. It also requires clarity on the base URI, which might not be given when
+using features like embedding subresources.
+
+The main advantage of non-absolute URIs is the reduction in payload size, which can be better achieved by following the
+recommendation to use gzip compression.
+
+Example:
+
+In this example the origin service (serving ) can only be reached through a reverse proxy
+which acts as an API gateway (serving ). The client communicates with the origin service through
+the API gateway. That is why the origin service can only deduct the client facing URI from the `Forwarded` header.
+The `Forwarded` header is set by the API gateway.
+
+```http request
+# Request from the client to the API gateway
+GET https://api.otto.de/example-api/my-ressource/1234
+# Proxied request from the API gateway to the origin service
+GET https://myExampleService:8080/my-ressource/1234
+Forwarded: for=156.124.2.46;host=api.otto.de;proto=https
+```
+
+The answer from the origin-services must ues the `host` and `proto` directives of the `Forwarded` header and its API
+gateway path to generate absolute URLs:
+
+```json
+{
+ ...
+ "_links" : {
+ "self" : "https://api.otto.de/example-api/my-ressource/1234",
+ ...
+ }
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/020_should-contain-link-title-attribute.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/020_should-contain-link-title-attribute.md
new file mode 100644
index 0000000..0be3b20
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/020_should-contain-link-title-attribute.md
@@ -0,0 +1,22 @@
+---
+type: SHOULD
+id: R100064
+---
+
+# contain link title attribute
+
+All hyperlinks should have a ['title'](https://tools.ietf.org/html/draft-kelly-json-hal-08#section-5.7) attribute.
+The value of the attribute should not contain generic descriptions ('The author'), but should be a specific human-readable name or title of the target resource.
+
+```json
+{
+ "_links": {
+ "author": [
+ {
+ "href": "https://api.otto.de/authors/4711",
+ "title": "John"
+ }
+ ]
+ }
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/030_must-contain-deprecation-attribute.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/030_must-contain-deprecation-attribute.md
new file mode 100644
index 0000000..b4273c8
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/030_must-contain-deprecation-attribute.md
@@ -0,0 +1,10 @@
+---
+type: MUST
+id: R100065
+---
+
+# contain deprecation attribute
+
+Links to deprecated APIs must contain the optional link attribute ['deprecation'](https://tools.ietf.org/html/draft-kelly-json-hal-08#section-5.4), if applicable.
+The value of the deprecation attribute must point to human-readable information about the deprecation.
+See also [Deprecation](../../050_Compatibility/040_Deprecation/000_index.md).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/040_must-provide-conventional-hyperlinks.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/040_must-provide-conventional-hyperlinks.md
new file mode 100644
index 0000000..d3530c4
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/040_must-provide-conventional-hyperlinks.md
@@ -0,0 +1,74 @@
+---
+type: MUST
+id: R100033
+---
+
+# provide conventional hyperlinks
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+Hyperlinks to other resources [must use HAL](@guidelines/R000036).
+
+The following links must be contained in HAL representations:
+
+- `self`: The _canonical_ hyperlink of the resource.
+- `profile`: The fully qualified link pointing to the `profile` of the resource, if any. The link [must resolve to some
+ human-readable documentation](@guidelines/R100066) of the profile. The `profile` is omitted
+ if the resource does not have any custom properties beside HAL `_links` and `_embedded` elements. [Collection
+ resources](../../030_Resources/020_Collection-resources/000_index.md), for example, might only be plain `application/hal+json`
+ representations without any custom attributes.
+- `collection`: For items contained in a collection resource, this link should point to the collection. In most cases, this
+ link will be [templated](https://tools.ietf.org/html/draft-kelly-json-hal-08#section-5.2).
+- `search`: For searchable collection resources, a [templated](https://tools.ietf.org/html/draft-kelly-json-hal-08#section-5.2) link should be added that refers to the collection including all template parameters.
+
+Example of a [paged collection](@guidelines/R100025) resource:
+
+```json
+{
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders?page=2&pageSize=10" },
+ "profile": {
+ "href": "https://api.otto.de/portal/profiles/orders/paged-collection+v1"
+ },
+ "search": {
+ "href": "https://api.otto.de/orders{?q,page,pageSize}",
+ "templated": true
+ },
+ "item": [{ "href": "https://api.otto.de/orders/4711" }]
+ },
+ "_page": {
+ "size": 10,
+ "number": 2,
+ "totalElements": 21,
+ "totalPages": 3
+ }
+}
+```
+
+Example of a `collection item`:
+
+```json
+{
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders/4711" },
+ "profile": {
+ "href": "https://api.otto.de/portal/profiles/orders/order+v1"
+ },
+ "collection": {
+ "href": "https://api.otto.de/orders{?q,page,pageSize}",
+ "templated": true
+ }
+ },
+ "total": 3000,
+ "currency": "EUR",
+ "status": "shipped"
+}
+```
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
+- [MUST support hypermedia controls in collection resources](@guidelines/R100026)
+- [Link-Relation Types](../030_Link-relation-types/000_index.md)
+- [IANA link relations](http://www.iana.org/assignments/link-relations/link-relations.xhtml)
+- [REST lesson learned: consider a self link on all resources](https://blog.ploeh.dk/2013/05/03/rest-lesson-learned-consider-a-self-link-on-all-resources/)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/050_must-not-use-link-headers-for-json-representations.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/050_must-not-use-link-headers-for-json-representations.md
new file mode 100644
index 0000000..ddc1659
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/050_must-not-use-link-headers-for-json-representations.md
@@ -0,0 +1,10 @@
+---
+type: MUST NOT
+id: R100034
+reviewType: automatic
+---
+
+# use link headers for JSON representations
+
+For flexibility and precision, we prefer links to be directly embedded in the JSON payload instead of being attached using the uncommon link header syntax.
+As a result, the use of the `Link` header defined by [RFC 8288](https://tools.ietf.org/html/rfc8288#section-3) in conjunction with JSON media types is not allowed.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/060_must-support-forwarded-header.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/060_must-support-forwarded-header.md
new file mode 100644
index 0000000..b273286
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/060_must-support-forwarded-header.md
@@ -0,0 +1,13 @@
+---
+type: MUST
+id: R000044
+---
+
+# support `Forwarded` header
+
+In order to support proxies in front of your origin server, you must implement support for the `Fowarded` request header.
+
+The `Forwarded` header is defined in [RFC 7239](https://tools.ietf.org/html/rfc7239) for identifying e.g. the original host (and port) requested by the client in the `Host` HTTP request header or the specified protocol.
+Consult [RFC 7239, Section 4](https://tools.ietf.org/html/rfc7239#section-4) for examples of this header.
+
+[Absolute URLs](@guidelines/R100032) rendered in links of a HAL response contain the value of this header.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/070_must-contain-separate-id-field-in-the-payload.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/070_must-contain-separate-id-field-in-the-payload.md
new file mode 100644
index 0000000..a0bc860
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/070_must-contain-separate-id-field-in-the-payload.md
@@ -0,0 +1,10 @@
+---
+type: MUST
+id: R000061
+---
+
+# contain a separate ID field in the payload
+
+The payload of a resource must always contain the technical ID for the client, so that it can be reused without parsing it from the links.
+
+Read [Relative vs. Absolute links (internal link)](https://github.com/otto-ec/ottoapi_guidelines/blob/master/references/relative-vs-absolute-uris.md) for further information on this topic.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/080_must-support-hypermedia-controls-in-collection-resources.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/080_must-support-hypermedia-controls-in-collection-resources.md
new file mode 100644
index 0000000..aa352ac
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/080_must-support-hypermedia-controls-in-collection-resources.md
@@ -0,0 +1,26 @@
+---
+type: MUST
+id: R100026
+---
+
+# support hypermedia controls in collection resources
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+Provide links to navigate the result. Clients must be able to navigate the collection without additional knowledge. If the link is present, it must point to a valid segment of the collection resource.
+The [IANA link relations](http://www.iana.org/assignments/link-relations/link-relations.xhtml) must be used whenever applicable.
+
+The most common ones are:
+
+- `self` : the current page
+- `next` (_optional_): the next page. Should be set, only if next page is present.
+- `prev` (_optional_): the previous page, if present. Must be omitted for the first page.
+- `first` (_optional_): the first page
+- `last` (_optional_): the last page
+
+Some properties like `first`, `next` and `last` can be omitted if the implementation is not feasable, for example, when the calculation has a big performance impact.
+Exposing this data should consider the performance implications, not only now but over the lifespan of the service.
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/090_must-contain-links-for-embedded-resources.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/090_must-contain-links-for-embedded-resources.md
new file mode 100644
index 0000000..ed2906a
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/090_must-contain-links-for-embedded-resources.md
@@ -0,0 +1,57 @@
+---
+type: MUST
+id: R000042
+---
+
+# contain links for embedded resources
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+Servers must not entirely "swap out" a link for an embedded resource (or vice versa) because client support for this technique is OPTIONAL.
+
+For every embedded resource, a corresponding link MUST be contained in the `_links` object of the embedding resource.
+
+Example:
+
+```http request
+GET https://api.otto.de/products HTTP/1.1
+```
+
+```json
+{
+ "_links": {
+ "item": [{ "href": "http://api.otto.de/products/4711" }]
+ },
+ "_embedded": {
+ "item": [
+ {
+ "_links": {
+ "self": [{ "href": "http://api.otto.de/products/4711" }]
+ },
+ "productId": "4711"
+ }
+ ]
+ }
+}
+```
+
+But do not render the item like this:
+
+```http request
+GET https://api.otto.de/products HTTP/1.1
+```
+
+```json
+{
+ "_links": {
+ "item": [{ "href": "http://api.otto.de/products/4711" }]
+ },
+ "_embedded": {
+ "item": [
+ {
+ "productId": "4711"
+ }
+ ]
+ }
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/100_should-provide-hypermedia-links-in-embedded-documents.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/100_should-provide-hypermedia-links-in-embedded-documents.md
new file mode 100644
index 0000000..7f0324e
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/020_Links/100_should-provide-hypermedia-links-in-embedded-documents.md
@@ -0,0 +1,12 @@
+---
+type: SHOULD
+id: R100028
+---
+
+# provide hypermedia links in embedded documents
+
+The list resource items should provide the same links as the single resource representation as described in [Hypermedia](../000_index.md).
+
+Links may be omitted to prevent performance degradation or response bloat.
+Keep the client's use cases in mind.
+You should not omit information if most use cases need those and would be forced to do `n` additional calls.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/000_index.md
new file mode 100644
index 0000000..de6117c
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/000_index.md
@@ -0,0 +1,3 @@
+# Link relation types
+
+A link relation is a descriptive attribute attached to a hyperlink in order to define the type of the link or the relationship between the source and destination resources.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/010_must-prefer-existing-custom-link-relation-types.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/010_must-prefer-existing-custom-link-relation-types.md
new file mode 100644
index 0000000..694b883
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/010_must-prefer-existing-custom-link-relation-types.md
@@ -0,0 +1,14 @@
+---
+type: MUST
+id: R100035
+---
+
+# prefer existing custom link relation types
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+Already specified [custom link relation types](@guidelines/R100037) must be used instead of introducing new ones if the specified semantics are applicable.
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/020_must-prefer-iana-registered-link-relation-types.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/020_must-prefer-iana-registered-link-relation-types.md
new file mode 100644
index 0000000..c763b32
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/020_must-prefer-iana-registered-link-relation-types.md
@@ -0,0 +1,19 @@
+---
+type: MUST
+id: R100036
+---
+
+# prefer IANA-registered link relation types
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+Instead of defining [custom link relation types](@guidelines/R100037),
+[IANA-registered](http://www.iana.org/assignments/link-relations/link-relations.xhtml) link relation types must be used, if the specified semantics are applicable.
+
+Only if a more specific custom link relation type already exists, the custom option should be preferred.
+For example, the collection of all products should use `o:product` instead of `item`.
+A link relation type `o:author` must not be defined, because the IANA registry already defines `author`.
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/030_must-use-absolute-urls-for-custom-link-relation-types.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/030_must-use-absolute-urls-for-custom-link-relation-types.md
new file mode 100644
index 0000000..65b5fb2
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/030_must-use-absolute-urls-for-custom-link-relation-types.md
@@ -0,0 +1,26 @@
+---
+type: MUST
+id: R100037
+---
+
+# use absolute URLs for custom link relation types
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+If no [IANA-registered](http://www.iana.org/assignments/link-relations/link-relations.xhtml) link relation type is applicable and no [existing custom link relation type](@guidelines/R100035) can be used instead, a custom link relation type can be introduced.
+
+Custom link relations must comply with the following rules:
+
+- Custom link relation types must have a fully qualified URL.
+- The URL must be resolvable using the URI template `https://api.otto.de/portal/link-relations/{context-id}/{rel}`.
+- Just as with [profile URLs](@guidelines/R100066), link relation URLs must contain exactly one `context-id`. Context information prevent name collisions and allow grouping of link relations by domain.
+- In the URL, `context-id` and `rel` must be kebab-case.
+- Custom link relation types must be documented.
+- The documentation must be accessible in a human-readable format using the URL of the link relation type.
+
+Using a link relation type such as `"variation": {"href":"https://api.otto.de/variations/4711"}` is therefore not allowed.
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
+- [MUST use curied link relation types](@guidelines/R100038)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/040_must-use-curied-link-relation-types.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/040_must-use-curied-link-relation-types.md
new file mode 100644
index 0000000..9bdb7c6
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/040_must-use-curied-link-relation-types.md
@@ -0,0 +1,97 @@
+---
+type: MUST
+id: R100038
+---
+
+# use curied link relation types
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+Custom link relation types can be introduced if no [IANA-registered](@guidelines/R100036) or [existing custom](@guidelines/R100035) link relation type matches the semantics of a link.
+In this case, the rule [MUST use absolute URLs for custom link relation types](@guidelines/R100037) must be adhered to.
+
+A resource that uses custom link relation types to link to other resources must have a `curies` array in its `_links` property. OTTO API curie objects inside this array must have the property `href` with a value in the form of `https://api.otto.de/portal/link-relations/{context-id}/{rel}`.
+
+```json
+{
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders?page=2&pageSize=10" },
+ "curies": [
+ {
+ "name": "o",
+ "href": "https://api.otto.de/portal/link-relations/orders/{rel}",
+ "templated": true
+ }
+ ]
+ }
+}
+```
+
+Links to a resource with a custom link relation type must be curied using this CURI:
+
+```json
+{
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders?page=2&pageSize=10" },
+ "curies": [
+ {
+ "name": "o",
+ "href": "https://api.otto.de/portal/link-relations/orders/{rel}",
+ "templated": true
+ }
+ ],
+ "o:order": [
+ { "href": "https://api.otto.de/orders/4711" },
+ { "href": "https://api.otto.de/orders/0815" }
+ ]
+ }
+}
+```
+
+If the linked resources [can be embedded](@guidelines/R000041) into the response, the service should use the same link relation type that is used to link the subresources:
+
+```json
+{
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders?page=2&pageSize=10" },
+ "curies": [
+ {
+ "name": "o",
+ "href": "https://api.otto.de/portal/link-relations/orders/{rel}",
+ "templated": true
+ }
+ ],
+ "o:order": [
+ { "href": "https://api.otto.de/orders/4711" },
+ { "href": "https://api.otto.de/orders/0815" }
+ ]
+ },
+ "_embedded": {
+ "o:order": [
+ {
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders/4711" },
+ "collection": { "href": "https://api.otto.de/orders" }
+ },
+ "id": "4711",
+ "total": 4200
+ },
+ {
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders/0815" },
+ "collection": { "href": "https://api.otto.de/orders" }
+ },
+ "id": "0815",
+ "total": 12900
+ }
+ ]
+ }
+}
+```
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
+- [MUST prefer IANA-registered link relation types](@guidelines/R100036)
+- [MUST prefer existing custom link relation types](@guidelines/R100035)
+- [MUST use absolute URLs for custom link relation types](@guidelines/R100037)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/050_must-document-link-cardinality.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/050_must-document-link-cardinality.md
new file mode 100644
index 0000000..380417f
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/030_Link-relation-types/050_must-document-link-cardinality.md
@@ -0,0 +1,38 @@
+---
+type: MUST
+id: R100063
+---
+
+# document link cardinality
+
+This rule applies to APIs, that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+The HAL `_links` object holds property names of link relation types, and values of either a link object:
+
+```json
+{
+ "_links": {
+ "author": { "href": "http://api.otto.de/users/42" }
+ }
+}
+```
+
+...or an array of link objects:
+
+```json
+{
+ "_links": {
+ "item": [
+ { "href": "http://api.otto.de/products/4711" },
+ { "href": "http://api.otto.de/products/0815" }
+ ]
+ }
+}
+```
+
+In order to simplify the implementation of API clients, the client must know which link relation types contain single link objects, and which contain an array of link objects.
+Thats why every profile must document the cardinality of the link relation types used in the profile.
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/000_index.md
new file mode 100644
index 0000000..ccad5e3
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/000_index.md
@@ -0,0 +1,81 @@
+# Profiles
+
+The OTTO APIs must either support `application/json` or `application/hal+json` as a media type.
+As these formats are not specific enough for our purposes, all APIs [must be documented](@guidelines/R000003)
+using [OpenAPI Spec 3.0](http://spec.openapis.org/oas/v3.0.3).
+
+## Using profiles
+
+A `product` representation, for example, might use `application/hal+json` as a media type.
+Using OpenAPI Spec, the structure of the representation must be specified, so that developers of an API client know about the different properties of the `product`.
+
+Depending on the context, the same domain object may have several representations. For example, `product` as a search result might contain information such as availability or delivery options. `product` as part of the processed customer order shares some essential details with the search result, but would likely contain some other attributes instead. Therefore, different perspectives on the same business object may result in different representations.
+
+The specification must be identifiable by a URL such as `https://api.otto.de/portal/profiles/products/product+v1`.
+If later a second version of the `product` representation is added, the new version of the spec (`https://api.otto.de/portal/profiles/products/product+v2`) can be distinguished from the earlier version.
+
+Using the [`Accept` header with profile parameter](@guidelines/R000030), clients can now specify the requested version of the specification like this:
+
+```http request
+GET https://api.otto.de/products/42 HTTP/1.1
+Accept: application/hal+json; profile="https://api.otto.de/portal/profiles/products/product+v1"
+```
+
+The returned `product` representation (an `application/hal+json` document) [must contain a link](@guidelines/R100033) to the profile:
+
+```json
+{
+ "_links": {
+ "self": { "href": "https://api.otto.de/products/42" },
+ "profile": {
+ "href": "https://api.otto.de/portal/profiles/products/product+v1"
+ }
+ },
+ "etc": "..."
+}
+```
+
+[Following the `profile` link](@guidelines/R100066), an API client developer can now find the human-readable specification of the returned document.
+
+In many cases, the representation of a HAL resource contains hyperlinks to other resources.
+In our case, the representation might contain N links to product images (using a link relation type such as `o:product-image`) and a single link to a resource containing customer reviews (using the link relation type `o:customer-reviews`):
+
+```json
+{
+ "_links": {
+ "curies": [
+ {
+ "name": "o",
+ "href": "https://api.otto.de/portal/link-relations/products/{rel}",
+ "templated": true
+ }
+ ],
+ "self": { "href": "https://api.otto.de/products/42" },
+ "profile": {
+ "href": "https://api.otto.de/portal/profiles/products/product+v1"
+ },
+ "o:customer-reviews": { "href": "https://api.otto.de/customer-reviews/42" },
+ "o:product-images": [
+ { "href": "https://i.otto.de/42.jpg" },
+ { "href": "https://i.otto.de/43.jpg" }
+ ]
+ },
+ "etc": "..."
+}
+```
+
+As links may either contain a single link or an array of links, the specification of the `product` representation
+[must be explicit](@guidelines/R100063), whether `o:customer-reviews` contains a single link or an array of links.
+
+Profiles may also apply to request bodies: all public endpoints which accept requests with a body must support request versioning. Currently, this implicates POST, PUT, and PATCH, but other HTTP methods may follow.
+
+Even though the `profile` parameter is only defined for the media type `application/hal+json`, we chose to also use it for content type based versioning of other media types such as `application/json` and `application/json-patch+json`. This ensures a consistent usage of the `profile` parameter across all used media types.
+
+References:
+- [The 'profile' Link Relation Type (RFC 9606)](https://tools.ietf.org/html/rfc6906)
+- [SHOULD use `Accept` and `Content-Type` headers with profile parameter](@guidelines/R000030)
+- [MUST provide conventional hyperlinks](@guidelines/R100033)
+- [Paged collection](@guidelines/R100023)
+- [MUST use profiles for Public APIs](../../050_Compatibility/020_Versioning/010_must-use-profiles-for-public-rest-apis.md)
+- Parameters in `application/json` [RFC 7159, Section 11](https://datatracker.ietf.org/doc/html/rfc7159#section-11)
+- Parameters in `application/json-patch+json` [RFC 6902, Section 6](https://datatracker.ietf.org/doc/html/rfc6902#section-6)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/010_must-use-resolvable-profile-urls.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/010_must-use-resolvable-profile-urls.md
new file mode 100644
index 0000000..5b116d0
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/010_must-use-resolvable-profile-urls.md
@@ -0,0 +1,40 @@
+---
+type: MUST
+id: R100066
+---
+
+# use resolvable profile URLs
+
+To avoid name collisions for different domains and to allow grouping of profiles within the same context, the profile URI uses a `context-id`.
+The URI that identifies a profile must be resolvable and must match `https://api.otto.de/portal/profiles/{context-id}/{name}+v{version}`.
+
+Profile URIs must comply with the following conventions:
+
+- must contain exactly one `context-id`
+- `context-id` and `name` should be kebab-case
+- use plurals or _list_ to indicate a collection, e.g. `https://api.otto.de/portal/profiles/search/products+v1`.
+- must not contain team, task or use case shortcuts
+- must not contain trailing slashes
+
+The URL must point to a human-readable documentation of the profile.
+
+If the API uses [HAL](@guidelines/R000036), the `_links` of the representation [should contain a `profile` link](@guidelines/R100033) with an `href` containing the URL of the representation's profile:
+
+```json
+{
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders/4711" },
+ "profile": {
+ "href": "https://api.otto.de/portal/profiles/checkout/order+v1"
+ }
+ },
+ "total": 3000,
+ "currency": "EUR",
+ "status": "shipped"
+}
+```
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
+- [MUST provide conventional hyperlinks](@guidelines/R100033)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/020_must-use-kebab-case-profile-uris.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/020_must-use-kebab-case-profile-uris.md
new file mode 100644
index 0000000..68d1985
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/020_must-use-kebab-case-profile-uris.md
@@ -0,0 +1,12 @@
+---
+type: MUST
+id: R100070
+---
+
+# use kebab-case profile URIs
+
+Just like [other URIs](@guidelines/R000023), profile URIs must be kebab-case (and not camelCase).
+
+References:
+- [MUST use resolvable profile URLs](@guidelines/R100066)
+- [MUST use kebab-case for URIs](@guidelines/R000023)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/030_must-provide-openapi-spec-for-profiles.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/030_must-provide-openapi-spec-for-profiles.md
new file mode 100644
index 0000000..4fd7830
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/030_must-provide-openapi-spec-for-profiles.md
@@ -0,0 +1,11 @@
+---
+type: MUST
+id: R100067
+---
+
+# provide OpenAPI Spec for profiles
+
+Profiles must be specified using an OpenAPI specification, for example, by using `schemas` in a `components` block.
+
+Every version of a profile must be a separate model entity inside of the `components` block
+identified by a unique ID, which includes a version string.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/040_may-use-type-and-profile-attributes-in-hyperlinks.md b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/040_may-use-type-and-profile-attributes-in-hyperlinks.md
new file mode 100644
index 0000000..f7ae6e2
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/020_Hypermedia/040_Profiles/040_may-use-type-and-profile-attributes-in-hyperlinks.md
@@ -0,0 +1,67 @@
+---
+type: MAY
+id: R100068
+---
+
+# use type and profile attributes in hyperlinks
+
+The HAL `_links` object's property names are link relation types and values are either a link object or an array of link objects.
+
+Beside others, HAL links may contain the optional attributes ['type'](https://tools.ietf.org/html/draft-kelly-json-hal-08#section-5.3) or ['profile'](https://tools.ietf.org/html/draft-kelly-json-hal-08#section-5.6)
+
+As [versioning](../../050_Compatibility/020_Versioning/000_index.md) of APIs [should be implemented using `Accept` and `Content-Type` headers with profile parameter](@guidelines/R000030), HAL representations of a resource may use `type` and `profile` to specify the mediatype and profile of a linked resource.
+
+```json
+{
+ "_links": {
+ "author": [
+ {
+ "href": "https://api.otto.de/authors/4711",
+ "type": "application/hal+json",
+ "profile": "https://api.otto.de/portal/profiles/authors/person+v1"
+ }
+ ]
+ }
+}
+```
+
+While using the profile parameter improves the discoverability of the API (because the [link of the profile points to a human-readable documentation](@guidelines/R100066)), adding a new profile requires the API to add links for every profile:
+
+```json
+{
+ "_links": {
+ "author": [
+ {
+ "href": "https://api.otto.de/authors/4711",
+ "type": "application/hal+json",
+ "profile": "https://api.otto.de/portal/profiles/authors/person+v1"
+ },
+ {
+ "href": "https://api.otto.de/authors/4711",
+ "type": "application/hal+json",
+ "profile": "https://api.otto.de/portal/profiles/authors/person+v2"
+ }
+ ]
+ }
+}
+```
+
+Sometimes resources may link to other resources that are available in multiple mediatypes such as JSON and HTML, or JSON and XML.
+In this case, the API should use the type attribute in hyperlinks:
+
+```json
+{
+ "_links": {
+ "o:product": [
+ {
+ "href": "https://api.otto.de/products/4711",
+ "type": "application/hal+json"
+ },
+ {
+ "href": "https://www.otto.de/p/4711",
+ "type": "text/html"
+ }
+ ]
+ }
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/000_index.md
new file mode 100644
index 0000000..3c1229e
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/000_index.md
@@ -0,0 +1 @@
+# Resources
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/000_index.md
new file mode 100644
index 0000000..d32b432
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/000_index.md
@@ -0,0 +1,40 @@
+# Embedded resources
+
+The "hypertext cache pattern" allows servers to use embedded resources to dynamically reduce the number of requests a client makes, improving the efficiency and performance of the application.
+Clients should be automated for this purpose so that, for any given link relation, they will read from an embedded resource (if present) in preference to traversing a link.
+To activate this client behavior for a given link, servers should add an embedded resource into the representation with the same relation.
+Servers should not entirely "swap out" a link for an embedded resource (or vice versa) because client support for this technique is OPTIONAL.
+
+## Example
+
+The following examples show the hypertext cache pattern applied to an "author" link:
+
+_Before:_
+
+```json
+{
+ "_links": {
+ "self": { "href": "/books/the-way-of-zen" },
+ "author": { "href": "/people/alan-watts" }
+ }
+}
+```
+
+_After:_
+
+```json
+{
+ "_links": {
+ "self": { "href": "/blog-post" },
+ "author": { "href": "/people/alan-watts" }
+ },
+ "_embedded": {
+ "author": {
+ "_links": { "self": { "href": "/people/alan-watts" } },
+ "name": "Alan Watts",
+ "born": "January 6, 1915",
+ "died": "November 16, 1973"
+ }
+ }
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/010_should-embed-subresources.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/010_should-embed-subresources.md
new file mode 100644
index 0000000..d9fad43
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/010_should-embed-subresources.md
@@ -0,0 +1,39 @@
+---
+type: SHOULD
+id: R000041
+---
+
+# embed subresources
+
+Embedding related resources (also known as resource expansion) is a great way to reduce the number of requests.
+Resources that link to subresources should return these subresources using the HAL `_embedded` object.
+
+Do not embed a resource or at least embed it optional (via embed query param), if it generates unnecessary load, traffic, or response bloat.
+
+Example:
+
+```http request
+GET https://api.otto.de/products HTTP/1.1
+```
+
+```json
+{
+ "_links": {
+ "item": [{ "href": "http://api.otto.de/products/4711" }]
+ },
+ "_embedded": {
+ "item": [
+ {
+ "productId": "4711",
+ "price": {
+ "amount": 71.99,
+ "currency": "EUR"
+ }
+ }
+ ]
+ }
+}
+```
+
+References:
+- [SHOULD support optional embedding of subresources](@guidelines/R000063)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/020_should-support-optional-embedding-of-subresources.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/020_should-support-optional-embedding-of-subresources.md
new file mode 100644
index 0000000..8697e0a
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/020_should-support-optional-embedding-of-subresources.md
@@ -0,0 +1,56 @@
+---
+type: SHOULD
+id: R000063
+---
+
+# support optional embedding of subresources
+
+Resources that link to subresources [SHOULD support embedding of subresources](@guidelines/R000041).
+In order to improve flexibility of the API for different use cases, embedding of subresources should be optional, using the request parameter [`embed`](@guidelines/R000049) to select the
+subresources to embed.
+
+In cases where clients know upfront that they need some related resources they can instruct the server to prefetch that data eagerly.
+Whether this is optimized on the server, for example, by a database join, or done in a generic way, for example, with an HTTP proxy that transparently embeds resources, is up to the implementation.
+
+Example:
+
+```http request
+GET https://api.otto.de/products?embed=(item) HTTP/1.1
+```
+
+```json
+{
+ "_links": {
+ "item": [{ "href": "http://api.otto.de/products/4711" }]
+ },
+ "_embedded": {
+ "item": [
+ {
+ "_links": {
+ "self": [{ "href": "http://api.otto.de/products/4711" }]
+ },
+ "productId": "4711",
+ "price": {
+ "amount": 71.99,
+ "currency": "EUR"
+ }
+ }
+ ]
+ }
+}
+```
+
+If parameter `embed` is not provided by the client, the resources should be embedded by default.
+However, clients could also decide to NOT embed the linked resources:
+
+```http request
+GET https://api.otto.de/products?embed=() HTTP/1.1
+```
+
+```json
+{
+ "_links": {
+ "item": [{ "href": "http://api.otto.de/products/4711" }]
+ }
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/040_should-read-embedded-resources-instead-of-traversing-links.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/040_should-read-embedded-resources-instead-of-traversing-links.md
new file mode 100644
index 0000000..60b3f87
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/040_should-read-embedded-resources-instead-of-traversing-links.md
@@ -0,0 +1,15 @@
+---
+type: SHOULD
+id: R000043
+---
+
+# read embedded resources instead of traversing links
+
+For any given link relation, clients of an API should be automated to read from an embedded resource (if present) in preference to traversing a link.
+
+If supported by the API, clients should use the common request parameter
+[`embed`](@guidelines/R000049) to select the subresources they are interested in.
+
+References:
+- [SHOULD embed subresources](@guidelines/R000041)
+- [SHOULD support optional embedding of subresources](@guidelines/R000063)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/050_must-use-hal-format-for-embedded-resources.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/050_must-use-hal-format-for-embedded-resources.md
new file mode 100644
index 0000000..78b403c
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/010_Embedded-resources/050_must-use-hal-format-for-embedded-resources.md
@@ -0,0 +1,14 @@
+---
+type: MUST
+id: R000045
+---
+
+# use HAL format for embedded resources
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+If [HAL is mandatory](@guidelines/R000036) is mandatory, subresources must be embedded the same format.
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/000_index.md
new file mode 100644
index 0000000..059762b
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/000_index.md
@@ -0,0 +1,4 @@
+# Collection resources
+
+A collection resource represents a list of resources such as the collection of all products.
+The response may contain additional top level fields and metadata.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/010_must-use-plural-for-collection-resources.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/010_must-use-plural-for-collection-resources.md
new file mode 100644
index 0000000..2831915
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/010_must-use-plural-for-collection-resources.md
@@ -0,0 +1,14 @@
+---
+type: MUST
+id: R100020
+---
+
+# use plural for collection resources
+
+If a resource can be identified as a collection resource, such as `order`, use the plural for resource naming:
+
+`/orders`
+
+If we want to identify a single customer resource, this is what we do:
+
+`/orders/{orderId}`
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/020_must-use-hal-format-for-collection-resource.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/020_must-use-hal-format-for-collection-resource.md
new file mode 100644
index 0000000..9cd7ece
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/020_must-use-hal-format-for-collection-resource.md
@@ -0,0 +1,17 @@
+---
+type: MUST
+id: R100021
+---
+
+# use HAL format for collection resources
+
+This rule applies to APIs that have to comply with [REST maturity level 3](@guidelines/R000033).
+
+The list of resources is embedded under `_embedded` with the key representing the link-relation type.
+This is the same as the one used in the `_links` section.
+
+The [Embedded resources](../010_Embedded-resources/000_index.md) section provides more information on embedding documents.
+
+References:
+- [MUST implement REST maturity level 2](@guidelines/R000032)
+- [MUST implement REST maturity level 3 for transitional APIs](@guidelines/R000033)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/030_must-support-pagination-for-collection-resources.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/030_must-support-pagination-for-collection-resources.md
new file mode 100644
index 0000000..1e1e1fc
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/030_must-support-pagination-for-collection-resources.md
@@ -0,0 +1,142 @@
+---
+type: MUST
+id: R100023
+---
+
+# support pagination for collection resources
+
+Any sufficiently large collection resource must support pagination to handle the server load and support the client processing patterns.
+
+There are two approaches to pagination:
+
+- Offset/Limit-based pagination
+- Cursor-based pagination
+
+Choosing the right approach depends entirely on the constraints of the service.
+There is no preference of which one to choose, they both have their advantages.
+
+## Offset/limit-based pagination
+Offset or limit-based pagination allows the navigation of the result by specifying an offset.
+This kind of pagination is ususally implemented as page-based pagination, that means, the result set is further divided into pages of a certain size and you navigate by providing the page number instead of just an offset.
+This is the most common approach to do pagination, especially for traditional RDBM systems.
+
+PROs
+
+- well-known pattern
+- wide support for server and client
+
+CONs
+
+- assumes fixed length / fixed window: next page might contain previous elements or skip elements if elements were inserted or deleted in the meantime.
+ Should be avoided for frequently updated collections.
+
+Example:
+
+```json
+{
+ "_links": {
+ "item": [
+ { "href": "https://api.otto.de/orders/123" },
+ { "href": "https://api.otto.de/orders/124" }
+ ],
+ "prev": { "href": "https://api.otto.de/orders?page=1" },
+ "self": { "href": "https://api.otto.de/orders?page=2" },
+ "next": { "href": "https://api.otto.de/orders?page=3" },
+ "first": { "href": "https://api.otto.de/orders" },
+ "last": { "href": "https://api.otto.de/orders?page=9" }
+ },
+ "_embedded": {
+ "item": [
+ {
+ "total": 30.0,
+ "currency": "USD",
+ "status": "shipped",
+
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders/123" }
+ }
+ },
+ {
+ "total": 20.0,
+ "currency": "USD",
+ "status": "processing",
+
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders/124" }
+ }
+ }
+ ]
+ },
+
+ "_page": {
+ "size": 10,
+ "totalElements": 100,
+ "totalPages": 1,
+ "number": 0
+ },
+
+ "currentlyProcessing": 14,
+ "shippedToday": 20
+}
+```
+
+## Cursor-based pagination
+Cursor-based pagination is often preferred, especially when data sets increase quickly.
+
+PROs
+
+- window moves: next page always refers to the following elements, even if new elements are prepended in the meantime
+
+CONs
+
+- not well-known
+- limited support for clients
+- cursor might be invalid if the entry is deleted, breaking iteration
+
+Example:
+
+```json
+{
+ "_links": {
+ "self": {
+ "href": "https://api.otto.de/orders?after=532d39e987409c5b6fe7f913c9e568af"
+ },
+ "item": [
+ { "href": "https://api.otto.de/orders/123" },
+ { "href": "https://api.otto.de/orders/124" }
+ ],
+ "prev": {
+ "href": "https://api.otto.de/orders?before=911d39e987409c5b6fe7f913c9e568ca"
+ },
+ "next": {
+ "href": "https://api.otto.de/orders?after=40770e2e3ce129faadd08663fa434c33"
+ },
+ "first": { "href": "https://api.otto.de/orders" }
+ },
+ "_embedded": {
+ "item": [
+ {
+ "total": 30.0,
+ "currency": "USD",
+ "status": "shipped",
+
+ "_links": {
+ "self": { "href": "https://api.otto.de/orders/123" }
+ }
+ },
+ {
+ "total": 20.0,
+ "currency": "USD",
+ "status": "processing",
+
+ "_links": {
+ "self": { "href": "/orders/124" }
+ }
+ }
+ ]
+ },
+
+ "currentlyProcessing": 14,
+ "shippedToday": 20
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/040_must-use-common-paging-query-parameters.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/040_must-use-common-paging-query-parameters.md
new file mode 100644
index 0000000..b7b69cc
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/040_must-use-common-paging-query-parameters.md
@@ -0,0 +1,24 @@
+---
+type: MUST
+id: R100024
+---
+
+# use common paging query parameters
+
+This rule applies to public APIs. For private APIs it should be followed.
+
+For offset-based pagination you must stick to the following query parameters:
+
+- `pageSize`: Number of elements in the response or the chunk size
+- `page`: Page number that is requested (0-indexed)
+
+Requested pages outside the valid range (e.g. page 10 of a 5-element collection) must return an empty collection.
+
+For cursor-based pagination we _recommend_ using the following query parameters:
+
+- `after`: Results after the cursor position
+- `before`: Results before the cursor position
+
+References:
+- [MUST stick to conventional query parameters](@guidelines/R000049)
+- [MUST support pagination](@guidelines/R100023)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/050_should-define-default-and-max-page-size.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/050_should-define-default-and-max-page-size.md
new file mode 100644
index 0000000..56b1535
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/050_should-define-default-and-max-page-size.md
@@ -0,0 +1,16 @@
+---
+type: SHOULD
+id: R100039
+---
+
+# define default and maximum page size
+
+Every collection resource should define and document
+
+- a reasonable default page size (`defaultPageSize`)
+- a maximum page size (`maxPageSize`)
+
+which can be used as the `pageSize` query parameter.
+
+References:
+- [MUST stick to conventional query parameters](@guidelines/R000049).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/060_must-provide-page-metadata-for-offset-based-pagination.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/060_must-provide-page-metadata-for-offset-based-pagination.md
new file mode 100644
index 0000000..7938aed
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/060_must-provide-page-metadata-for-offset-based-pagination.md
@@ -0,0 +1,29 @@
+---
+type: MUST
+id: R100025
+---
+
+# provide page metadata for offset-based pagination
+
+Page metadata is important for clients that build their own links and do not use hypermedia controls.
+
+The page metadata structure must match the following structure.
+
+```json
+{
+ "_page": {
+ "size": 5,
+ "number": 0,
+ "totalElements": 50,
+ "totalPages": 10
+ }
+}
+```
+
+- `size` : Maximum number of elements in the response
+- `number` : Current page number (0 indexed)
+- `totalElements` (_optional_): Overall number of elements
+- `totalPages` (_optional_): Overall number of pages
+
+Some fields like `totalElements` and `totalPages` can be omitted if the implementation is not feasable, for example, when the calculation has a big performance impact.
+Exposing this data should consider the performance implications, not only now but over the lifespan of the service.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/090_must-use-common-sorting-query-parameter.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/090_must-use-common-sorting-query-parameter.md
new file mode 100644
index 0000000..79bdf53
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/090_must-use-common-sorting-query-parameter.md
@@ -0,0 +1,20 @@
+---
+type: MUST
+id: R100030
+---
+
+# use common sorting query parameter
+
+If simple sorting of the results is possible, the `sort` query parameter must be used.
+
+- The parameter accepts a property and an optional direction suffix (e.g. `sort=price:desc`).
+ The direction suffix can be `asc` or `desc` in any word case, i.e. `desc`. `dEsC`, `DESC` are all valid.
+- The property name should correspond to the name used in the resource representation (e.g. `sort=price.grossValue`).
+- Multiple sorting criteria [must be provided as a comma-separated list](@guidelines/R000062) (e.g. `sort=price:asc,name:desc`).
+- Services do not need to support all resource properties to be used for sorting and must respond with a `400 Bad Request` if they do not.
+- If the use case cannot be expressed using this simple sorting parameter, you should introduce a separate query parameter or a separate endpoint that accepts a complex filter/query language as a JSON body instead of a query parameter.
+
+`Note`{ label } Make sure to add the `sort` parameter to the to HAL links if necessary.
+
+References:
+- [MUST stick to conventional query parameters](@guidelines/R000049)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/100_must-use-query-parameters-for-basic-search-or-filtering.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/100_must-use-query-parameters-for-basic-search-or-filtering.md
new file mode 100644
index 0000000..8eea712
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/100_must-use-query-parameters-for-basic-search-or-filtering.md
@@ -0,0 +1,37 @@
+---
+type: MUST
+id: R100031
+---
+
+# use query parameters for basic search or filtering
+
+Resource-specific query parameters may be introduced for querying.
+They should reference the property and the operation if necessary.
+
+- `brand=Adidas`: Property `brand` matches `Adidas`
+- `minColors=5`: Either property `colors` or the computed number of colors (e.g. the resource only includes an array of colors) needs to be greater than `5`
+- `releasedAfter=2020-02-02`: Release date needs to be after `2020-02-02`
+
+Different types may have different interpretations of equality, or have their own set of operators.
+For example`color=blue` may include any shades of blue and also match `aquamarine`. `maxOrderStatus=PACKED` may include all items that are packed, in delivery or already delivered.
+
+Use common terminology, e.g.
+
+- negation: `not`
+- value ranges: `max`, `min`
+- dates: `before`, `after`
+
+For basic querying capabilities that are not specific to a property but the whole resource the `q` parameter should be used.
+Usually this is a simple text query, satisfying simple search needs that might cover a lot of use cases.
+
+Query parameters should be combinable (e.g. `brand=Puma&color=blue`) and otherwise respond with a `400 Bad Request`.
+
+If multiple values need to be supported, they [should be provided as a comma-separated list](@guidelines/R000062) (e.g. `brand=Adidas,Puma`).
+
+These query parameters must be documented with their possible values (ranges), semantics and interactions with other query parameters (e.g. multiple values form a logical _or_, but with other query parameters an _and_ connection).
+This may be obvious for single valued properties, but not necessarily for lists (e.g. `tags=sporty,retro`)
+
+`Note`{ label } Make sure to add the query parameters to the to HAL links if necessary.
+
+References:
+- [MUST stick to conventional query parameters](@guidelines/R000049)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/110_use-json-for-advanced-querying-and-filtering.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/110_use-json-for-advanced-querying-and-filtering.md
new file mode 100644
index 0000000..e0c009a
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/020_Collection-resources/110_use-json-for-advanced-querying-and-filtering.md
@@ -0,0 +1,8 @@
+---
+type: MUST
+id: R100041
+---
+
+# use JSON for advanced querying and filtering
+
+If simple query parameters are too limiting for your complex use cases, introduce a separate `POST` endpoint, which accepts a query language as JSON.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/000_index.md
new file mode 100644
index 0000000..b6b191f
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/000_index.md
@@ -0,0 +1,6 @@
+# Naming conventions
+
+When resources are well-named, an API is intuitive and easy to use.
+If resources are poorly named, the same API can feel difficult to use and understand.
+Having a strong and consistent strategy for naming REST resources results in an easy-to-understand API that developers enjoy working with.
+To make our API as easy to use as possible in this section we define our URI naming conventions.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/010_must-avoid-actions-as-resource-names.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/010_must-avoid-actions-as-resource-names.md
new file mode 100644
index 0000000..6f919e1
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/010_must-avoid-actions-as-resource-names.md
@@ -0,0 +1,21 @@
+---
+type: MUST
+id: R000015
+---
+
+# avoid actions as resource names
+
+REST is all about resources.
+Therefore, we look at the domain entities involved in web service interaction, and try to model our API around them, using the standard HTTP methods as operational indicators.
+
+DO
+
+- `POST /orders/{orderId}`
+- `DELETE /articles/{articleNumber}`
+- `POST /articles/{articleNumber}/lock`
+
+DON'T
+
+- `POST /orders/create-order`
+- `POST /articles/{articleNumber}/delete`
+- `POST /artcles/lock-article/{articleNumber}`
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/020_must-use-nouns-to-represent-resources.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/020_must-use-nouns-to-represent-resources.md
new file mode 100644
index 0000000..9f2a487
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/020_must-use-nouns-to-represent-resources.md
@@ -0,0 +1,13 @@
+---
+type: MUST
+id: R000016
+---
+
+# use nouns to represent resources
+
+The API describes resources, so the only place where actions should appear is in the HTTP methods.
+Keep URLs free of verbs and use only nouns.
+
+DO
+
+`/orders/{orderId}/processes/cancelations/{cancelationProcessId}`
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/030_must-use-lowercase-letters-in-uris.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/030_must-use-lowercase-letters-in-uris.md
new file mode 100644
index 0000000..7adad93
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/030_must-use-lowercase-letters-in-uris.md
@@ -0,0 +1,16 @@
+---
+type: MUST
+id: R000017
+---
+
+# use lowercase letters in URIs
+
+We consistently use lowercase letters in URI paths.
+
+DO
+
+
+
+DON'T
+
+
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/040_must-follow-a-logical-order.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/040_must-follow-a-logical-order.md
new file mode 100644
index 0000000..14933d2
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/040_must-follow-a-logical-order.md
@@ -0,0 +1,11 @@
+---
+type: MUST
+id: R000018
+---
+
+# follow a logical order
+
+```plaintext
+/customers/{userId}/addresses
+/customers/{userId}/addresses/{addressId}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/050_must-use-forward-slash-to-indicate-hierarchical-relationships.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/050_must-use-forward-slash-to-indicate-hierarchical-relationships.md
new file mode 100644
index 0000000..db8099e
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/050_must-use-forward-slash-to-indicate-hierarchical-relationships.md
@@ -0,0 +1,14 @@
+---
+type: MUST
+id: R000019
+---
+
+# use forward slash (/) to indicate hierarchical relationships
+
+Use the forward slash (/) in the path portion of the URI to indicate a hierarchical relationship between resources.
+
+```plaintext
+/customers/{userId}
+/customers/{userId}/addresses
+/customers/{userId}/addresses/{addressId}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/060_must-not-end-uri-with-a-trailing-slash.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/060_must-not-end-uri-with-a-trailing-slash.md
new file mode 100644
index 0000000..c5d5ad5
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/060_must-not-end-uri-with-a-trailing-slash.md
@@ -0,0 +1,16 @@
+---
+type: MUST NOT
+id: R000020
+---
+
+# end URIs with a trailing slash (/)
+
+As the last character in a URI's path does not add semantic value and may cause confusion, a URI must not end with a trailing slash (/).
+
+DO
+
+`/customers/{userId}/addresses/{addressId}`
+
+DON'T
+
+`/customers/{userId}/addresses/{addressId}/`
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/070_must-use-camelcase-for-query-parameters.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/070_must-use-camelcase-for-query-parameters.md
new file mode 100644
index 0000000..50546b3
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/070_must-use-camelcase-for-query-parameters.md
@@ -0,0 +1,16 @@
+---
+type: MUST
+id: R000022
+---
+
+# use camelCase for query parameters
+
+Use CamelCase to delimit combined words in query parameters.
+
+DO
+
+`productId`, `articleNumber`, `loginId`, `lId` etc.
+
+DON'T
+
+`product_id`, `Articlenumber`, `login-id`, `LID`
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/080_must-support-lists-for-multiple-values-of-the-same-parameter.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/080_must-support-lists-for-multiple-values-of-the-same-parameter.md
new file mode 100644
index 0000000..f58b0ce
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/080_must-support-lists-for-multiple-values-of-the-same-parameter.md
@@ -0,0 +1,10 @@
+---
+type: MUST
+id: R000062
+---
+
+# support lists for multiple values of the same query parameter
+
+If multiple values need to be supported, they should be provided as a comma-separated list (e.g. `key=value1,value2`).
+
+Must not promote usage of multiple occurrence of the same parameter in the query string (e.g. `key=value1&key=value2`), prefer lists instead.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/090_must-use-kebabcase-for-uris.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/090_must-use-kebabcase-for-uris.md
new file mode 100644
index 0000000..efe4050
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/090_must-use-kebabcase-for-uris.md
@@ -0,0 +1,13 @@
+---
+type: MUST
+id: R000023
+reviewType: automatic
+---
+
+# use kebab-case for URIs
+
+When crafting a URI, we use a hyphen to delimit combined words (kebab-case).
+
+This is what a well-formed kebab-case URI looks like:
+
+`https://api.otto.de/carts/shipping-address`
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/100_must-use-url-friendly-resource-identifiers.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/100_must-use-url-friendly-resource-identifiers.md
new file mode 100644
index 0000000..5b6dfc9
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/100_must-use-url-friendly-resource-identifiers.md
@@ -0,0 +1,24 @@
+---
+type: MUST
+id: R000024
+---
+
+# use URL-friendly resource identifiers
+
+To simplify encoding of resource IDs in URLs, their representation must only consist of ASCII strings.
+
+USE
+
+- letters [a-zA-Z]
+- numbers [0-9]
+- underscore \_
+- minus -
+- colon :
+- period .
+- and - on rare occasions - slash /
+
+DON'T USE (among others)
+
+- umlauts äöü
+- accents àèĉ
+- eszett ß
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/110_must-stick-to-conventional-query-parameters.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/110_must-stick-to-conventional-query-parameters.md
new file mode 100644
index 0000000..41f5207
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/110_must-stick-to-conventional-query-parameters.md
@@ -0,0 +1,59 @@
+---
+type: MUST
+id: R000049
+---
+
+# stick to conventional query parameters
+
+To provide clients with a consistent API, the following query parameters must be used instead of introducing custom parameters for the same functionality.
+
+## Paging
+
+This rule applies to public APIs. For private APIs it should be followed.
+
+| name | description | values | example |
+| :--------- | :--------------------------------- | :----- | :-------------- |
+| `pageSize` | Number of elements in the response | `1..` | `?pageSize=10` |
+| `page` | Page number (0-indexed) | `0..` | `?page=2` |
+| `after` | Results after the cursor position | \* | `?after=e2e3c` |
+| `before` | Results before the cursor position | \* | `?before=129fa` |
+
+
+## Sorting
+
+| name | description | values | example |
+| :----- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :---------------------- | :---------------------- |
+| `sort` | Property to sort by with optional ordering. Can be provided multiple times to sort by multiple properties. Naming should correspond to JSON field names with dot-navigation if necessary (e.g. `price.grossValue`). | `[:(asc\|desc)]` | `?sort=price:desc,name` |
+
+## Querying
+
+| name | description | values | example |
+| :--- | :---------------- | :----- | :--------- |
+| `q` | Simple text query | \* | `?q=shoes` |
+
+Introduce [your own descriptive query parameters for querying](R100031).
+
+If more advanced queries are necessary, make them available via [separate endpoints that accept queries as JSON payloads](R100041).
+
+## Filtering
+
+Depending on your use case and payload size, you can significantly reduce network bandwidth need by supporting filtering of returned entity fields.
+
+| name | description | values | example |
+| :------- | :------------------------------------------ | :----- | :------------------------------ |
+| `fields` | Selection of fields that should be returned | \* | `?fields=name,friends(id,name)` |
+
+See also [Filtering of fields using common query parameter](R004070)
+
+## Embedding
+
+| name | description | values | example |
+| :------ | :---------------------------------------- | :----- | :----------------------------- |
+| `embed` | Selection of link-relation types to embed | \* | `?embed=(item,item(o:images))` |
+
+Examples:
+
+- Do not embed anything: `?embed=()`
+- Embed products into the response: `?embed=(o:product)`
+- Embed all products and for every product also embed its variations: `?embed=(o:product, o:product(o:variation))`
+
diff --git a/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/120_should-not-use-external-identifier-as-primary-resource-identifier.md b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/120_should-not-use-external-identifier-as-primary-resource-identifier.md
new file mode 100644
index 0000000..c7aa816
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/030_Resources/030_Naming-conventions/120_should-not-use-external-identifier-as-primary-resource-identifier.md
@@ -0,0 +1,21 @@
+---
+type: SHOULD NOT
+id: R100077
+---
+
+# use external identifiers as primary resource identifiers
+
+When you create an API endpoint that requires a resource identifier, you SHOULD NOT use an external identifier as resource identifier. Example: You're about to implement `some-resource/{external-id}`, assuming that `some-resource` is your resource and `external-id` is an ID that is not under your control - you'd better not do that.
+
+Use one of the following options for your implementation instead:
+
+1. Use your own unique identifier representing the external identifier, e.g. `some-resource/{your-unique-id}`.
+2. Use a templated hypermedia link, such as `o:templated-link`.
+3. Use querying capabilities, e.g. `/some-resource?external-id-name={external-id}`.
+
+
+This is why using an external identifier as primary resource identifier is not recommended:
+
+- The API will often respond with a 404 status for consumer requests with existing identifiers, causing issues for error monitoring.
+- 404 errors should be reserved for rare cases, where an API forgets to notify a consumer about a resource being deleted and the consumer accesses this (now) stale link.
+- Business need might change the relation.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/040_Errors/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/000_index.md
new file mode 100644
index 0000000..d50802f
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/000_index.md
@@ -0,0 +1,9 @@
+# Errors
+
+HTTP status codes are the most obvious choice for error communication, but they have a limited expressiveness.
+Many status codes are too generic to explain the specific type of an error.
+Most importantly, without contextual details, they are not particularly meaningful and user-friendly.
+
+Different frameworks provide their own methods for error responses.
+Particularly in microservice architectures with different programming languages and frameworks in use, this is not optimal.
+An API must always report the same error message scheme.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/000_index.md
new file mode 100644
index 0000000..face61c
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/000_index.md
@@ -0,0 +1 @@
+# Error handling
diff --git a/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/010_must-use-problem-json-as-error-response-format.md b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/010_must-use-problem-json-as-error-response-format.md
new file mode 100644
index 0000000..d4dc819
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/010_must-use-problem-json-as-error-response-format.md
@@ -0,0 +1,45 @@
+---
+type: MUST
+id: R000034
+---
+
+# use `problem+json` as error response format
+
+We decided to adopt "Problem Details for HTTP APIs" as described in [RFC 7807](https://tools.ietf.org/html/rfc7807).
+In case of an error, all REST operations must return an error response in this well-defined format along with the appropriate media type `application/problem+json`. This error response enhances the correctly used [HTTP status code](R000012) with contextual information.
+
+Example response:
+
+```http
+HTTP/1.1 403 Forbidden
+Content-Type: application/problem+json
+
+{
+ "type": "about:blank",
+ "title": "Forbidden",
+ "status": 403,
+ "detail": "For data protection reasons, you are not allowed to view account details of others.",
+ "instance": "/account/12345/"
+}
+```
+
+## Info
+Always respond with the corresponding media type `application/problem+json` regardless of the given `accept` header.
+
+The [`type`](https://www.rfc-editor.org/rfc/rfc7807#section-3.1) of the problem object should be used to identify the problem type globally.
+The URI does not need to be resolvable. If it is resolvable, it should contain a human-readable description of the problem type.
+
+Responses should [use existing error types](R000037) if possible to keep error churn as low as possible.
+
+Response properties in detail:
+
+| property | description | mandatory |
+| ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- |
+| `type` | Identifies the type of the problem. If it is a resolvable URL, the resolved content should contain a human-readable description of the problem type. If the problem type has no additional semantics beyond the HTTP status code, the URI `about:blank` can be used. | ✔ |
+| `title` | Title should roughly contain and describe the problem. However, it should be static and not include a detailed error description, e.g., do not list the invalid values. If the type is `about:blank`, the reason phrase of the status should be used as title. | ✔ |
+| `status` | Represents the corresponding [HTTP Status Code](R000012). | ✔ |
+| `detail` | Should contain further details about the error. The RFC specifies that this field should not contain debugging information. Instead, it may contain details about the exact problem and how to solve it. It should not be parsed for further information. | ✗ |
+| `instance` | It is possible to specify the instance of the service that has the problem or the relative URI that was called. | ✗ |
+
+## Important
+In contrast to the RFC the properties `type`, `title`, and `status` are mandatory.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/020_should-use-existing-problem-types.md b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/020_should-use-existing-problem-types.md
new file mode 100644
index 0000000..1e12b4b
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/020_should-use-existing-problem-types.md
@@ -0,0 +1,13 @@
+---
+type: SHOULD
+id: R000037
+---
+
+# use existing problem types
+
+In addition to the [predefined types](https://www.rfc-editor.org/rfc/rfc7807#section-4.2) in RFC7807, we have defined
+the problem type [https://api.otto.de/portal/problems/validation-failed](@guidelines/R000038).
+
+We encourage API designers to reuse existing problem types instead of creating completely new or slightly modified ones.
+
+If none of the existing error types match the semantics of the problem, [defining a new problem type](@guidelines/R000040) is a feasible option.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/030_must-use-extension-for-input-validation-errors.md b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/030_must-use-extension-for-input-validation-errors.md
new file mode 100644
index 0000000..edc22ca
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/030_must-use-extension-for-input-validation-errors.md
@@ -0,0 +1,152 @@
+---
+type: MUST
+id: R000038
+---
+
+# use `problem+json` extension for input validation errors
+
+Validation checks can be performed on the request body, e.g. on form input values or business objects to be stored, as well as on path and query parameters. The `validation-failed` type should be used for all sorts of validation errors. All validation errors for one request should be combined into a self-sufficient error response that contains detailed messages for each failed check.
+
+If an input validation error occurs, we expect a `400 Bad Request` response.
+
+The problem `type` is defined as .
+The `title` should be _"Your request cannot be validated."_.
+The `status` code is always `400`.
+
+This results in the following structure:
+
+```json
+{
+ "type": "https://api.otto.de/portal/problems/validation-failed",
+ "title": "Your request cannot be validated.",
+ "status": 400,
+ "validationErrors": [
+ {
+ "in": "query",
+ "path": "paymentType",
+ "invalidValue": "CHECK",
+ "details": [
+ {
+ "key": "serviceX.payment.unknownValue",
+ "message": "The 'CHECK' value is not a known value for the 'paymentType' query parameter."
+ }
+ ]
+ }
+ ]
+}
+```
+
+The added `validationErrors` property should contain detailed information about all validation errors that occurred during request validation.
+Clients can parse the details section and handle the errors accordingly, e.g. display messages in the corresponding input form, remove items from the underlying collection, or request another user action.
+
+For each invalid property of the request body, path or query parameter, the API must respond with a dedicated validation error object.
+
+The following table shows the available properties:
+
+| property | description | mandatory |
+| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- |
+| `in` | Shows the location of the validated object or attribute. Allowed values:path
- URL path, e.g. `my-path-param` in `myEndpoint/{my-path-param}/detailResource`.query
- query parameter, e.g. `pageSize` for pagination.header
- header parameter, e.g. for custom header.body
- if the validated element is part of the request body.
| ✔ |
+| `path` | Depending on the "in" property, the path can have a different meaning:path
- The name of the invalid path parameter.query
- The name of the invalid query parameter.header
- The name of the invalid header.body
- A [JSONPath](https://goessner.net/articles/JsonPath/) that points to the invalid property.
| |
+| `invalidValue` | Optional string representation of the invalid value that caused the validation error, e.g. a single word in a text property, which failed the check, etc. A missing `invalidValue` may express that no value or a null value has been provided in the request. | |
+| `details` | Array of objects that hold at least one detail message for the given parameter or request body element. | ✔ |
+| `details.key` | Mandatory error message key, which can be used to map the actual UI error message, e.g. in case of interationalization. The suggested format for strings is _service.object.errorKey_, e.g. _checkout.variation.alreadyExists_.
For fixed values, please [format enumerations in UPPER_SNAKE_CASE](@guidelines/R004090) | ✔ |
+| `details.message` | Optional validation message describing the error in detail. Due to the `key` the message is optional, but still recommended for comprehensive stack tracing and logging. |
+
+We aim at consistent and informative validation messages.
+We don't want nondescript validation messages.
+
+` `{label="danger"} Invalid
+` `{label="warning"} "Not a valid US phone number"
+` `{label="success"} "Not a valid 10-digit US phone number (must not include spaces or special characters)."
+
+The JSON response looks as follows (isolated from the problem details):
+
+```json
+{
+ "validationErrors": [
+ {
+ "in": "[path|query|header|body]",
+ "path": "$.json.path.to.error.field",
+ "invalidValue": "Optional invalid client input as a string.",
+ "details": [
+ {
+ "key": "machine.readable.key1",
+ "message": "First human-readable error message."
+ },
+ {
+ "key": "machine.readable.key2",
+ "message": "Another human-readable error message."
+ }
+ ]
+ }
+ ]
+}
+```
+
+Here's a comprehensive example (creating a fictional new partner):
+
+Functional API restrictions:
+
+- The `name` property must contain between 3 and 20 characters.
+- The `name` property must not contain whitespace.
+- The `bankAccount` items need an `iban` property.
+- The new partner has to pass the credit check.
+
+Request payload:
+
+```json
+{
+ "name": "A-TOO-LONG-RETAILER-NAME WITH-WHITESPACE",
+ "bankAccounts": [
+ {
+ "ownerName": "Otto"
+ }
+ ]
+}
+```
+
+Corresponding error response:
+
+```json
+{
+ "type": "https://api.otto.de/portal/problems/validation-failed",
+ "title": "Your request cannot be validated.",
+ "status": 400,
+ "validationErrors": [
+ {
+ "in": "body",
+ "path": "$.partner.name",
+ "invalidValue": "A-TOO-LONG-RETAILER-NAME WITH-WHITESPACE",
+ "details": [
+ {
+ "key": "serviceX.partner.stringTooLong",
+ "message": "Name must have between 3 and 20 characters."
+ },
+ {
+ "key": "serviceX.partner.noWhitespace",
+ "message": "Name must not contain whitespace."
+ }
+ ]
+ },
+ {
+ "in": "body",
+ "path": "$.partner.bankAccounts[0].iban",
+ "details": [
+ {
+ "key": "serviceX.partner.valueMissing",
+ "message": "IBAN must not be empty."
+ }
+ ]
+ },
+ {
+ "in": "body",
+ "details": [
+ {
+ "key": "serviceX.partner.creditCheckFailed",
+ "message": "Credit check was not successful."
+ }
+ ]
+ }
+ ]
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/040_add-custom-extensions-by-defining-a-problem-type.md b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/040_add-custom-extensions-by-defining-a-problem-type.md
new file mode 100644
index 0000000..8ac4a08
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/040_Errors/010_Error-handling/040_add-custom-extensions-by-defining-a-problem-type.md
@@ -0,0 +1,64 @@
+---
+type: MAY
+id: R000040
+---
+
+# add custom extensions by defining a problem `type`
+
+As described in [section 3.2](https://www.rfc-editor.org/rfc/rfc7807#section-3.2) of [RFC 7807](https://www.rfc-editor.org/rfc/rfc7807) _problem `type` definitions may extend the problem details object with additional members_.
+Thus, API providers need to define a specific problem `type` if they want to add additional non-standard properties to a problem+json response.
+
+In general, clients must ignore any extension they do not recognize.
+This allows problem types to evolve and include additional information in the future.
+
+Before defining a new problem type, check if the type is really required and cannot be expressed just by using the HTTP status code.
+For example communicating to the client that he is not allowed to place an order can easily be expressed by the generic HTTP status code [403 Forbidden](https://www.rfc-editor.org/rfc/rfc9110#name-403-forbidden).
+If this is the case, just use the problem type [`about:blank`](https://www.rfc-editor.org/rfc/rfc7807#section-4.2) that signals that the problem is semantically identical to the meaning of the status code.
+
+Creating a new `type` always includes having a fixed human-readable `title` and a fixed `status` associated (see [https://www.rfc-editor.org/rfc/rfc7807#section-4](https://www.rfc-editor.org/rfc/rfc7807#section-4)).
+
+The URI encoded in `type` must be treated as an identifier that should not change. While encouraged, it does not need to be resolvable.
+The `type` URI should be in the same URL namespace as the APIs endpoints. If all API endpoints are located under `https://api.otto.de/payment/` the custom `type` URLs should als be located under the same context path (e.g., `https://api.otto.de/payment/problems/credit-too-low`).
+If possible, API providers should provide a `type` URL that resolves to a human-readable documentation (e.g., HTML) of the problem type.
+
+Example:
+
+A new context-specific type `https://api.otto.de/payment/problems/credit-too-low` is introduced. It adds the properties `maxCredit` and `requiredCredit`.
+
+```json
+{
+ "type": "https://api.otto.de/payment/problems/credit-too-low",
+ "title": "Credit too low",
+ "status": 422,
+ "detail": "The required credit \"40 €\" exceeds the maximal credit for the customer \"20 €\".",
+ "requiredCredit": 4000,
+ "maxCredit": 2000
+}
+```
+
+Example documentation:
+Problem type:
+
+Title: Credit too low
+
+Status: 422
+
+Description: This problem indicates that the credit associated with the customer account is insufficient to perform the operation of the request. The maximal credit will be communicated in the `maxCredit` property.
+
+Additional properties:
+
+- `maxCredit`: The maximal credit for the customer in euro cents. May not be present due to access restrictions.
+- `requiredCredit`: The required credit for the operation in euro cents. Always present.
+
+Example:
+
+```json
+{
+ "type": "https://api.otto.de/payment/problems/credit-too-low",
+ "title": "Credit too low",
+ "status": 422,
+ "detail": "The required credit \"40 €\" exceeds the maximal credit for the customer \"20 €\".",
+ "requiredCredit": 4000,
+ "maxCredit": 2000
+}
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/000_index.md
new file mode 100644
index 0000000..55167cf
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/000_index.md
@@ -0,0 +1,6 @@
+# Compatibility
+
+This section contains REST API specific rules to maintain compatibility.
+
+This section contains REST API-specific rules to maintain compatibility.
+Also consider the rules defined in the [general guidelines for compatibility](../../020_GENERAL-GUIDELINES/030_Compatibility/000_index.md).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/000_index.md
new file mode 100644
index 0000000..69f67e2
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/000_index.md
@@ -0,0 +1,5 @@
+# Client behavior
+
+Clients must be tolerant to changes of REST APIs. The rules in this section define how clients should behave to ease API evolution.
+
+This section contains REST API-specific additions to the general rule [MUST prepare consumers to accept compatible API extensions](@guidelines/R000029).
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/010_must-send-unknown-fields-in-put-requests.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/010_must-send-unknown-fields-in-put-requests.md
new file mode 100644
index 0000000..066e905
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/010_must-send-unknown-fields-in-put-requests.md
@@ -0,0 +1,11 @@
+---
+type: MUST
+id: R000079
+appliesTo: client
+---
+
+# send unknown fields in PUT requests
+
+To allow API evolution of services, clients must not break if providers add new properties to responses (see [MUST prepare consumers to accept compatible API extensions](@guidelines/R000029)).
+
+A client that needs to update a resource, first has to retrieve the current state of the resource using a GET request. The client may then perform the necessary modifications ignoring unknown properties. In the subsequent PUT request for updating the resource on the server, the client must send all properties (i.e. known and unknown properties) to the server.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/020_must-accept-undocumented-status-codes.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/020_must-accept-undocumented-status-codes.md
new file mode 100644
index 0000000..22bd769
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/020_must-accept-undocumented-status-codes.md
@@ -0,0 +1,11 @@
+---
+type: MUST
+id: R000080
+appliesTo: client
+---
+
+# accept undocumented status codes
+
+Clients must be prepared to handle HTTP status codes not explicitly specified in endpoint definitions.
+
+Clients are not required to understand every status code returned, but they must at least understand the class of each status code (i.e. 1xx, 2xx, 3xx, 4xx, 5xx) as defined in [RFC 7231 Section 6](https://tools.ietf.org/html/rfc7231#section-6). Clients must treat an unrecognized status code equivalent to the x00 status code (i.e. 100, 200, 300, 400, 500) of its class.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/030_must-follow-redirection.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/030_must-follow-redirection.md
new file mode 100644
index 0000000..9e29046
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/010_Client-behavior/030_must-follow-redirection.md
@@ -0,0 +1,9 @@
+---
+type: MUST
+id: R000081
+appliesTo: client
+---
+
+# follow redirection
+
+Clients must follow the redirect when the server returns the HTTP status code `HTTP 301 Moved Permanently`. This allows services to evolve without breaking compatibility.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/000_index.md
new file mode 100644
index 0000000..75407a3
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/000_index.md
@@ -0,0 +1,21 @@
+# Versioning of incompatible changes
+
+OTTO API supports two versioning approaches for HTTP APIs: via [profiles](@guidelines/R000065) and via [URL path](@guidelines/R000031). Versioning via profiles is preferred.
+
+## Why profile versioning
+
+We cannot go with a single global version number for the entire OTTO REST API, as this would mean too much coordination overhead for our feature teams.
+To implement versioning for REST APIs, we want to use industry standards wherever possible. Thus, we exclude solutions that violate existing standards or are based on draft standards that might change in an incompatible way.
+
+URL-based versioning links only to a specific version of a resource and creates a fixed dependency on a specific version. This conflicts with the use of hypermedia/HAL. Therefore, versioning must be done via profiles.
+In addition, profiles also allow resource/sub-resource independent versioning.
+
+In cases where profile-based versioning is not possible or sufficient, URL-based versioning can be applied.
+
+During the initial discussion of versioning, several options have been [identified and evaluated (internal link)](https://github.com/otto-ec/ottoapi_guidelines/blob/main/content/references/REST/versioning.md).
+
+References:
+- [Profiles in HAL+JSON](https://datatracker.ietf.org/doc/html/draft-kelly-json-hal-08#page-8)
+- [The 'profile' Link Relation Type (RFC 9606)](https://tools.ietf.org/html/rfc6906)
+- [SHOULD use `Accept` and `Content-Type` headers with profile parameter](@guidelines/R000030)
+- [MUST provide conventional hyperlinks](@guidelines/R100033)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/010_must-use-profiles-for-public-rest-apis.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/010_must-use-profiles-for-public-rest-apis.md
new file mode 100644
index 0000000..edb3c64
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/010_must-use-profiles-for-public-rest-apis.md
@@ -0,0 +1,34 @@
+---
+type: MUST
+id: R000065
+---
+
+# use profiles for Public REST APIs
+
+[Public APIs](../../../010_CORE-PRINCIPLES/030_API-scope.md) have to be versioned with [profiles](../../020_Hypermedia/040_Profiles/000_index.md) and provide comprehensive profile documentation using custom `x-ottoapi` tags.
+
+```yml
+openapi: 3.0.3
+
+x-ottoapi:
+ profiles:
+ "{{service.profiles}}/checkout/delivery-methods+v1":
+ title: Delivery methods
+ description: Contains the delivery address type allowed for a specific checkout.
+ schema:
+ $ref: ./schemas.yml#/components/schemas/DeliveryMethodOptions
+ examples:
+ v1:
+ $ref: ./examples.yml#/components/examples/DeliveryMethodsResponseV1
+ "{{service.profiles}}/checkout/delivery-methods+v2":
+ <<: *delivery-methods-v1
+ description: |
+ Contains the delivery address type allowed for a specific checkout. Includes express delivery options.
+ schema:
+ $ref: ./schemas.yml#/components/schemas/DeliveryMethodOptionsV2
+ examples:
+ v2:
+ $ref: ./examples.yml#/components/examples/DeliveryMethodsResponseV2
+
+paths: [...]
+```
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/020_should-use-accept-and-content-type-headers-with-profile-parameter.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/020_should-use-accept-and-content-type-headers-with-profile-parameter.md
new file mode 100644
index 0000000..d309ea4
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/020_should-use-accept-and-content-type-headers-with-profile-parameter.md
@@ -0,0 +1,23 @@
+---
+type: SHOULD
+id: R000030
+---
+
+# use `Accept` and `Content-Type` headers with profile parameter
+
+Change your RESTful APIs in a compatible way and avoid generating additional API versions.
+Multiple versions can significantly complicate understanding, testing, maintaining, evolving, operating and releasing our systems ([supplementary reading](http://martinfowler.com/articles/enterpriseREST.html)).
+
+If the modification of an API cannot be done in a compatible way, versioning should be implemented using the `Accept` and `Content-Type` header with `profile` parameter.
+
+If the client does not specify the required `profile` in the `Accept` header, the server may choose which version is returned.
+
+If the client does not specify the `Content-Type` header with `profile` parameter in a request with a body, the server may refuse the request with status code `400 Bad Request`.
+
+The server may decline invalid combinations of `Content-Type` and `Accept` headers with `406 Not Acceptable`. For endpoint methods featuring both a request and a response body (e.g. `POST`), only requests for the same profile version in request and response body (via `Content-Type` and `Accept` header) must be supported.
+
+References:
+- [MUST use profiles for Public APIs](@guidelines/R000065)
+- [MUST use resolvable profile URLs](@guidelines/R100066)
+- [MUST provide OpenAPI spec for profiles](@guidelines/R100067)
+- [RFC 7231, p. 59: 406 for unsupported versions](https://datatracker.ietf.org/doc/html/rfc7231#section-6.5.6)
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/030_should-not-use-resource-versioned-path.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/030_should-not-use-resource-versioned-path.md
new file mode 100644
index 0000000..979fb24
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/030_should-not-use-resource-versioned-path.md
@@ -0,0 +1,10 @@
+---
+type: SHOULD NOT
+id: R000031
+---
+
+# use resource versioned path
+
+Version numbers in URLs should not be used.
+However, if the preferred versioning option is not possible,
+a [resource versioned path (internal link)](https://github.com/otto-ec/ottoapi_guidelines/blob/main/content/references/REST/versioning.md#resource-versioned-paths) may be introduced, if absolutely required.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/040_should-not-use-uri-versioning.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/040_should-not-use-uri-versioning.md
new file mode 100644
index 0000000..94a38e1
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/020_Versioning/040_should-not-use-uri-versioning.md
@@ -0,0 +1,18 @@
+---
+type: SHOULD NOT
+id: R000026
+---
+
+# use URI versioning
+
+If you absolutely have to use a version identifier as part of your URL, do so by keeping it as a path segment relative to your resource.
+
+DO
+
+- `/users/{user-identifier}`
+- `/users/v2/{user-identifier}`
+
+DON'T
+
+- `/users/{user-identifier}?version=2`
+- `/v2/users/{user-identifier}`
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/000_index.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/000_index.md
new file mode 100644
index 0000000..80920ea
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/000_index.md
@@ -0,0 +1,3 @@
+# Deprecation of HTTP APIs
+
+HTTP APIs need to provide deprecation and sunset information _on the wire_. The following rules define this requirement in more detail.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/010_must-monitor-usage-of-deprecated-api-scheduled-for-sunset.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/010_must-monitor-usage-of-deprecated-api-scheduled-for-sunset.md
new file mode 100644
index 0000000..60cccea
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/010_must-monitor-usage-of-deprecated-api-scheduled-for-sunset.md
@@ -0,0 +1,8 @@
+---
+type: MUST
+id: R000068
+---
+
+# monitor usage of deprecated API scheduled for sunset
+
+API providers must monitor the usage of the sunset API, API version, or API feature in order to observe migration progress and avoid uncontrolled breaking effects on clients still using the API.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/020_should-add-deprecation-and-sunset-header-to-responses.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/020_should-add-deprecation-and-sunset-header-to-responses.md
new file mode 100644
index 0000000..224d7b3
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/020_should-add-deprecation-and-sunset-header-to-responses.md
@@ -0,0 +1,23 @@
+---
+type: SHOULD
+id: R000069
+---
+
+# add `Deprecation` and `Sunset` header to responses
+
+During the deprecation phase, the API provider should add a `Deprecation` header (see [draft: RFC Deprecation HTTP Header](https://tools.ietf.org/html/draft-dalal-deprecation-header)) and - if also planned - a `Sunset` header (see [RFC 8594](https://tools.ietf.org/html/rfc8594#section-3)) to each response affected by a deprecated element (see [MUST reflect deprecation in API specifications](@guidelines/R000067)).
+
+The `Deprecation` header can either be set to `true` when a feature is disabled, or it can carry a deprecation timestamp at which a replacement is made available and consumers are no longer allowed to use the feature (see [MUST NOT start using deprecated APIs](@guidelines/R000071)).
+The optional `Sunset` timestamp indicates when consumers have to stop using a feature at the latest.
+The sunset timestamp should always offer an appropriate time interval for switching to a replacement feature.
+
+Example:
+
+```http
+Deprecation: Sun, 31 Dec 2024 23:59:59 GMT
+Sunset: Sun, 31 Dec 2025 23:59:59 GMT
+```
+
+If multiple elements are deprecated, the `Deprecation` and `Sunset` headers are expected to be set to the earliest timestamp to reflect the shortest interval consumers are expected to get active.
+
+Adding the `Deprecation` and `Sunset` header to the response is not sufficient to gain client consent to shut down an API or feature.
diff --git a/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/030_should-add-monitoring-for-deprecation-and-sunset-header.md b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/030_should-add-monitoring-for-deprecation-and-sunset-header.md
new file mode 100644
index 0000000..23eda12
--- /dev/null
+++ b/03_api_guidelines/030_REST-GUIDELINES/050_Compatibility/040_Deprecation/030_should-add-monitoring-for-deprecation-and-sunset-header.md
@@ -0,0 +1,10 @@
+---
+type: SHOULD
+id: R000070
+appliesTo: client
+---
+
+# add monitoring for `Deprecation` and `Sunset` header
+
+Consumers should monitor the `Deprecation` and `Sunset` headers in HTTP responses to get information about future sunset of APIs and API features (see [SHOULD add `Deprecation` and `Sunset` header to responses](@guidelines/R000069)).
+We recommend that API providers build alerts on this monitoring information to ensure alignment with API consumers on the required migration task.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..6ebc35a
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,22 @@
+# Contributing to the OTTO Retail-API Documentation
+
+## Setup for contributing
+
+If you want to contribute, please fork this repository on GitHub, install [Git](https://git-scm.com/) to your computer and clone your new forked repository.
+
+Changes and additions to the OTTO Retail-API documentation require a pull request against `main`.
+This ensures that the intended changes:
+ - can be properly reviewed with context.
+ - do not negatively affect or block the build process.
+ - integrate into the overall picture.
+
+In any case, choose a descriptive PR title that explains the context and main purpose of the PR.
+Use the present tense and start the title description with a verb.
+
+
+## Documentation styleguide
+ - Use [GitHub-flavored markdown](https://github.com/microsoft/api-guidelines/blob/vNext/CONTRIBUTING.md#pull-requests:~:text=GitHub%2Dflavored%20markdown)
+ - Use syntax-highlighted examples liberally
+ - Write one sentence per line
+
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..aae4510
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,395 @@
+Attribution 4.0 International
+
+=======================================================================
+
+Creative Commons Corporation ("Creative Commons") is not a law firm and
+does not provide legal services or legal advice. Distribution of
+Creative Commons public licenses does not create a lawyer-client or
+other relationship. Creative Commons makes its licenses and related
+information available on an "as-is" basis. Creative Commons gives no
+warranties regarding its licenses, any material licensed under their
+terms and conditions, or any related information. Creative Commons
+disclaims all liability for damages resulting from their use to the
+fullest extent possible.
+
+Using Creative Commons Public Licenses
+
+Creative Commons public licenses provide a standard set of terms and
+conditions that creators and other rights holders may use to share
+original works of authorship and other material subject to copyright
+and certain other rights specified in the public license below. The
+following considerations are for informational purposes only, are not
+exhaustive, and do not form part of our licenses.
+
+ Considerations for licensors: Our public licenses are
+ intended for use by those authorized to give the public
+ permission to use material in ways otherwise restricted by
+ copyright and certain other rights. Our licenses are
+ irrevocable. Licensors should read and understand the terms
+ and conditions of the license they choose before applying it.
+ Licensors should also secure all rights necessary before
+ applying our licenses so that the public can reuse the
+ material as expected. Licensors should clearly mark any
+ material not subject to the license. This includes other CC-
+ licensed material, or material used under an exception or
+ limitation to copyright. More considerations for licensors:
+ wiki.creativecommons.org/Considerations_for_licensors
+
+ Considerations for the public: By using one of our public
+ licenses, a licensor grants the public permission to use the
+ licensed material under specified terms and conditions. If
+ the licensor's permission is not necessary for any reason--for
+ example, because of any applicable exception or limitation to
+ copyright--then that use is not regulated by the license. Our
+ licenses grant only permissions under copyright and certain
+ other rights that a licensor has authority to grant. Use of
+ the licensed material may still be restricted for other
+ reasons, including because others have copyright or other
+ rights in the material. A licensor may make special requests,
+ such as asking that all changes be marked or described.
+ Although not required by our licenses, you are encouraged to
+ respect those requests where reasonable. More_considerations
+ for the public:
+ wiki.creativecommons.org/Considerations_for_licensees
+
+=======================================================================
+
+Creative Commons Attribution 4.0 International Public License
+
+By exercising the Licensed Rights (defined below), You accept and agree
+to be bound by the terms and conditions of this Creative Commons
+Attribution 4.0 International Public License ("Public License"). To the
+extent this Public License may be interpreted as a contract, You are
+granted the Licensed Rights in consideration of Your acceptance of
+these terms and conditions, and the Licensor grants You such rights in
+consideration of benefits the Licensor receives from making the
+Licensed Material available under these terms and conditions.
+
+
+Section 1 -- Definitions.
+
+ a. Adapted Material means material subject to Copyright and Similar
+ Rights that is derived from or based upon the Licensed Material
+ and in which the Licensed Material is translated, altered,
+ arranged, transformed, or otherwise modified in a manner requiring
+ permission under the Copyright and Similar Rights held by the
+ Licensor. For purposes of this Public License, where the Licensed
+ Material is a musical work, performance, or sound recording,
+ Adapted Material is always produced where the Licensed Material is
+ synched in timed relation with a moving image.
+
+ b. Adapter's License means the license You apply to Your Copyright
+ and Similar Rights in Your contributions to Adapted Material in
+ accordance with the terms and conditions of this Public License.
+
+ c. Copyright and Similar Rights means copyright and/or similar rights
+ closely related to copyright including, without limitation,
+ performance, broadcast, sound recording, and Sui Generis Database
+ Rights, without regard to how the rights are labeled or
+ categorized. For purposes of this Public License, the rights
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
+ Rights.
+
+ d. Effective Technological Measures means those measures that, in the
+ absence of proper authority, may not be circumvented under laws
+ fulfilling obligations under Article 11 of the WIPO Copyright
+ Treaty adopted on December 20, 1996, and/or similar international
+ agreements.
+
+ e. Exceptions and Limitations means fair use, fair dealing, and/or
+ any other exception or limitation to Copyright and Similar Rights
+ that applies to Your use of the Licensed Material.
+
+ f. Licensed Material means the artistic or literary work, database,
+ or other material to which the Licensor applied this Public
+ License.
+
+ g. Licensed Rights means the rights granted to You subject to the
+ terms and conditions of this Public License, which are limited to
+ all Copyright and Similar Rights that apply to Your use of the
+ Licensed Material and that the Licensor has authority to license.
+
+ h. Licensor means the individual(s) or entity(ies) granting rights
+ under this Public License.
+
+ i. Share means to provide material to the public by any means or
+ process that requires permission under the Licensed Rights, such
+ as reproduction, public display, public performance, distribution,
+ dissemination, communication, or importation, and to make material
+ available to the public including in ways that members of the
+ public may access the material from a place and at a time
+ individually chosen by them.
+
+ j. Sui Generis Database Rights means rights other than copyright
+ resulting from Directive 96/9/EC of the European Parliament and of
+ the Council of 11 March 1996 on the legal protection of databases,
+ as amended and/or succeeded, as well as other essentially
+ equivalent rights anywhere in the world.
+
+ k. You means the individual or entity exercising the Licensed Rights
+ under this Public License. Your has a corresponding meaning.
+
+
+Section 2 -- Scope.
+
+ a. License grant.
+
+ 1. Subject to the terms and conditions of this Public License,
+ the Licensor hereby grants You a worldwide, royalty-free,
+ non-sublicensable, non-exclusive, irrevocable license to
+ exercise the Licensed Rights in the Licensed Material to:
+
+ a. reproduce and Share the Licensed Material, in whole or
+ in part; and
+
+ b. produce, reproduce, and Share Adapted Material.
+
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
+ Exceptions and Limitations apply to Your use, this Public
+ License does not apply, and You do not need to comply with
+ its terms and conditions.
+
+ 3. Term. The term of this Public License is specified in Section
+ 6(a).
+
+ 4. Media and formats; technical modifications allowed. The
+ Licensor authorizes You to exercise the Licensed Rights in
+ all media and formats whether now known or hereafter created,
+ and to make technical modifications necessary to do so. The
+ Licensor waives and/or agrees not to assert any right or
+ authority to forbid You from making technical modifications
+ necessary to exercise the Licensed Rights, including
+ technical modifications necessary to circumvent Effective
+ Technological Measures. For purposes of this Public License,
+ simply making modifications authorized by this Section 2(a)
+ (4) never produces Adapted Material.
+
+ 5. Downstream recipients.
+
+ a. Offer from the Licensor -- Licensed Material. Every
+ recipient of the Licensed Material automatically
+ receives an offer from the Licensor to exercise the
+ Licensed Rights under the terms and conditions of this
+ Public License.
+
+ b. No downstream restrictions. You may not offer or impose
+ any additional or different terms or conditions on, or
+ apply any Effective Technological Measures to, the
+ Licensed Material if doing so restricts exercise of the
+ Licensed Rights by any recipient of the Licensed
+ Material.
+
+ 6. No endorsement. Nothing in this Public License constitutes or
+ may be construed as permission to assert or imply that You
+ are, or that Your use of the Licensed Material is, connected
+ with, or sponsored, endorsed, or granted official status by,
+ the Licensor or others designated to receive attribution as
+ provided in Section 3(a)(1)(A)(i).
+
+ b. Other rights.
+
+ 1. Moral rights, such as the right of integrity, are not
+ licensed under this Public License, nor are publicity,
+ privacy, and/or other similar personality rights; however, to
+ the extent possible, the Licensor waives and/or agrees not to
+ assert any such rights held by the Licensor to the limited
+ extent necessary to allow You to exercise the Licensed
+ Rights, but not otherwise.
+
+ 2. Patent and trademark rights are not licensed under this
+ Public License.
+
+ 3. To the extent possible, the Licensor waives any right to
+ collect royalties from You for the exercise of the Licensed
+ Rights, whether directly or through a collecting society
+ under any voluntary or waivable statutory or compulsory
+ licensing scheme. In all other cases the Licensor expressly
+ reserves any right to collect such royalties.
+
+
+Section 3 -- License Conditions.
+
+Your exercise of the Licensed Rights is expressly made subject to the
+following conditions.
+
+ a. Attribution.
+
+ 1. If You Share the Licensed Material (including in modified
+ form), You must:
+
+ a. retain the following if it is supplied by the Licensor
+ with the Licensed Material:
+
+ i. identification of the creator(s) of the Licensed
+ Material and any others designated to receive
+ attribution, in any reasonable manner requested by
+ the Licensor (including by pseudonym if
+ designated);
+
+ ii. a copyright notice;
+
+ iii. a notice that refers to this Public License;
+
+ iv. a notice that refers to the disclaimer of
+ warranties;
+
+ v. a URI or hyperlink to the Licensed Material to the
+ extent reasonably practicable;
+
+ b. indicate if You modified the Licensed Material and
+ retain an indication of any previous modifications; and
+
+ c. indicate the Licensed Material is licensed under this
+ Public License, and include the text of, or the URI or
+ hyperlink to, this Public License.
+
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
+ reasonable manner based on the medium, means, and context in
+ which You Share the Licensed Material. For example, it may be
+ reasonable to satisfy the conditions by providing a URI or
+ hyperlink to a resource that includes the required
+ information.
+
+ 3. If requested by the Licensor, You must remove any of the
+ information required by Section 3(a)(1)(A) to the extent
+ reasonably practicable.
+
+ 4. If You Share Adapted Material You produce, the Adapter's
+ License You apply must not prevent recipients of the Adapted
+ Material from complying with this Public License.
+
+
+Section 4 -- Sui Generis Database Rights.
+
+Where the Licensed Rights include Sui Generis Database Rights that
+apply to Your use of the Licensed Material:
+
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
+ to extract, reuse, reproduce, and Share all or a substantial
+ portion of the contents of the database;
+
+ b. if You include all or a substantial portion of the database
+ contents in a database in which You have Sui Generis Database
+ Rights, then the database in which You have Sui Generis Database
+ Rights (but not its individual contents) is Adapted Material; and
+
+ c. You must comply with the conditions in Section 3(a) if You Share
+ all or a substantial portion of the contents of the database.
+
+For the avoidance of doubt, this Section 4 supplements and does not
+replace Your obligations under this Public License where the Licensed
+Rights include other Copyright and Similar Rights.
+
+
+Section 5 -- Disclaimer of Warranties and Limitation of Liability.
+
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
+
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
+
+ c. The disclaimer of warranties and limitation of liability provided
+ above shall be interpreted in a manner that, to the extent
+ possible, most closely approximates an absolute disclaimer and
+ waiver of all liability.
+
+
+Section 6 -- Term and Termination.
+
+ a. This Public License applies for the term of the Copyright and
+ Similar Rights licensed here. However, if You fail to comply with
+ this Public License, then Your rights under this Public License
+ terminate automatically.
+
+ b. Where Your right to use the Licensed Material has terminated under
+ Section 6(a), it reinstates:
+
+ 1. automatically as of the date the violation is cured, provided
+ it is cured within 30 days of Your discovery of the
+ violation; or
+
+ 2. upon express reinstatement by the Licensor.
+
+ For the avoidance of doubt, this Section 6(b) does not affect any
+ right the Licensor may have to seek remedies for Your violations
+ of this Public License.
+
+ c. For the avoidance of doubt, the Licensor may also offer the
+ Licensed Material under separate terms or conditions or stop
+ distributing the Licensed Material at any time; however, doing so
+ will not terminate this Public License.
+
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
+ License.
+
+
+Section 7 -- Other Terms and Conditions.
+
+ a. The Licensor shall not be bound by any additional or different
+ terms or conditions communicated by You unless expressly agreed.
+
+ b. Any arrangements, understandings, or agreements regarding the
+ Licensed Material not stated herein are separate from and
+ independent of the terms and conditions of this Public License.
+
+
+Section 8 -- Interpretation.
+
+ a. For the avoidance of doubt, this Public License does not, and
+ shall not be interpreted to, reduce, limit, restrict, or impose
+ conditions on any use of the Licensed Material that could lawfully
+ be made without permission under this Public License.
+
+ b. To the extent possible, if any provision of this Public License is
+ deemed unenforceable, it shall be automatically reformed to the
+ minimum extent necessary to make it enforceable. If the provision
+ cannot be reformed, it shall be severed from this Public License
+ without affecting the enforceability of the remaining terms and
+ conditions.
+
+ c. No term or condition of this Public License will be waived and no
+ failure to comply consented to unless expressly agreed to by the
+ Licensor.
+
+ d. Nothing in this Public License constitutes or may be interpreted
+ as a limitation upon, or waiver of, any privileges and immunities
+ that apply to the Licensor or You, including from the legal
+ processes of any jurisdiction or authority.
+
+
+=======================================================================
+
+Creative Commons is not a party to its public
+licenses. Notwithstanding, Creative Commons may elect to apply one of
+its public licenses to material it publishes and in those instances
+will be considered the "Licensor." The text of the Creative Commons
+public licenses is dedicated to the public domain under the CC0 Public
+Domain Dedication. Except for the limited purpose of indicating that
+material is shared under a Creative Commons public license or as
+otherwise permitted by the Creative Commons policies published at
+creativecommons.org/policies, Creative Commons does not authorize the
+use of the trademark "Creative Commons" or any other trademark or logo
+of Creative Commons without its prior written consent including,
+without limitation, in connection with any unauthorized modifications
+to any of its public licenses or any other arrangements,
+understandings, or agreements concerning use of licensed material. For
+the avoidance of doubt, this paragraph does not form part of the
+public licenses.
+
+Creative Commons may be contacted at creativecommons.org.
diff --git a/README.md b/README.md
index 5b47eda..e4cfa96 100644
--- a/README.md
+++ b/README.md
@@ -1 +1,30 @@
-# retail-api-hub-documentation
\ No newline at end of file
+# OTTO Retail-API
+
+Latest published version:
+[**PDF**](https://github.com/otto-de/retail-api-hub-documentation/releases/download/v1.0.0/otto-retail-api-guidelines.pdf)
+[**HTML**](https://github.com/otto-de/retail-api-hub-documentation/releases/download/v1.0.0/otto-retail-api-guidelines.html)
+
+
+## Getting access
+The OTTO Retail-API is only available to suppliers with access to OTTO Supplier Connect.
+If you are a registered supplier, log into your OTTO Supplier Connect account and request a Retail-API client.
+Once your request has been processed, you will receive a client ID and client secret, both of which are required for authentication.
+
+If you have any questions, comments or require assistance, please don't hesitate to contact us and we will get back to you as soon as possible.
+As a registered supplier, open a new ticket in OTTO Supplier Connect via the Helpdesk and select the subcategory "Weitere Schnittstellen".
+
+Before you start the implementation, please read the [Getting Started](01_getting-started) guide.
+
+For detailed information on how to use our API, see [About the API](02_about-the-api).
+
+Please also refer to the [OTTO API Guidelines](03_api_guidelines/000_index.md).
+
+The OTTO Retail-API specifications can be found in the [References](references) folder.
+
+
+## This repository
+This repository contains a collection of documents and related materials for the implementation of the OTTO Retail-API.
+To contribute to this repository, please see the [contribution guidelines](CONTRIBUTING.md).
+
+# License
+We have published these guidelines under the CC-BY-4.0 (Creative commons Attribution 4.0) license. Please see [LICENSE file](LICENSE).
diff --git a/references/README.md b/references/README.md
new file mode 100644
index 0000000..d69a654
--- /dev/null
+++ b/references/README.md
@@ -0,0 +1,2 @@
+# OTTO Retail-API specifications
+