> ## Documentation Index
> Fetch the complete documentation index at: https://docs.occtoo.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Destination

Data consumption in Occtoo involves retrieving and utilizing data from various custom destinations. Occtoo allows users to create destinations in Occtoo Studio, specifying properties such as identifier, languages, regions, and endpoints. These destinations can be either public — accessible via a unique URL without authentication — or protected, requiring an access token. Users can fetch destination data using various [filtering](#filtering) and querying capabilities provided by the Occtoo API. This flexibility enables efficient data retrieval tailored to specific needs, supporting a wide range of use cases and integrations.

## Destination API consumption

A destination comprises one or more endpoints for data retrieval. Each endpoint supports both GET and POST methods. These request methods offer various filtering options, allowing users to customize the response according to their needs. Several [query parameters](#api-query-parameters) are available, all of which are optional. If no parameters are specified, the API fetches the first 50 results by default.

### OpenAPI documentation

All destinations provide an OpenAPI URL. This URL allows users to view and test the various endpoints exposed by the destination. The OpenAPI specification URL is formed by combining the destination's base URL with the suffix '/openapi'.

```text theme={null}
https://global.occtoo.com/{@CUSTOMER}/{@DESTINATION}/v1/openapi
```

<Tip>
  To try the feature go to [https://editor-next.swagger.io/](https://editor-next.swagger.io/). From the menu select 'File' => 'Import URL' and enter the OpenAPI URL to see and test the destination. If it is a protected destination, client id and secret need to be provided.
</Tip>

### Unprotected and protected destinations

A destination can be either unprotected or protected. An unprotected destination is public, meaning it is available to anyone with access to the URL and does not require authentication. Protected destinations, on the other hand, restrict access to authorized users only, ensuring that sensitive data and functionalities are secure. Authentication for protected destinations is done using an access token.

#### Token endpoint

The token endpoint is bundled with the destination and is accessed via a POST request. Upon passing valid credentials, a token is returned. This token remains valid for 24 hours from its creation and can be reused an unlimited number of times within that timeframe.

```text theme={null}
https://destinations.occtoo.com/destinations/{@DESTINATION-ID}/token
```

<Warning>
  There is a rate limit of 100 token requests per hour for an application, so it is **highly** recommended to employ mechanisms to store and reuse the received token for the time period it is valid.
  If the rate limit is exceeded the token endpoint will respond with a 429 HTTP response. The 429 response contains a Retry-After header which gives an indication when the rate limit is reset.
</Warning>

##### Request payload

The tokens endpoint accepts a JSON payload in the body, consisting of the properties `clientId` and `clientSecret`. These properties correspond to the identifiers provided by the [application](/guides/studio/destinations/register-an-application) used to access the destination.

```javascript theme={null}
{
    "clientId" : "{@APPLICATION-ID}",
    "clientSecret": "{@APPLICATION-SECRET}"
}
```

##### Response payload

Upon successful authentication of the passed credentials, an **access token** is returned from the API using the format below.

```javascript theme={null}
{
    "accessToken": "eyJhbGciOiJSUzI1NiIsImtpZCI6Im9jY3Rvby1jb20iLCJ0eXAiOiJhdCtqd3QifQ.eyJuYmYiOjE3MTc1MDg4MjYsImV4cCI6MTcxNzUxMjQyNiwiaXNzIjoiaHR0cHM6Ly9hdXRoLXRlc3Qub2NjdG9vLmNvbSIsImF1ZCI6IjhjZDQ1NjBmLWI4NjctNGQ3YS1hOTcyLWEzNTVjZDVjMjZkNyIsImNsaWVudF9pZCI6ImRlNTAwNjYyLTkwZmMtNDY2OC1hOGI0LTgwMmNiZjQwMTY4MCIsImNsaWVudF9yZXNvdXJjZSI6IjhjZDQ1NjBmLWI4NjctNGQ3YS1hOTcyLWEzNTVjZDVjMjZkNyIsImp0aSI6IjNFMDdENzgyM0E3MjBEQkVCNDQ0NzI4NzRFRkQ3Qzc2IiwiaWF0IjoxNzE3NTA4ODI2LCJzY29wZSI6WyI4Y2Q0NTYwZi1iODY3LTRkN2EtYTk3Mi1hMzU1Y2Q1YzI2ZDciXX0.gP2mMFFEYF4Pp1nw_UESdZpK9be8VnX1DCL_jIgZKdaF2rHG4nHT4PDDoV6W3V9A8pYI3HiVMZk7tEAn4WvPU5qzL-ayLiYD8DnGD7X5TpipGJ3cX7cZOZvqKzR7Kvx9affgbMZw7mBEJgnkrw6mDCRAt_6jJIo33AQMjD-oyFOFEn-xCmUnABwLw7sldiCQNRTDVQ_uFCWgePPeb3iAGEJd8Yh0oKUsfuuGBpSeBJtlLM-s5ts-2BNXYweUpP6MUIiC746EVVfcMdoTdzLEjkwpddScLacT-QI54E7zN00U4dlIS4uWoRLUvnZoczNlG_kyryckDTnz_LV5897N_Q",
    "expiresIn": 3600
}
```

#### Accessing a protected destination

To access a protected destination API, users must use the obtained access token as a [bearer token](https://oauth.net/2/bearer-tokens/). The bearer token must be included in the authorization header of every API request, formatted as "Authorization: Bearer `access token`". The API validates this token to verify the application's identity and permissions, granting access only if the token is valid and unexpired.

### Request response compression

[Gzip compression](https://www.gzip.org/) is a widely used method for reducing the size of data transmitted over networks, resulting in faster loading times and reduced bandwidth usage. In the context of Occtoo destinations, gzip compression is enabled to further optimize data retrieval processes. However, it is an opt-in feature, meaning callers can enable it by defining the 'Accept-Encoding' property in the HTTP header and setting its value to 'gzip'. This instructs the server to compress the response data before sending it to the caller, enhancing performance and efficiency in data retrieval tasks.

```curl theme={null}
curl --location 'https://global.occtoo.com/exampletenant/exampledestination/v1/exampleendpoint' \
--header 'Accept-Encoding: gzip' \
--header 'Authorization: Bearer {@DESTINATION-ACCESS-TOKEN}'
```

### Facets

Facets aid in building navigation features by marking certain fields as facets. This allows retrieval of all values for those fields given a filter, along with the total count for each value. When adding a facet, you need to specify the property and the maximum number of facet values to retrieve for that property. Additionally, you can set a localized label for the facet header, which is useful when presenting the values in a UI.

<Warning>
  Adding a facet size above 50 can have a negative effect on response times
</Warning>

```javascript theme={null}
/*Example facet response*/

"facets": [
    {
      "propertyId": "category",
      "header": "Category",
      "values": [
        {
          "count": 1,
          "key": "Category 1"
        },
        {
          "count": 83,
          "key": "Category 2"
        }
      ]
    },
    {
      "propertyId": "brand",
      "header": "Brand",
      "values": [
        {
          "count": 3,
          "key": "Brand A"
        },
        {
          "count": 6,
          "key": "Brand B"
        }
      ]
    }
 ]
```

### Filtering

All properties can be filtered, though the syntax varies depending on the type of property. To see the different types for a specific endpoint, an OpenAPI URL is generated as described in the [Documentation](#openapi-documentation) section.

#### GET filtering

When using the GET method, all comparisons are performed using the EQUAL operator. It is possible to filter on different properties in a single query, utilizing the AND comparison. Additionally, filtering on multiple values for one property is achieved using an OR comparison.

<Tabs>
  <Tab title="Filter on two different properties">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?brand=BrandA&category=Category1
    ```
  </Tab>

  <Tab title="Filter on two different values for one property (OR)">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?brand=BrandA&brand=BrandB
    ```
  </Tab>
</Tabs>

#### POST filtering

Within the POST body, a 'filter' can be supplied to reduce the number of returned results. The filter may be empty. However, nested content (object arrays) within each result cannot be filtered.

The filter contains a list of queries, any one of which must be fulfilled. Each query may include criteria for inclusion (*must*), exclusion (*must\_not*), or both. Criteria are expressed as properties of the criteria, where the ID matches the ID of the property in the result.

All criteria within the same query must be met.

##### Example

<Tabs>
  <Tab title="Must filter on two values">
    Include only results for market "DE" OR "FI".

    ```javascript theme={null}
    {
      "filter": [
        {
          "must":{
            "market":["DE", "FI"]
          }
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Must and must not filters combined">
    Include only results for market "DE", "FI" OR "UK".
    For markets "DE", "FI" additionally exclude results of type "ExcludeThisTypeForDEAndFI".

    ```javascript theme={null}
    {
      "filter": [
        {
          "must":{
            "market":["DE", "FI"]
          },
          "must_not":{
            "type":["ExcludeThisTypeForDEAndFI"]
          }
        },
        {
          "must":{
            "market":["UK"]
          }
        }
      ]
    }
    ```
  </Tab>
</Tabs>

Filter values are always passed as arrays of values. Various data types are available for filter values, matching the data type of the property in the result:

* String: Regular string value.
* Datetime: Format yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZ. No UTC conversion is done on the data.
* Integer: Regular integer value.
* Double: Uses '.' as a decimal separator.
* Bool: Possible values are true/false.

Matching of property values is performed using exact matches against ANY of the provided filter values.

##### Example

Alternate query syntax. These queries are the same.

```javascript theme={null}
{
  "filter": [
    {
      "must":{
        "market":["DE", "FI"]
      }
    },
    {
      "must":{
        "market": {
          "operator": "Equal",
          "values": ["DE", "FI"]
        }
      }
    }
  ]
}
```

When a result has a property with multiple values, and more than one value must match at once, the standard OR between filter values can be replaced with an AND by using the "match" parameter set to "All" using the alternate criteria syntax.

##### Example

Include only results that include tags "A" AND "B".

```javascript theme={null}
{
  "filter": [
    {
      "must":{
        "tags": {
          "operator": "Equal",
          "values": ["A", "B"],
          "match": "All"
        }
      }
    }
  ]
}
```

In cases where exact matching of filter values is not very useful, Range-style criteria are available using separate "operators" for DateTime, Integer, and Double properties.

Range operators:

* GreaterThan
* GreaterThanOrEqual
* LessThan
* LessThanOrEqual
* Between
* BetweenInclusive

##### Example

<Tabs>
  <Tab title="Greater than operator">
    Include only results whose price is greater than 15.0.

    ```javascript theme={null}
    {
      "filter": [
        {
          "must":{
              "price": {
                "operator": "GreaterThan",
                "values": [15.0]
              }
          }
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Greater than or equal to operator">
    Include only results whose price is greater than or equal to 15.0.

    ```javascript theme={null}
    {
      "filter": [
        {
          "must":{
              "price": {
                "operator": "GreaterThanOrEqual",
                "values": [15.0]
              }
          }
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Less than operator">
    Include only results whose price is less than 15.0.

    ```javascript theme={null}
    {
      "filter": [
        {
          "must":{
              "price": {
                "operator": "LessThan",
                "values": [15.0]
              }
          }
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Less than or equal to operator">
    Include only results whose price is less than or equal to 15.0.

    ```javascript theme={null}
    {
      "filter": [
        {
          "must":{
              "price": {
                "operator": "LessThanOrEqual",
                "values": [15.0]
              }
          }
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Between operator">
    Include only results whose price is greater than 15.0 but less than 20.0.

    ```javascript theme={null}
    {
      "filter": [
        {
          "must":{
              "price": {
                "operator": "Between",
                "values": [15.0, 20.0]
              }
          }
        }
      ]
    }
    ```
  </Tab>

  <Tab title="Between inclusive operator">
    Include only results whose price is at least 15.0 and at most 20.0.

    ```javascript theme={null}
    {
      "filter": [
        {
          "must":{
              "price": {
                "operator": "BetweenInclusive",
                "values": [15.0, 20.0]
              }
          }
        }
      ]
    }
    ```
  </Tab>
</Tabs>

### API query parameters

#### id

**Type: string (array)**

Get one or multiple entries by ID.

<Tabs>
  <Tab title="GET">
    For the GET request the ID parameter can be repeated to get multiple entries at once.

    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?id=id1
    ```
  </Tab>

  <Tab title="POST">
    The POST request uses the filter syntax and can be combined freely with other filters to specifically include or exclude IDs.

    ```javascript theme={null}
    // Payload body

    //To include only specific ids
    {
      "filter": [{
        "must": { "id": ["id1", "id2", "id3"] }
      }]
    }

    //To exclude specific ids
    {
      "filter": [{
        "must_not": { "id": ["id1", "id2", "id3"] }
      }]
    }
    ```
  </Tab>
</Tabs>

#### select

**Type: string (array)**

Return only the specified properties for each entry instead of the full result object. This reduces the response size and is useful when a client only needs a few properties from an endpoint that exposes many. The property names are the ones exposed by the endpoint, meaning the [alias](/guides/studio/destinations/endpoint-content#rename-a-property-for-the-api) if one is configured.

If 'select' is omitted, all properties configured on the endpoint are returned.

For the GET request, the 'select' parameter can be repeated to return multiple properties at once. For the POST request, an array of one or more property names is required.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?select=propertyA&select=propertyB
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "select": ["propertyA", "propertyB"]
    }
    ```
  </Tab>
</Tabs>

<Tip>
  'Select' can be combined freely with filtering, sorting, and searching — those operate on all properties of the endpoint, not just the selected ones. If only the IDs of the entries are needed, use [listIds](#listids) instead.
</Tip>

#### listIds

**Type: boolean**

This allows for an efficient way to retrieve the IDs of the entries. No additional properties are returned. By default, 50 IDs are returned. If more results are needed, it can be used together with [top](#top).

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?listIds=true
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    // Payload body

    {
        "listIds": true
    }
    ```
  </Tab>
</Tabs>

#### includeTotals

**Type: boolean**

Includes the total number of results for the query in the response. However, it has a negative impact on request performance that increases with the number of entries.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?includeTotals=true
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
        "includeTotals": true
    }
    ```
  </Tab>
</Tabs>

#### includeMeta

**Type: boolean**

Include a 'meta' section for each entry in the response. This section contains information about when the entry was last updated, its type, language, and ID. The timestamp is in UTC datetime format.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?includeMeta=true
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "includeMeta": true
    }
    ```
  </Tab>
</Tabs>

Example of meta data payload included on each result entry

```json theme={null}
 "@meta": {
            "@timestamp": "2022-07-26T16:12:19.6882765Z",
            "@id": "74a7d309",
            "@type": "SomeCardType",
            "@language": "en"
          }
```

#### top

**Type: int32**

Retrieve the top x number of entries from the endpoint. This can be used together with [skip](#skip) for implementing pagination. The maximum number of entries to retrieve with 'top' and 'skip' is 10 000.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?top=100
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    // Payload body
    {
      "top": 100
    }
    ```
  </Tab>
</Tabs>

#### skip

**Type: int32**

Skip x number of entries in the request. This can be used together with [top](#top) for implementing pagination. The maximum number of entries to retrieve with 'top' and 'skip' is 10 000.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    GET https://{@DESTINATION-ENDPOINT-ADDRESS}?skip=10
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "skip": 10
    }
    ```
  </Tab>
</Tabs>

<Tip>
  The maximum number of entries to retrieve with top and skip is 10 000. If more results are needed, use [after](#after).
</Tip>

#### after

**Type: string (array)**

'After' is used together with sorting and allows for getting the entries after the provided value for the specified sorting property. It can be used together with either [sortAsc](#sortasc) or [sortDesc](#sortdesc). By default, 50 entries are returned. If more results are needed, it can be used together with [top](#top). A maximum of 10 000 entries can be returned from 'top'.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?after=id123&sortAsc=id
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "after": "id123",
      "sortAsc": ["id"]
    }
    ```
  </Tab>
</Tabs>

#### sortAsc

**Type: string (array)**

To sort a property in ascending order, use the 'sortAsc' parameter. For the GET request, the 'sortAsc' parameter can be repeated to sort on multiple properties at once. For the POST request, an array of one or more sort properties is required.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?sortAsc=propertyA
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "sortAsc": ["propertyA"]
    }
    ```
  </Tab>
</Tabs>

#### sortDesc

**Type: string (array)**

To sort a property in descending order, use the 'sortDesc' parameter. For the GET request, the 'sortDesc' parameter can be repeated to sort on multiple properties at once. For the POST request, an array of one or more sort properties is required.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?sortDesc=propertyA
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "sortDesc": ["propertyA"]
    }
    ```
  </Tab>
</Tabs>

#### language

**Type: string**

Specify requested language.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?language=languageCode
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "language": "languageCode"
    }
    ```
  </Tab>
</Tabs>

<Tip>
  To return values for all languages in one request, the parameter can be set to 'all' (?language=all). This will return one entry for each language. However, top limits still apply, so make sure to request results as multiples of the number of languages.
</Tip>

#### search

**Type: string (array)**

To search property values matching the specified phrase, use the 'search' parameter. This is used together with 'searchOn' to specify which properties to search on. It matches the entire search phrase, but the character '\*' can be used for wildcard search. For instance, '\*value' is equivalent to 'ends with value', 'value\*' is equivalent to 'begins with value', and '\*value\*' is equivalent to 'contains value'.

For the GET request, the 'search' parameter can be repeated to search on multiple phrases at once. For the POST request, an array of one or more search properties is required. If multiple phrases are provided, they will be combined using AND logic.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?search=phrase
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "search": ["phrase"]
    }
    ```
  </Tab>
</Tabs>

#### searchOn

**Type: string (array)**

To specify the properties to search on, use the 'searchOn' parameter. For the GET request, the 'searchOn' parameter can be repeated to search on multiple properties at once. For the POST request, an array of one or more search properties is required.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?searchOn=property
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "searchOn": ["property"]
    }
    ```
  </Tab>
</Tabs>

#### caseInsensitiveSearch

**Type: boolean**

By default, the search is case sensitive. To perform a case insensitive search, set the flag 'caseInsensitiveSearch' to true.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?caseInsensitiveSearch=true
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "caseInsensitiveSearch": true
    }
    ```
  </Tab>
</Tabs>

#### periodSince

**Type: datetime**

Retrieve all entries modified after the provided timestamp. All times are compared using UTC in the format yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZ.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?periodSince=2022-07-26T17:54:19.7458504Z
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "period": 
      {
        "since" : "2022-07-26T17:54:19.7458504Z"
      }
    }
    ```
  </Tab>
</Tabs>

#### periodBefore

**Type: datetime**

Retrieve all entries modified before the provided timestamp. All times are compared using UTC in the format yyyy-MM-dd'T'HH:mm:ss.SSSSSSSZ.

<Tabs>
  <Tab title="GET">
    ```text theme={null}
    https://{@DESTINATION-ENDPOINT-ADDRESS}?periodBefore=2022-07-26T17:54:19.7458504Z
    ```
  </Tab>

  <Tab title="POST">
    ```javascript theme={null}
    //Payload body
    {
      "period": 
      {
        "before" : "2022-07-26T17:54:19.7458504Z"
      }
    }
    ```
  </Tab>
</Tabs>

<Tip>
  The parameter 'periodSince' can be combined with 'periodBefore' to get all updates within a specific range.
</Tip>

### API response

The structure of the response object remains consistent whether it's a POST or a GET request. It always includes the language being retrieved and an array of result objects. If there are no results, an empty array is returned. The result objects vary between endpoints and destinations, as they are configured individually. To view the structure of a specific endpoint, an OpenAPI URL is generated, as described in the [OpenAPI documentation](#openapi-documentation) section.

If the API parameter [`select`](#select) is used, each result object contains only the requested properties.

If the endpoint contains facets, they are included as an array. The structure of the facet response is described under [facets](#facets). If facets are not configured, the "facets" property is omitted from the response.

The "total" property indicates the total number of results and is only included in the response if the API parameter [`includeTotals`](#includetotals) is present and set to true. If the parameter is not present, the "total" property is omitted from the response.

```javascript theme={null}
{
  "language": "en",
  "total": 1847,
  "results": [],
  "facets" : []
}
```
