Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Experience APIs for API Sections API only API
version: '2.2'
description: API-only mode endpoints, for users who want to use the Experience APIs without using the full Experience OS features. In API-only mode, you are responsible for generating user and session IDs, and for reporting pageviews and events, while still benefiting from Dynamic Yield's personalization capabilities.
servers:
- url: https://dy-api.com/v2
security:
- sec0: []
tags:
- name: API only
description: API-only mode endpoints, for users who want to use the Experience APIs without using the full Experience OS features. In API-only mode, you are responsible for generating user and session IDs, and for reporting pageviews and events, while still benefiting from Dynamic Yield's personalization capabilities.
paths:
/collect/user/engagement (API only):
post:
summary: Reporting Engagement - API site
description: 'Report user engagement (clicks) over a variation or a recommended item.
Select your endpoint from the Base URL dropdown. If you are not sure which server URL you should use, see here.'
operationId: reporting-engagement-2
tags:
- API only
requestBody:
content:
application/json:
schema:
type: object
properties:
user:
properties:
id:
type: string
description: The User ID. In API-site implementations, you are responsible for generating IDs for new users, and persisting them for existing ones.
required:
- id
type: object
session:
properties:
custom:
type: string
description: The Session ID In API-site implementations, the identifier is for you to generate & persist.
required:
- custom
type: object
context:
properties:
device:
properties:
ip:
type: string
description: The client IP address, for IP filtering. If not passed, the IP of the caller is used. *Optional*
default: 54.100.200.255
type: object
type: object
engagements:
type: array
description: One or more engagements with a variation. This is where you report the type of engagement together with a reference to the content or recommendation that the user engaged with. If you wish to report on impression or slot impression, set the implicit impression to false in the choose request (otherwise impression numbers will be doubled in the reports).
items:
properties:
type:
type: string
description: Pass the value *CLICK* or *IMP* (impressions) for API Custom Code Campaigns; pass the value *SLOT_CLICK* for API Recommendations campaigns, pass the value *PN_CLICK* to track click on Reconnect Push Notifications, pass the value *PN_IMP* to track Reconnect Push Notification delivery, pass the value *SLOT_IMP* for QSR Recommendations campaigns only
enum:
- CLICK
- IMP
- SLOT_CLICK
- PN_CLICK
- PN_IMP
- SLOT_IMP
decisionId:
type: string
description: '**Required for reporting CLICK or IMP**: The unique Decision ID as returned from the `choose` endpoint.'
variations:
type: array
description: 'Only required for reporting explicit impressions over Custom Campaigns which return multiple variations on each decision (e.g. a slider)**: an array of multiple variation IDs the user seen.'
default: []
items:
type: integer
format: int32
slotId:
type: string
description: '**Required for reporting a click on an API Recommendations Campaign**: The Slot ID for the specific clicked product as returned from the `choose` endpoint. *Not used for Custom API Campaigns*.'
trackingData:
type: string
required:
- type
type: object
responses:
'204':
description: '204'
content:
application/json:
examples:
Success (no body returned):
value: ' <NO BODY RETURNED>'
'400':
description: '400'
content:
application/json:
examples:
Result:
value: '{}'
schema:
type: object
properties: {}
deprecated: false
x-readme:
code-samples:
- language: javascript
code: "var request = require(\"request\");\n\nvar options = {\n method: 'POST',\n url: 'https://dy-api.com/v2/collect/user/engagement',\n headers: {'content-type': 'application/json', 'dy-api-key': 'your-api-key'},\n body: `{\n \"user\": {\n \"id\": \"myuser123abc\"\n },\n \"session\": {\n \"custom\": \"custsession123\"\n },\n \"context\": {\n \"device\": {\n \"ip\": \"54.100.200.255\"\n }},\n \"engagements\": [\n {\n \"decisionId\": \"l7MxODY3NDc5MDc2Mjg2ODUzMTExe6MyMzShMcCRB84AAWWz\",\n \"type\": \"IMP\"\n },\n\t\t\t{\n \"decisionId\": \"l7MxODY3NDc5MDc2Mjg2ODUzMTExe6MyMzShMcCRB84AAWWz\",\n \"type\": \"CLICK\"\n },\n {\n \"type\": \"SLOT_CLICK\",\n \"slotId\": \"l4SkdHlwZahDQVRFR09SWahsb2NhdGlvbtoAL2h0dHBzOi8vc2hvcC53ZWJzaXRlLmNvbS9tZW4tcGFudHMvcDczODM3MjMtMDEwpGRhdGGQqHJlZmVycmVysHd3dy5yZWZlcnJlci5jb23NLwrNeyvCAKsxMjAxMTIzLTAwNwE=*l7MxODY3NDc5MDc2Mjg2ODUzMjAyzQI3ozIzNKExwJEHzgABZbM=\"\n },\n {\n \"type\": \"SLOT_IMP\",\n \"slotIds\": [\"l4SkdHlwZahDQVRFR09SWahsb2NhdGlvbtoAL2h0dHBzOi8vc2hvcC53ZWJzaXRlLmNvbS9tZW4tcGFudHMvcDczODM3MjMtMDEwpGRhdGGQqHJlZmVycmVysHd3dy5yZWZlcnJlci5jb23NLwrNeyvCAKsxMjAxMTIzLTAwNwE=*l7MxODY3NDc5MDc2Mjg2ODUzMjAyzQI3ozIzNKExwJEHzgABZbM=\"]\n }\n ]}`\n};\n\nrequest(options, function (error, response, body) {\n if (error) throw new Error(error);\n\n console.log(body);\n});"
name: 'API-Only Mode: Engagement request (Node.JS)'
samples-languages:
- javascript
/collect/user/event (API only):
post:
summary: Reporting Events - API site
description: 'Report a predefined or custom event.
Select your endpoint from the Base URL dropdown. If you are not sure which server URL you should use, see here.'
operationId: reporting-events-api-only
tags:
- API only
requestBody:
content:
application/json:
schema:
type: object
required:
- events
properties:
user:
properties:
id:
type: string
description: The User ID.. In API-Only Mode, you are responsible for generating IDs for new users, and persisting them for existing ones.
required:
- id
type: object
session:
properties:
custom:
type: string
description: The Session ID. In API-Only Mode, the identifier is for you to generate & persist.
required:
- custom
type: object
context:
properties:
device:
properties:
ip:
type: string
description: The client IP address, for IP filtering. If not passed, the IP of the caller is used. *Optional*
default: 54.100.200.255
type: object
type: object
events:
type: array
description: One or more events to report
responses:
'204':
description: '204'
content:
application/json:
examples:
Success (no body returned):
value: ' <NO BODY RETURNED>'
deprecated: false
x-readme:
code-samples:
- language: javascript
code: "var request = require(\"request\");\n\nvar options = {\n method: 'POST',\n url: 'https://dy-api.com/v2/collect/user/event',\n headers: {'content-type': 'application/json', 'dy-api-key': 'your-api-key'},\n body: `{\n \"user\": {\n \"id\": \"myuser123abc\"\n },\n \"session\": {\n \"custom\": \"custsession123\"\n },\n \"context\": {\n \"device\": {\n \"ip\": \"54.100.200.255\"\n }},\n \"events\": [{\n \t\"name\": \"myEvent123\",\n \t\"properties\":{}\n }]}`\n};\n\nrequest(options, function (error, response, body) {\n if (error) throw new Error(error);\n\n console.log(body);\n});"
name: 'API-Only Mode: Event request (Node.JS)'
samples-languages:
- javascript
/collect/user/pageview (API only):
post:
summary: Reporting Pageviews - API site
description: 'Report a pageview without choosing variations for any campaigns.
Select your endpoint from the Base URL dropdown. If you are not sure which server URL you should use, see here.'
operationId: reporting-pageviews-api-only
tags:
- API only
requestBody:
content:
application/json:
schema:
type: object
properties:
user:
properties:
id:
type: string
description: The User ID.. In API-Only Mode, you are responsible for generating IDs for new users, and persisting them for existing ones.
required:
- id
type: object
session:
properties:
custom:
type: string
description: The Session ID In API-Only Mode, the identifier is for you to generate & persist.
required:
- custom
type: object
context:
properties:
page:
properties:
type:
type: string
description: Page type, such as HOMEPAGE, CATEGORY, PRODUCT, etc. See Developer Guide for listing.
default: PRODUCT
data:
type: array
description: Additional data related to the page type, such as the product SKU for PRODUCT-type pages. Detailed in the Developer Guide.
default:
- p76311-020
items:
type: string
location:
type: string
description: Page URL (for web), location (for SPAs), or screen name (for mobile apps)
default: https://shop.biz/nice-shirt-p76311.html
referrer:
type: string
description: Page referrer, if available. *Optional*
default: https://google.cz
locale:
type: string
description: Page locale, such as "en_US". *Optional*
default: de_DE
required:
- type
- data
- location
type: object
device:
properties:
userAgent:
type: string
description: For web-based clients, the User-Agent string. If not passed, the API Gateway will check for that header in the HTTPS request. *Optional*
default: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
ip:
type: string
description: The client IP address, for geolocation-based targeting and audience building. If not passed, the IP of the caller is used. *Optional*
default: 54.100.200.255
type: object
type: object
responses:
'204':
description: '204'
content:
text/plain:
examples:
Success (no body returned):
value: <NO BODY RETURNED>
deprecated: false
x-readme:
code-samples:
- language: javascript
code: "var request = require(\"request\");\n\nvar options = {\n method: 'POST',\n url: 'https://dy-api.com/v2/collect/user/pageview',\n headers: {'content-type': 'application/json', 'dy-api-key': 'your-api-key'},\n body: `{\n \"user\": {\n \t\"id\": \"myuser123abc\"\n },\n \"session\": {\n \"custom\": \"custsession123\"\n },\n \"context\": {\n \"page\": {\n \"type\": \"PRODUCT\",\n \"location\": \"https://shop.biz/nice-shirt-p76311.html\",\n \"referrer\": \"https://google.cz\",\n \"locale\": \"de_DE\"\n },\n \"device\": {\n \"userAgent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36\",\n \"ip\": \"54.100.200.255\"\n }\n }}`\n};\n\nrequest(options, function (error, response, body) {\n if (error) throw new Error(error);\n\n console.log(body);\n});"
name: 'API-Only Mode: Pageview request (Node.JS)'
samples-languages:
- javascript
/serve/user/choose (API only):
post:
summary: Choosing Variations - API site
description: 'Get chosen variations for one or more campaigns, either Custom Campaigns or Recommendations. By default also reports a new pageview with the given context.
Select your endpoint from the Base URL dropdown. If you are not sure which server URL you should use, see here.'
operationId: choosing-variations-api-only
tags:
- API only
requestBody:
content:
application/json:
schema:
type: object
properties:
user:
properties:
id:
type: string
description: The User ID. In API-only mode, you are responsible for generating IDs for new users, and persisting them for existing ones.
required:
- id
type: object
session:
properties:
custom:
type: string
description: The Session ID. In API-Only Mode you should generate & persist this ID.
required:
- custom
type: object
selector:
properties:
names:
type: array
description: Array of Dynamic Yield campaign names to choose variations for. Pass the *API Selector Name* of campaigns rather than the display name, which may change by the Admin UI User. Names are case-insensitive, but whitespace-sensitive. An empty list is valid.
default:
- Banner Main
- German Banner
- PDP Recs Tray"
items:
type: string
groups:
type: array
description: All the active campaign selectors in the group are sent back in the response to your CHOOSE call, the definition of the group is done in the Experience OS console.
items:
type: string
preview:
type: object
description: Preview token IDs, as passed by the dyApiPreview URL parameter on preview
properties: {}
required:
- names
type: object
context:
properties:
page:
properties:
type:
type: string
description: Page type, such as HOMEPAGE, CATEGORY, PRODUCT, and so on. See the support site for details.
default: HOMEPAGE
data:
type: array
description: Additional data related to the page type, such as the product SKU for PRODUCT-type pages. **Required only for Category and Product pages**. Do not use for Homepage or other types. See more details on the support site.
items:
type: string
location:
type: string
description: Page URL (for web), location (for SPAs), or screen name (for mobile apps)
default: https://shop.biz/index.html
referrer:
type: string
description: Page referrer, if available. *Optional*
locale:
type: string
description: Page locale, such as "en_US". Should be sent in each request when using the localized content feature. *Optional*
default: en_US
required:
- type
- data
- location
type: object
device:
properties:
userAgent:
type: string
description: For web-based clients, the User-Agent string. If not passed, the API Gateway will check for that header in the HTTPS request. *Optional*
default: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
ip:
type: string
description: The client IP address, for geolocation-based targeting and audience building. If not passed, the IP of the caller is used. *Optional*
default: 54.100.200.255
dateTime:
type: string
description: 'Date & time in ISO 8601 format: YYYY-MM-DDThh:mm:ss.sss±hh:mm (with local time zone). *Optional*.'
type: object
pageAttributes:
type: object
description: A shallow object of custom attributes that can be used for campaign targeting in the Experience OS console. *Optional*
properties: {}
type: object
options:
properties:
isImplicitPageview:
type: boolean
description: 'Whether to report a new pageview with the given context. In API-only Mode this value is *true* by default. Note that if you''re calling `choose` more than once for a page , you should make sure that a pageview is reported only once: Either set this to parameter to *false* in all but one of your `choose` calls, or for a less error-prone approach: always pass *false*, and use the dedicated `pageview` endpoint to report all pageviews.'
default: true
' returnAnalyticsMetadata':
type: boolean
description: Whether to return additional metadata (display names & IDs for all entities) useful for reporting to analytics tools
default: false
recsProductData:
properties:
skusOnly:
type: boolean
description: To reduce the size of the response, you can limit it so that it only includes the SKUs
' fieldFilter':
type: array
description: Specify the fields you need in the recommendation campaign response by using the “fieldFilter” parameter. Simply send an array of strings of the relevant fields, and only those fields and values are sent back.
items:
type: string
type: object
type: object
responses:
'200':
description: '200'
content:
application/json:
examples:
Result:
value: "{\n \"choices\": [\n {\n \"id\": 484687,\n \"name\": \"test1\",\n \"type\": \"DECISION\",\n \"variations\": [\n {\n \"id\": 21831162,\n \"payload\": {\n \"type\": \"CUSTOM_JSON\",\n \"data\": {\n \"hello\": 1\n }\n }\n }\n ],\n \"decisionId\": \"l7QtNjM5NDkxMzUzMDQ1MjE4NjYyMs4ADcQTpzgyODQwMDEBkJHOAU0d+qUzMjc3Mw==\"\n }\n ]\n}"
schema:
type: object
properties:
choices:
type: array
items:
type: object
properties:
id:
type: integer
example: 484687
default: 0
name:
type: string
example: test1
type:
type: string
example: DECISION
variations:
type: array
items:
type: object
properties:
id:
type: integer
example: 21831162
default: 0
payload:
type: object
properties:
type:
type: string
example: CUSTOM_JSON
data:
type: object
properties:
hello:
type: integer
example: 1
default: 0
decisionId:
type: string
example: l7QtNjM5NDkxMzUzMDQ1MjE4NjYyMs4ADcQTpzgyODQwMDEBkJHOAU0d+qUzMjc3Mw==
'400':
description: '400'
content:
application/json:
examples:
Result:
value: '{}'
schema:
type: object
properties: {}
deprecated: false
x-readme:
code-samples:
- language: javascript
code: "var request = require(\"request\");\n\nvar options = {\n method: 'POST',\n url: 'https://dy-api.com/v2/serve/user/choose',\n headers: {'content-type': 'application/json', 'dy-api-key': 'your-api-key'},\n body: `{\n \"selector\": {\n \"names\": [\n \"test1\"\n ]\n },\n \"user\": {\n \"id\": \"customUserId123\"\n },\n \"session\": {\n \"custom\": \"myCustomSession345\"\n },\n \"context\": {\n \"page\": {\n \"type\": \"HOMEPAGE\",\n \"location\": \"https://example.org\",\n \"locale\": \"en_US\",\n \"data\":[]\n },\n \"device\": {\n \"userAgent\": \"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36\",\n \"ip\": \"54.100.200.255\"\n }\n },\n \"options\": {\n \"isImplicitPageview\": false,\n \" returnAnalyticsMetadata\": false\n }}`\n};\n\nrequest(options, function (error, response, body) {\n if (error) throw new Error(error);\n\n console.log(body);\n});\n\n"
name: API-only example (Node.JS)
- language: javascript
code: "func postActiona() {\n let data = [\n \"user\": [\n \"id\": \"yaeaaa477y723hania\"\n ],\n \"session\": [\n \"custom\": \"iqudddcd4gff2fashe2koh\"\n ],\n \"selector\": [\n \"names\": [\n \"PDP Top Banner\",\n \"PDP Recs\"\n ]\n ],\n \"context\": [\n \"page\": [\n \"type\": \"PRODUCT\",\n \"data\": [\"7383723-010\"],\n \"location\": \"https://sugoi-ne.com/men-pants/p7383723-010\",\n \"referrer\": \"https://sugoi-ne.com/men-pants\",\n \"locale\": \"en_US\"\n ],\n \"device\": [\n \"userAgent\": \"Mozilla/5.0 (iPhone; CPU iPhone OS 13_3 like Mac OS X)\",\n \"ip\": \"54.100.200.255\"\n ],\n \"pageAttributes\": [\n \"customPageAttribute\": \"someValue\"\n ]\n ],\n \"options\": [\n \"isImplicitPageview\": true\n ]\n ];\n let serviceUrl = URL(string: \"https://dy-api.com/v2/serve/user/choose\")!\n var request = URLRequest(url: serviceUrl)\n request.httpMethod = \"POST\"\n request.setValue(\"Application/json\", forHTTPHeaderField: \"Content-Type\")\n request.setValue(\"69891577675178c7f8ce0767ded46402f9a97fa7fad1bae5d340e6d9673a9d1f\", forHTTPHeaderField: \"DY-API-Key\")\n guard let httpBody = try? JSONSerialization.data(withJSONObject: data, options: []) else {\n return\n }\n request.httpBody = httpBody\n let session = URLSession.shared\n session.dataTask(with: request) { (data, response, error) in\n if let data = data {\n do {\n let json = try JSONSerialization.jsonObject(with: data, options: [])\n print(json)\n } catch {\n print(error)\n }\n }\n }.resume()\n }"
name: iOS API-only example
- language: javascript
code: "suspend fun sendPostRequest() = withContext(Dispatchers.IO) {\n val data = \"{\" +\n \" \\\"user\\\": {\" +\n \" \\\"id\\\": \\\"yaeaaa477y723hania\\\"\" +\n \" },\" +\n \" \\\"session\\\": {\" +\n \" \\\"custom\\\": \\\"iqudddcd4gff2fashe2koh\\\"\" +\n \" },\" +\n \" \\\"selector\\\": {\" +\n \" \\\"names\\\": [\" +\n \" \\\"PDP Top Banner\\\",\" +\n \" \\\"PDP Recs\\\"\" +\n \" ]\" +\n \" },\" +\n \" \\\"context\\\": {\" +\n \" \\\"page\\\": {\" +\n \" \\\"type\\\": \\\"HOMEPAGE\\\",\" +\n \" \\\"data\\\": [],\" +\n \" \\\"location\\\": \\\"https://sugoi-ne.com/men-pants/p7383723-010\\\",\" +\n \" \\\"referrer\\\": \\\"https://sugoi-ne.com/men-pants\\\",\" +\n \" \\\"locale\\\": \\\"en_US\\\"\" +\n \" },\" +\n \" \\\"device\\\": {\" +\n \" \\\"userAgent\\\": \\\"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36\\\",\" +\n \" \\\"ip\\\": \\\"54.100.200.255\\\"\" +\n \" },\" +\n \" \\\"pageAttributes\\\": {\" +\n \" \\\"customPageAttribute\\\": \\\"someValue\\\"\" +\n \" }\" +\n \" },\" +\n \" \\\"options\\\": {\" +\n \" \\\"isImplicitPageview\\\": true\" +\n \" }\" +\n \"}\"\n\n val mURL = URL(\"https://dy-api.com/v2/serve/user/choose\")\n\n with(mURL.openConnection() as HttpURLConnection) {\n requestMethod = \"POST\"\n setRequestProperty(\"Content-Type\", \"application/json; charset=utf-8\")\n setRequestProperty(\"DY-API-Key\", \"69891577675178c7f8ce0767ded46402f9a97fa7fad1bae5d340e6d9673a9d1f\")\n\n doOutput = true\n val outputWriter = OutputStreamWriter(outputStream)\n outputWriter.write(data)\n outputWriter.flush()\n\n println(\"URL : $url\")\n println(\"Response Code : $responseCode\")\n\n BufferedReader(InputStreamReader(inputStream)).use {\n val response = StringBuffer()\n\n var inputLine = it.readLine()\n while (inputLine != null) {\n response.append(inputLine)\n inputLine = it.readLine()\n }\n println(\"Response : $response\")\n }\n }\n}"
name: Android API-only example
samples-languages:
- javascript
components:
securitySchemes:
sec0:
type: apiKey
in: header
name: DY-API-Key
x-default: your-api-key
x-provenance:
method: searched
source: https://dy.dev/reference
harvested: '2026-10-14'
tool: harvest-readme-openapi.py
note: Assembled verbatim from the OpenAPI definition ReadMe embeds in each operation page of the provider's developer portal; paths and components merged by API title, nothing authored.
assembled_from:
- https://dy.dev/reference/choosing-variations-api-only.md
- https://dy.dev/reference/reporting-engagement-2.md
- https://dy.dev/reference/reporting-events-api-only.md
- https://dy.dev/reference/reporting-pageviews-api-only.md
merge:
pages: 4
deduped: 3
conflicts_kept_first: 0