# Ad Delivery: Integration methos

In this chapter, you will find the different ways to integrate with the Adhese ad server and Gateway, which will allow you to request and display ads across channels.
Both components are integrated in the same way. The difference lies in the internal configuration and demand orchestration — not in the way requests are made.
All integrations are secure by design and aligned with Adhese’s privacy-first approach. The platform operates without third-party cookies and relies on server-side processing of first-party data to deliver targeted advertising.

# Typescript Web SDK

The Adhese Typescript SDK for web implementations can be found on [https://adhese.github.io/sdk\_typescript/](https://adhese.github.io/sdk_typescript/)

# Prebid

Adhese is available as a bidder for both Prebid.js and Prebid Server and has been used in various custom wrappers created by publishers and SSPs.

Once connected you can use the Adhese adserver to run your own campaigns, connect to other Adhese instances or connect to [Adhese Gateway](https://documentation.adhese.org/books/gateway).

<p class="callout info"><a href="https://docs.prebid.org/dev-docs/bidders.html#adhese">Prebid.js Bidder</a> on <a href ="https://prebid.org/">Prebid</a> +
<a href="https://docs.prebid.org/dev-docs/pbs-bidders.html#adhese">Prebid Server Bidder</a> on <a href="https://prebid.org/">Prebid</a></p>

# Mobile SDK

<p class="callout warning">The Mobile SDK should be considered legacy functionality. It's not used for new implementations.</p>

Information on the mobile Adhese SDK's can be found on the following GitHub pages:

Android: [https://github.com/adhese/ava](https://github.com/adhese/ava)

iOS: [https://github.com/adhese/avi](https://github.com/adhese/avi)

# Request API: JSON endpoint (old)

For integrations where you don't want to use an SDK or other library, we provide the request endpoint so you can build the request URLs yourself. Both GET and POST requests are supported, but there is a slight difference between them.

## POST endpoint

This endpoint provides access to the ad server and gateway functionality for server applications. This functionality allows implementers to send an HTTP POST request to their Adhese endpoint, returning an array of ads for the requested ad slots.

The POST body can contain a number of parameters, the structure of which is documented below.

The API is public and requires no authentication. Any client-side framework that can interpret a JSON response can request the same endpoint.

### Endpoint URL

To obtain the endpoint URL for your account, contact [Adhese Support](https://documentation.adhese.org/books/introduction/page/adhese-support).

Default look of the endpoint URL:

```html
https://ads-{customer}.adhese.com/json/

```

### Request Type

HTTP POST request over an HTTPS connection. In a production environment, no cookies are needed; all data is passed in the request body.

For debugging purposes, add a ‘set-cookie’ header with the value ‘debugKey=\[any\_value\]’. This will make all activity from your requests available in [Gateway Debug Logging](https://documentation.adhese.org/books/adhese-gateway/page/adhese-gateway#bkmrk-gateway-debug-loggin).

<p class="callout danger">Do not use this debug cookie for production requests. If used on a large scale, it will add significant latency to your responses.</p>

### POST Body

The body of your POST request can contain JSON following a fixed structure. There are three main properties.

```
{
    "slots": [
        {
            "slotname": "some_slot"
        },
        ...
    ],
    "parameters": {
        "kw": [
        "cheese",
        "wine"
        ],
        ...
    },
    "user": {
      "ext": {
        "eids": []
      }
    }
}

```

#### slots

An array of slot objects containing all the ad units required for a given page or state of the end-user application. At least one slot is required.

Each slot contains at least a 'slotname', which is a unique identifier for a specific advertisement placement. This string is stored in the Adhese database and used for targeting campaigns.

```
"slots": [
        {
            "slotname": "some_slot"
        },
        {
            "slotname": "another_slot"
        }
    ]

```

#### parameters

An object that contains a set of properties and their corresponding array of values. The purpose of this object is to define one or more attributes that tell you something about the page, user, context, etc.

The parameter keys are fixed two-character codes defined in your Adhese account. The value is always an array of strings. All parameter properties are optional. You can leave them out if they are empty or irrelevant, or send an empty array as value.

```
"parameters": {
    "kw": [
        "cheese",
        "wine"
    ],
    "mi": [
        "ABCDEF123456"
    ]
}

```

*In the example above, “kw“ is used for “search keyword“and “mi” for “member id.”*

#### slot level parameters

A slot can also contain a 'parameters' attribute that follows the same structure. Parameters can be defined at both the request and slot levels. The values of these parameters will be merged for each corresponding slot.

```
"slots": [
    {
        "slotname": "some_slot",
        "parameters": {
            "ps": "top"
        }
    },
    {
        "slotname": "another_slot",
        "parameters": {
            "ps": "bottom"
        }
    }
]

```

#### user

The user property is reserved for situations where external ID providers are available, and their identifiers need to be transferred to buyers further down the line. This is mainly useful in an open market context. For more info, please contact our Support Team.

### Example of a complete request body

```
{
    "slots": [
        {
            "slotname": "homepage_banner"
        },
        {
            "slotname": "homepage_rectangle_top"
        },
        {
            "slotname": "homepage_rectangle_bottom"
        },
        {
            "slotname": "homepage_halfpage",
            "parameters": {
                ...
            }
        }
    ],
    "parameters": {
        // Example user ID
        "id": [
            "1234567890ABCD"
        ],
        // Example product categories
        "ct": [
            "computers",
            "laptops"
        ],
        // search keywords
        "kw": [
            "cheese",
            "wine"
        ]
    }
}

```

### Response Codes

#### 200

All is OK. If no advertisements are available, an empty array will be in the response body.

#### 454

No slots were added to the request body, so no advertisements can be returned. An error message containing the message' slots cannot be empty' is added to the response as header ‘x-adhese-bad-request’.

#### 442

A duplicate slotname has been used for one or more slots. An error message is added to the response as header ‘x-adhese-bad-request’ containing message ‘request contains duplicate slots: \[list of duplicate slots\]’

#### 500

Internal server error. Further information could be available in the debug log if it was a debug request or via Adhese Support.

### Response Object

<p class="callout danger">To be moved to its own page</p>

The response object contains a number of attributes. A full description can be found here: [https://github.com/adhese/sdk#response-object-structure](https://github.com/adhese/sdk#response-object-structure).

The relevant attributes for a server-side integration are the following:

## slotName

A string containing the name of the slot for which this response is intended. When requesting multiple slots simultaneously, this can be used as a key to link the responses to the slots you have added to the request body.

## tag

The ad markup used to render the advertisement on the client is returned as a string and can be of any type interpretable by the client or requester.

For typical web and display advertising, the markup is usually a fragment of HTML that can be inserted into a container on the page.

For video or audio advertising, the markup is usually a VAST-compliant XML document.

For native advertising, the markup typically comprises a JSON object containing all the elements required by a client application or browser script to render the ad correctly.

<p class="callout info">The markup can contain JSON as a string, which the application consuming the responses must parse to get the actual JSON.</p>

## width

The ad container width in pixels is needed for the ad to display as intended.

## height

The ad container height in pixels is needed for the ad to display as intended.

## trackedImpressionCounter

The client application can call a unique URL when the ad is added to a page, even if it is not yet visible and the user has to scroll to see it.

The call to the URL can be asynchronous, and the response can be ignored.

The call to this URL registers a 'paid impression' for a specific ad, as defined by the IAB.

## viewableImpressionCounter

The client application can call a unique URL when the ad is visible in the viewport for at least 50% and for at least one second. The call to the URL can be asynchronous, and the response can be ignored.

A call to this URL will register a 'viewable impression', a metric defined by the IAB and used in digital advertising.

## clickTag

The clickTag attribute contains a unique URL that can be used to create a link that is counted as a 'click' on the ad and redirects the user to the ad's landing page.

When implemented in an application that does not use links or URLs, the clickTag URL can register a click while ignoring the response, just like the impression counters.

## Event tracking

<p class="callout danger">To be moved to its own page</p>

### Creating an Event Tracking URL

You can create unique URLs based on the JSON output to register any event related to the ad once it is rendered on screen.

A tracking event URL structure looks like this:

```
https://[ad_request_host]/track-[your_event_string]/[response.id]/sl[response.slotID]/II[response.impressionID]

```

### Adding an Event Tracking URL to a template

In an Advar or HTML5 template, event-tracking URLs can be created using [server-side request parameters](https://documentation.adhese.org/books/integrations-and-delivery/page/server-side-request-parameters). A tracking event would then look like this:

```
https://[adheseDomain:ad_host]/track-[your_event_string]/[adheseLogID]/sl[adheseReplace:sl]/II[adheseReplace:II]

```

## Example of a full response object

```
[
    {
        "dm": "dmDMGo2g0c0;ADV0",
        "adType": "714x224",
        "adFormat": "714x224",
        "timeStamp": "1642511791000",
        "share": "0",
        "priority": "0",
        "orderId": "2",
        "adspaceId": "2",
        "adspaceKey": "CI-ADH-12345678",
        "body": "",
        "trackingUrl": "",
        "tracker": "https://ads-demo.adhese.com/track/121//sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/?t=1642610778623",
        "extraField1": "",
        "extraField2": "",
        "altText": "",
        "height": "224",
        "width": "714",
        "tag": "{    '_links': {        'self': {            'href': 'https://ads-demo.adhese.com/raylene//sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/ad121-4/UR/acties/'        }    },    'resourceType': 'Editorial',    'type': 'HalfWidthSmallResponsiveEditorial',    'position': {        'x': 'left',        'y': 'top'    },    'contentSize': 'half',    'color': 'drop',    'text': {        'title': 'Maak kans op een exclusieve Bud Dreams Jacket',        'body': 'Bekijk de actie'    },    'images': [        {            'title': '<IMAGE_TITLE>',            'width': 714,            'height': 224,            'link': {                'href': 'https://pool-demo.adhese.com/pool/lib/4_2nd_1.jpg'            }        },        {            'title': '<IMAGE_TITLE>',            'width': 714,            'height': 224,            'link': {                'href': 'https://pool-demo.adhese.com/pool/lib/4_2nd_1.jpg'            }        }    ],    'navItem': {        'title': 'Bekijk de actie',        'link': {            'href': 'https://ads-demo.adhese.com/raylene//sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/ad121-4/URhttps://ah.nl/acties/winactie-bud'        }    }}",
        "tagUrl": "https://pool-demo.adhese.com/pool/lib/4_0.advar",
        "heightLarge": "224",
        "widthLarge": "714",
        "libId": "4",
        "id": "121",
        "advertiserId": "0",
        "orderProperty": "brands-budweiser",
        "ext": "advar",
        "swfSrc": "https://pool-demo.adhese.com/pool/lib/4_0.advar",
        "url": "https://ads-demo.adhese.com/raylene//sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/ad121-4/UR",
        "clickTag": "https://ads-demo.adhese.com/raylene//sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/ad121-4/UR",
        "swfSrc2nd": "https://pool-demo.adhese.com/pool/lib/4_2nd_1.jpg",
        "swfSrc3rd": "",
        "swfSrc4th": "",
        "poolPath": "https://pool-demo.adhese.com/pool/lib/",
        "comment": "",
        "adDuration": "0",
        "adDuration2nd": "0",
        "adDuration3rd": "0",
        "adDuration4th": "0",
        "orderName": "Example Bud Dream Jacket",
        "creativeName": "Bud Dream Jacket",
        "deliveryMultiples": "free",
        "deliveryGroupId": "o2g0c0",
        "adspaceStart": "1630447200000",
        "adspaceEnd": "1643669999000",
        "swfSrc5th": "",
        "swfSrc6th": "",
        "adDuration5th": "0",
        "adDuration6th": "0",
        "width3rd": "0",
        "width4th": "0",
        "width5th": "0",
        "width6th": "0",
        "height3rd": "0",
        "height4th": "0",
        "height5th": "0",
        "height6th": "0",
        "slotName": "ah.nl-test_bonus_bonusregulier_left-714x224",
        "slotID": "6",
        "impressionCounter": "https://ads-demo.adhese.com/track/121//sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/?t=1642610778623",
        "trackedImpressionCounter": "https://ads-demo.adhese.com/track/121//sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/?t=1642610778623",
        "viewableImpressionCounter": "https://ads-demo.adhese.com/track/121-Adhese_IABview/sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/?t=1642610778623",
        "additionalCreatives": [],
        "origin": "JERLICIA",
        "originData": {},
        "auctionable": "true",
        "additionalViewableTracker": "",
        "additionalCreativeTracker": "https://ads-demo.adhese.com/track/121-additional-4/sl6/brChrome/brChrome97/brOSX/brdesktop/dtdesktop/ogcontrol/II19656e55-a3cd-4a39-8ed5-28f575a2e9b1/tlnone/ctaardappel-groente-fruit/ctkruiden-knoflook-pepers/umknown/kwkaas/om0/cuc/cxveel-gebruikt:snel/cxkeuken:italiaans/cxmomenten:wat_eten_we_vandaag/id1234567890ABCD/miAH0099887766/A2127.68.78.84/?t=1642610778623",
        "extension": {
            "mediaType": "banner",
            "prebid": {
                "cpm": {
                    "amount": "13.047",
                    "currency": "EUR"
                }
            }
        }
    }
]

```

# Request API: Headsup endpoint

The headsup endpoint returns **all** the materials for the campaigns running on the requested DOOH position.   
It can be used by the DOOH screens to **retrieve and cache all materials** at the beginning of the day to avoid delays by having to download materials during the day.

<p class="callout warning">To ensure that the assets are included in the response, the *Use in heads-up file* setting **must be enabled at format level**. This action can be performed by all admin users in the Adhese UI.</p>

```html
https://headsup-[customer].adhese.org/api/headsup/download-list/sl[positioncode]
```

<table id="bkmrk-parameters-value-req" style="width: 100%;"><colgroup><col style="width: 12.7533%;"></col><col style="width: 72.5948%;"></col><col style="width: 14.6519%;"></col></colgroup><thead><tr><td>Parameters</td><td>Value</td><td>Required</td></tr></thead><tbody><tr><td>customer</td><td>The name of your Adhese account</td><td>Yes</td></tr><tr><td>position code</td><td>The code of the position you wish to request: \[location code\]\[optional position code\]-\[format code\]. This value is always prefixed by 'sl'.</td><td>Yes</td></tr></tbody></table>

### Response

 The JSON response consists of a "media" array that may be empty or populated with multiple ad objects, depending on the number of active campaigns. **The structure of an ad object is fixed and can not be customized.**

The ID and URL from which to download the file is identical and is also available in the stack endpoint that will be used to download DOOH playlists during the day.

**Example**

```json
{
    "media":[
        {
            "ad":{
                "id":"https://pool-demo.adhese.com/pool/lib/562_2nd_1.mp4",
                "mime":"video/mp4",
                "curl":"https://pool-demo.adhese.com/pool/lib/562_2nd_1.mp4",
                "filesize": 15470592,
                "checksum":"071f717962db99cc137d138696d33209f2e4818d42a54f70dfa6606eeb1b640b"
            }
        },
        {
            "ad":{
                "id":"https://pool-demo.adhese.com/pool/lib/560_2nd_1.mp4",
                "mime":"video/mp4",
                "curl":"https://pool-demo.adhese.com/pool/lib/560_2nd_1.mp4",
                "filesize": 15470592,
                "checksum":"4e78745a33518ff22c1c9f39852a49c1c0fadd0adf722e3394ad1215d5e5ff5b"
            }
        },
        {
            "ad":{
                "id":"https://pool-demo.adhese.com/pool/lib/561_2nd_1.mp4",
                "mime":"video/mp4",
                "curl":"https://pool-demo.adhese.com/pool/lib/561_2nd_1.mp4",
                "filesize": 6582272,
                "checksum":"64d2eab6d51b208c0cec3fc4d64c53381e5d41ae2a1d4c5b7704b1818bdb6158"
            }
        }
    ]
}
```

# Request API: Stack endpoint

The stack endpoint allows you to request **one position** for which Adhese will return a **list of ads**. There are 2 versions:

1. /m/stack/: returns a limited amount of ads
2. /e/stack/: returns an unlimited<sup>1</sup> amount of ads<sup>2</sup>

<p class="callout warning">**<span style="text-decoration: underline;">1</span>** The adserver rules still apply and will influence which campaigns are part of the response. Not all booked campaigns are necessarily part of the returned array. </p>

<p class="callout warning"><span style="text-decoration: underline;">**2**</span> The **/e/stack/** endpoint must be enabled by Adhese support before it becomes available</p>

### m/stack endpoint

```html
https://ads-[customer].adhese.com/m/stack/sl[positioncode]/[target prefix][target value]?max_ads=[amount]
```

<table id="bkmrk-parameters-value-req-1" style="width: 100%; height: 182.578px;"><thead><tr style="height: 29.7969px;"><td style="width: 11.4422%; height: 29.7969px;">**Parameters**</td><td style="width: 76.405%; height: 29.7969px;">**Value**</td><td style="width: 12.1528%; height: 29.7969px;">**Required**</td></tr></thead><tbody><tr style="height: 29.7969px;"><td class="align-left" style="width: 11.4422%; height: 29.7969px;">customer</td><td class="align-left" style="width: 76.405%; height: 29.7969px;">The name of your Adhese account</td><td class="align-left" style="width: 12.1528%; height: 29.7969px;">Yes</td></tr><tr style="height: 46.5938px;"><td class="align-left" style="width: 11.4422%; height: 46.5938px;">position code</td><td class="align-left" style="width: 76.405%; height: 46.5938px;">The code of the position you wish to request is \[location code\]-\[format code\]. This value is always prefixed by 'sl'.</td><td class="align-left" style="width: 12.1528%; height: 46.5938px;">Yes</td></tr><tr style="height: 46.5938px;"><td style="width: 11.4422%; height: 46.5938px;">custom target</td><td style="width: 76.405%; height: 46.5938px;">Similar to the basic JSON GET endpoint, the stack request can contain target information by adding a prefix followed by a value. More values can be separated with a ; </td><td style="width: 12.1528%; height: 46.5938px;">No</td></tr><tr style="height: 29.7969px;"><td class="align-left" style="width: 11.4422%; height: 29.7969px;">max\_ads<sup>1</sup></td><td class="align-left" style="width: 76.405%; height: 29.7969px;">The maximum number of ads you wish to request</td><td class="align-left" style="width: 12.1528%; height: 29.7969px;">Yes</td></tr></tbody></table>


<p class="callout info"><span style="text-decoration: underline;">**1**</span> A configuration on the adserver can be activated to ensure the max\_ads value never exceeds a specific limit. When the parameter is left empty, the configured limit will be used instead. </p>

### e/stack endpoint

```html
https://ads-[customer].adhese.com/e/stack/sl[positioncode]/[target prefix][target value]
```

<table id="bkmrk-%C2%A0-value-required-cus" style="width: 100%; height: 152.781px;"><thead><tr style="height: 29.7969px;"><td style="width: 11.4422%; height: 29.7969px;">**Parameters**</td><td style="width: 76.405%; height: 29.7969px;">**Value**</td><td style="width: 12.1528%; height: 29.7969px;">**Required**</td></tr></thead><tbody><tr style="height: 29.7969px;"><td class="align-left" style="width: 11.4422%; height: 29.7969px;">customer</td><td class="align-left" style="width: 76.405%; height: 29.7969px;">The name of your Adhese account</td><td class="align-left" style="width: 12.1528%; height: 29.7969px;">Yes</td></tr><tr style="height: 46.5938px;"><td class="align-left" style="width: 11.4422%; height: 46.5938px;">position code</td><td class="align-left" style="width: 76.405%; height: 46.5938px;">The code of the position you wish to request is \[location code\]-\[format code\]. This value is always prefixed by 'sl'.</td><td class="align-left" style="width: 12.1528%; height: 46.5938px;">Yes</td></tr><tr style="height: 46.5938px;"><td style="width: 11.4422%; height: 46.5938px;">custom target</td><td style="width: 76.405%; height: 46.5938px;">Similar to the basic JSON GET endpoint, the stack request can contain target information by adding a prefix followed by a value. More values can be separated with a ; </td><td style="width: 12.1528%; height: 46.5938px;">No</td></tr></tbody></table>

### Stack response

#### Returned code

The response contains JSON code: an **ads** array that will either be empty or populated with one or more objects, depending on the number of active campaigns.

The structure of the objects within the array is determined by the advar template used when setting up the creatives.

<details id="bkmrk-an-example-response-"><summary>An example response used in a DOOH setup</summary>

```json
{
    "ads":[
        {
            "id":"https://pool-demo.adhese.com/pool/lib/562_2nd_1.mp4",
            "dur":28.07,
            "prio":15,
            "booking_prio":0,
            "publisher":"1",
            "key":"",
            "proofOfPlay":"https://ads-demo.adhese.com/track/3474/sl357/tlnone/piplayer_id/A2?1746011926824",
            "error":"https://ads-demo.adhese.com/track/3474-PLAY_ERROR_[ERRORCODE]/sl357/tlnone/piplayer_id/A2/?1746011926824"
        },
        {
            "id":"https://pool-demo.adhese.com/pool/lib/561_2nd_1.mp4",
            "dur":11.45,
            "prio":15,
            "booking_prio":0,
            "publisher":"1",
            "key":"",
            "proofOfPlay":"https://ads-demo.adhese.com/track/3444/sl357/tlnone/piplayer_id/A2?1746011926824",
            "error":"https://ads-demo.adhese.com/track/3444-PLAY_ERROR_[ERRORCODE]/sl357/tlnone/piplayer_id/A2/?1746011926824"
        },
        {
            "id":"https://pool-demo.adhese.com/pool/lib/560_2nd_1.mp4",
            "dur":18.85,
            "prio":15,
            "booking_prio":0,
            "publisher":"1",
            "key":"",
            "proofOfPlay":"https://ads-demo.adhese.com/track/3455/sl357/tlnone/piplayer_id/A2?1746011926824",
            "error":"https://ads-demo.adhese.com/track/3455-PLAY_ERROR_[ERRORCODE]/sl357/tlnone/piplayer_id/A2/?1746011926824"
        }
    ]
}
```

</details>#### Sorting the returned list

The order in which the ads array is populated can be be configured by using the **sequence** property in the advar template.  
As value you can use a number that is filled in through the advar form, or use one of the [Adhese macro's](https://documentation.adhese.org/books/templating/page/macros-for-templates-and-advar-templates) that return an ID.   
  
When the **sequence** property is added and given a value, the adserver will sort the available ads based on its value. In the example below we use the CREATIVE ID to sort the array **from lowest ID to highest ID**.

```json
"sequence": <ADHESE_LIB_ID>
```

<p class="callout info">The sequence property is only used by the adserver and will be removed before the response is returned</p>

# Request API: JSON endpoint

The JSON endpoint is the foundation of every display integration with Adhese. It gives you direct access to the ad server and Gateway without an SDK or library: you build the request, and Adhese returns the ads for your slots as JSON. Any environment that can send an HTTPS request and parse JSON can use it — a backend service, a CMS, a mobile app, ...

The Typescript Web SDK and the Prebid adapter use this same endpoint under the hood. If you use one of those, you do not need this page for implementation, but it remains the reference for what actually happens under the hood.

The API is public and requires no authentication and **cookies are not required** for an integration to work.

## Endpoint URL

Each Adhese account has its own endpoint. The default pattern is:

```
https://ads-[customer].adhese.com/json/
```

## Making a POST request

Send a **POST request over HTTPS** with a JSON body (structure below). This is the recommended method for all new integrations.

<p class="callout info">The endpoint also accepts **GET requests,** where the slots and parameters are encoded in the URL path instead of a body. We prefer the POST request but documentation can be retrieved</p>

### Request body

The POST body is a JSON object with up to three top-level properties:

```json
{
    "slots": [
        {
            "slotname": "some_slot"
        },
        ...
    ],
    "parameters": {
        "kw": [
        "cheese",
        "wine"
        ],
        ...
    },
    "user": {
      "ext": {
        "eids": []
      }
    }
}
```

<table id="bkmrk-property-required-pu"><thead><tr><th>Property</th><th>Required</th><th>Purpose</th></tr></thead><tbody><tr><td>`slots`</td><td>**Yes**</td><td>The ad placements you are requesting</td></tr><tr><td>`parameters`</td><td>No</td><td>Request-level targeting data (page, user, context)</td></tr><tr><td>`user`</td><td>No</td><td>External user IDs for downstream buyers (open market)</td></tr></tbody></table>

### slots

An array of slot objects — one per ad placement needed for the current page or application state. **At least one slot is required.**

Each slot object contains at minimum a `slotname`: the unique identifier of the placement as configured in your Adhese account. Campaigns are targeted against these names.

```json
"slots": [
    { "slotname": "some_slot" },
    { "slotname": "another_slot" }
]

```

<p class="callout warning">⚠️ Each `slotname` may appear only once per request. Duplicates cause the request to be rejected with status `442`.</p>

### parameters

An object of targeting attributes describing the page, user, or context. Keys are **fixed two-character codes** defined in your Adhese account; values are **always arrays of strings**.

All parameters are optional — omit a key entirely, or send an empty array, when there is nothing to pass.

```json
"parameters": {
    "kw": ["cheese", "wine"],
    "mi": ["ABCDEF123456"]
}

```

In this example, `kw` carries search keywords and `mi` a member ID. Reserved parameter codes are listed on [Request target parameters](https://documentation.adhese.org/books/integration-setup/page/request-target-parameters).

### Slot-level parameters

A slot object can carry its own `parameters` property with the same structure. For each slot, request-level and slot-level parameters are **merged**. Use this for attributes that differ per placement, such as position on the page:

```json
"slots": [
    {
        "slotname": "some_slot",
        "parameters": { "ps": ["top"] }
    },
    {
        "slotname": "another_slot",
        "parameters": { "ps": ["bottom"] }
    }
]

```

### user

Reserved for passing identifiers from external ID providers to buyers further down the chain, mainly in an open-market context:

```json
"user": {
    "ext": {
        "eids": []
    }
}

```

If you think you need this, contact [Adhese Support](https://documentation.adhese.org/books/introduction/page/adhese-support) before implementing.

### Complete request example

```json
{
    "slots": [
        { "slotname": "homepage_banner" },
        { "slotname": "homepage_rectangle_top" },
        { "slotname": "homepage_rectangle_bottom" },
        {
            "slotname": "homepage_halfpage",
            "parameters": { "ps": ["right"] }
        }
    ],
    "parameters": {
        "id": ["1234567890ABCD"],
        "ct": ["computers", "laptops"],
        "kw": ["cheese", "wine"]
    }
}

```

Here `id` is a user ID, `ct` product categories, and `kw` search keywords.

## Making a GET request

The GET version of the ad request contains the same information as the POST version, **slot level parameters are however not supported.**

Example request

```html
https://ads-[account].adhese.com/json/sl_sdk_example_-leaderboard/ctsports;soccer?t=244.18664863333106
```

<table border="1" id="bkmrk-section-meaning-deta"><thead><tr><td>Section</td><td>Meaning</td><td>Details</td></tr></thead><tbody><tr><td class="align-left"><sub>https://ads-\[account\].adhese.com</sub></td><td class="align-left"><sub>Ads domain</sub></td><td class="align-left"><sub>The domain is either the default ads domain for your account or a configured first-party domain. More info on first-party domains can be found here.</sub></td></tr><tr><td class="align-left"><sub>/json/</sub></td><td class="align-left"><sub>Endpoint identifier</sub></td><td class="align-left"> </td></tr><tr><td class="align-left"><sub>/sl\[location code\]-\[format code\]/</sub></td><td class="align-left"><sub>Slots</sub></td><td class="align-left"><sub>This section can be added more than once. Each placement starts with the prefix 'sl', followed by the full slot code. </sub></td></tr><tr><td class="align-left"><sub>/ctsports;soccer/</sub>

</td><td class="align-left"><sub>Target(s)</sub></td><td class="align-left"><sub>This section can be added more than once. Each target section starts with its predefined prefix and is followed by either one value or a list of values separated by ';'.</sub></td></tr><tr><td class="align-left"><sub>?t=\[timestamp\]</sub>

</td><td class="align-left"><sub>Timestamp</sub></td><td class="align-left"><sub>A timestamp to avoid caching issues</sub></td></tr></tbody></table>

## Response codes

<table id="bkmrk-code-meaning-details"><thead><tr><th>Code</th><th>Meaning</th><th>Details</th></tr></thead><tbody><tr><td>`200`</td><td>OK</td><td>Body contains an array of ads. If no ads are available, the array is empty — an empty array is a **successful** response, not an error.</td></tr><tr><td>`442`</td><td>Duplicate slots</td><td>One or more `slotname` values appear more than once. Header `x-adhese-bad-request` lists the duplicates.</td></tr><tr><td>`454`</td><td>No slots</td><td>The request body contains no slots. Header `x-adhese-bad-request` contains `slots cannot be empty`.</td></tr><tr><td>`500`</td><td>Internal server error</td><td>If this was a debug request, check the debug log; otherwise contact Adhese Support.</td></tr></tbody></table>

When handling errors programmatically, read the `x-adhese-bad-request` response header for the specific message.

## Response object

A `200` response contains a JSON array with one object per delivered ad. The objects contain many attributes; the complete field reference lives at [General JSON response structure](https://documentation.adhese.org/books/integration-setup/page/general-json-response-structure) *(editor note: previously linked to the GitHub SDK readme — decide on a single canonical reference)*.

For a server-side or custom display integration, these are the attributes you need:

<table id="bkmrk-attribute-descriptio"><thead><tr><th>Attribute</th><th>Description</th></tr></thead><tbody><tr><td>`slotName`</td><td>The slot this ad belongs to. Use it as the key to match responses to the slots in your request when requesting multiple slots at once.</td></tr><tr><td>`tag`</td><td>The ad markup, returned as a string. For display ads this is typically an HTML fragment to insert into the slot's container. For video/audio it is a VAST-compliant XML document; for native ads it is a JSON object (delivered as a string that your application must parse).</td></tr><tr><td>`width`</td><td>Width of the ad container in pixels, required for correct display.</td></tr><tr><td>`height`</td><td>Height of the ad container in pixels, required for correct display.</td></tr><tr><td>`trackedImpressionCounter`</td><td>Unique URL to call when the ad is **added to the page**, even if not yet visible. Registers an IAB *paid impression*. Fire-and-forget: the call can be asynchronous and the response ignored.</td></tr><tr><td>`viewableImpressionCounter`</td><td>Unique URL to call when the ad has been **at least 50% in the viewport for at least one second**. Registers an IAB *viewable impression*. Fire-and-forget.</td></tr><tr><td>`clickTag`</td><td>Unique URL that counts a click and redirects the user to the ad's landing page. Use it as the href wrapping the creative. In applications without links, the URL can be called directly to register the click, ignoring the response.</td></tr></tbody></table>

### Trimmed response example

```json
[
    {
        "slotName": "homepage_banner",
        "adFormat": "714x224",
        "width": "714",
        "height": "224",
        "tag": "<div>…ad markup…</div>",
        "trackedImpressionCounter": "https://ads-{customer}.adhese.com/track/…",
        "viewableImpressionCounter": "https://ads-{customer}.adhese.com/track/…-Adhese_IABview/…",
        "clickTag": "https://ads-{customer}.adhese.com/raylene/…/UR",
        "orderName": "Example Campaign",
        "creativeName": "Example Creative",
        "extension": {
            "mediaType": "banner",
            "prebid": {
                "cpm": { "amount": "13.047", "currency": "EUR" }
            }
        }
    }
]

```

*This example is abbreviated for readability. Responses contain many additional fields — see the full field reference linked above.*

## Rendering and tracking workflow

For each ad in the response, a correct display integration does the following, in order:

1. **Match** the ad to its container using `slotName`.
2. **Render** the `tag` markup inside a container sized by `width` × `height`.
3. **Call** `trackedImpressionCounter` the moment the ad is added to the page.
4. **Observe** viewability (e.g. with an Intersection Observer) and call `viewableImpressionCounter` once the ad has been ≥50% in view for ≥1 second.
5. **Wrap** the creative's landing-page link in the `clickTag` URL so clicks are counted and redirected.

Skipping step 3 or 4 - or executing them at the wrong time - is the most common cause of reporting discrepancies between Adhese and third-party measurement.

## Event tracking

Beyond impressions and clicks, you can register **custom events** (e.g. video quartiles, expansions, interactions) by constructing tracking URLs from the response data.

### Building a custom event tracking URL

```
https://[ad_request_host]/track-[your_event_string]/[response.id]/sl[response.slotID]/II[response.impressionID]

```

- `your_event_string` — a name of your choosing for the event; it will appear in reporting
- `response.id`, `response.slotID`, `response.impressionID` — taken from the ad's response object