> Synerise Documentation — API > > This file contains the complete "API" section of the Synerise documentation. Each article begins with a top-level "# " heading. The manifest listing all sections is at https://hub.synerise.com/llms-full.txt # Introduction to Synerise API ## Introduction Synerise RESTful APIs are a quick and simple way to integrate your existing or future systems with Synerise or benefit from functionalities available within your applications. ### SSL Synerise API requires connectivity over HTTPS (SSL) and supports the TLS 1.2 protocol (support for newer versions to be added in the near future).
On older configurations, an update may be required, including the update of CA certificate repository.
### Servers When working with the Synerise API, make sure you're using the correct base URL, depending on the cloud where your workspace is hosted: - `https://api.synerise.com` for Microsoft Azure EU environment - `https://api.azu.synerise.com` for Microsoft Azure USA environment - `https://api.geb.synerise.com` for Google Cloud Platform environment ### API Versioning Synerise is built with CI/CD (Continuous Integration/Continuous Delivery) principles in mind and we often deploy changes multiple times a day. We do not have fixed release cycles, but instead features are brought live for you as soon as they are ready. Such an approach allows us to deliver features, changes, and bug fixes very fast and keeping track of them is possible thanks to our [live changelog](https://changelog.synerise.com). Thus, as part of our API Contract, we want to ensure that within an API Version: 1. No fields will be deleted or changed in a non-backwards compatible way. 2. We make changes that are additional, such as new fields, new methods, new error messages/codes, or mandatory parameters becoming optional (but, generally speaking, not causing compatibility issues). Whenever we may need to roll out elements that are not backwards compatible, we will do that as a new API version for the given functional area, so an endpoint that was version 1 is now also available as version 2, with the previous one still being operational. ### Deprecation Endpoints that already have newer versions send `X-API-DEPRECATED` in the response Headers, giving you time to switch to the new endpoint. Deprecated API endpoints are also marked visually in the API reference pages. # Introduction to API Authorization Synerise uses a number of authentication methods in the API. The available methods depend on the endpoint and the consumer. JSON Web Tokens (JWTs) are the most common. ## API consumer types Synerise defines different types of API consumers that can receive their own authorization tokens. Each method within our API Reference indicates which types of API Consumers can use them. ### Profile This is the end user of your website or application - the one who browses pages, purchases items, and so on. In the portal, this is called a profile. In our APIs, the profile is usually called a "client" in endpoint URLs and JSON entity names. The profile can register and maintain their own account with following methods: - Synerise RaaS - Facebook authentication - OAuth-based authorization - Sign in with Apple They can also perform other customer actions, such as redeeming vouchers.
The profile can access and modify only its own data.
### Workspace The workspace is assigned to a particular company as explained [in these articles](/docs/settings/workspace). This consumer can use methods that, for example, create profiles, record profile actions, or manage promotions. When working with the API, you will usually authorize as the workspace. ### User This is the user who logs in to [the Synerise Portal](https://app.synerise.com/). A User is an actual person who performs actions in the Synerise Portal interface, but many of those actions can be automated using the API. Users have access to *Workspaces* or *Organizations* and different levels of permissions within those.
Workspaces used to be called _business profiles_. Many endpoints still use this nomenclature due to backwards compatibility.
## Access control ### Access permissions Each endpoint requires a permission to access it. These permissions can be defined granularly for users, roles, or API keys, so you have strict control over access to each endpoint. You can also assign groups of permissions. To find which permission is needed for an endpoint, read the endpoint's description in the [API Reference](https://hub.synerise.com/api-reference). For more information on managing permissions, read [this article](/docs/settings/identity-access-management/permissions). ### IP allowlisting You can limit access to Synerise to certain IP addresses. For more information, see [IP access control](/developers/api/api-authorization/ip-access). ## JSON Web Tokens Authentication with [JSON Web Tokens (JWTs)](https://jwt.io/) is available in most of the API endpoints. The token is generated by one of the `/auth/login/` endpoints depending on the **Consumer Type**, as described further in this article. You need to include the received token in the `Authorization` header of your requests, with a `Bearer` prefix. See this simplified example of a call: ```bash curl -X GET https://{SYNERISE_API_BASE_PATH}/v4/clients \ -H 'Accept: application/json' \ -H 'Api-Version: 4.4' \ -H 'Authorization: Bearer eyJhbGciOiJSzZXIiL...UFBQUFBSXVPQlFBcHUwd05BZ0FBQUE9PSIsIm5tZSI' \ -H 'Content-Type: application/json' ```
Remember to include a space between `Bearer` and the token.
If you are unauthorized or are using an invalid/expired token, the API returns `HTTP 401 Unauthorized` or `HTTP 403 Forbidden`. ### Token format Our JWT use the `RS512` hashing algorithm and their payload contains: - customer/user/profile identification. - the origin of the token (Synerise, Facebook, Oauth, Apple). - expiration time of the token. - **user tokens only:** information about the currently selected workspace and user permissions. ### Token lifetime By default, the token is valid for **one week**. You can request a refreshed token for the session by using the `/auth/refresh` endpoint **before** the current token expires. You can also verify your JWT signature by using the public key: - [Workspaces hosted on Microsoft Azure EU server](https://api.synerise.com/v4/public.pem) - [Workspaces hosted on Microsoft Azure USA server](https://api.azu.synerise.com/v4/public.pem) - [Workspaces hosted on Google Cloud Platform](https://api.geb.synerise.com/v4/public.pem) # Customer profiles
**Upcoming breaking change (effective July 6, 2026):** Synerise is introducing changes to how user identifiers and UUIDs are handled. These changes may affect profiles with accented or diacritical characters in identifiers, profiles with leading or trailing whitespace in identifiers, and profiles with duplicate UUIDs. For details and recommended actions, see [Upcoming changes to handling identifiers](/docs/settings/configuration/identifier-standardization).
When a customer interacts with your content for the first time, you can create a profile in the database. This profile may only be identified by an ID - such a profile is *anonymous* (has no personal data). If a user provides their email, for example by signing up to a newsletter, they are *recognized*. A profile is also created when a customer [registers an account](/developers/api/clients/registration). If a customer profile with the same email already exists at the time of registration, the created account becomes connected to that profile and the data is merged. The endpoints described in this article operate on profiles regardless of those profiles' relation to registered accounts. ## Creating profiles Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/CreateAClientInCrm). The minimum data required to create a customer profile is one of the following identifiers: - `email` - `phone` - `uuid` - `customId` For additional fields that you can send, see the reference documentation.
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/v4/clients' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJh...8MltQ' \
--data-raw '{
   "email": "sampleclient@synerise.com"
}'
**Result:** The response is HTTP 202 with no content. A profile is created, some properties are generated automatically or receive placeholders. See the response in [Retrieving a single profile](#retrieving-a-single-profile). ## Retrieving a single profile Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/FindAClient). You can retrieve a single profile from the database by providing one of the following identifiers: - `email` - `phone` - `uuid` - `customId` The following request retrieves the data of the customer created in [Creating a customer profile](#creating-profiles):
curl --location --request \
GET 'https://{SYNERISE_API_BASE_PATH}/v4/clients/by-email/sampleclient@synerise.com' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJhb...hjM' \
The response is the customer data. During profile creation, the **only** provided property was the email (see curl example in [Creating profiles](#creating-profiles) - the other properties are generated automatically or receive placeholder values.
{
    "previousClients": [],
    "clientId": 2149203825,
    "email": "sampleclient@synerise.com",
    "phone": null,
    "customId": null,
    "uuid": "24f539a0-d257-11ea-92f0-23c0f0aec77f",
    "firstName": "Sampleclient",
    "lastName": null,
    "displayName": null,
    "company": null,
    "address": null,
    "city": null,
    "province": null,
    "zipCode": null,
    "countryCode": null,
    "birthDate": null,
    "lastActivityDate": "2020-07-30T11:23:51Z",
    "sex": "NOT_SPECIFIED",
    "avatarUrl": "https://www.gravatar.com/avatar/2b13fb10fcb2ff3327a41c3c5dd3d2cd?s=100&r=g&d=blank",
    "anonymous": false,
    "agreements": {
        "email": false,
        "sms": false,
        "push": false,
        "webPush": false,
        "bluetooth": false,
        "rfid": false,
        "wifi": false
    },
    "attributes": {
        "eventCreateTime": "2020-07-30T11:23:46.092Z",
        "correlationId": "D57HkYUzRRu2ImZmjNg-Iw"
    },
    "tags": []
}
## Listing profiles Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/ListClients). This method allows you to list customer profiles from the database. The results can be filtered (see method reference). **The maximum number of retrieved entries is 10 000.**
curl --location --request \
GET 'https://{SYNERISE_API_BASE_PATH}/crm/v1/list' \
--header 'Authorization: Bearer eyJh...8MltQ' \
The response is a list of profiles. ## Updating profiles Method reference available: - [Identification by ID](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/UpdateAClient) - [Identification by email](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/UpdateAClientByEmail). If you use the [non-unique emails feature](/docs/settings/configuration/non-unique-emails), identification by email is not recommended. - [Identification by customId](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/UpdateAClientByCustomId) You can update the customer profile. When sending the request, include only the fields that you want to update. Sending a null value deletes an attribute (if it's a custom attribute) or sets it to null/default value (if the attribute is Synerise-native). Empty strings are not accepted. The following example updates the customer's name and surname:
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/v4/clients/by-email/sampleclient@synerise.com' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJhb...Jes' \
--data-raw '{
    "firstName": "John",
    "lastName": "Smith"
}'
**Result:** The response is HTTP 202 with no content. The profile data is updated. ## Deleting profiles Method reference available: - [Identification by ID](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/DeleteAClient) - [Identification by customId](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/DeleteAClientByCustomId) You can delete a profile.
curl --location --request \
DELETE 'https://{SYNERISE_API_BASE_PATH}/v4/clients/2149203825' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJhbG...DVDg2Udg' \
**Result:** The response is HTTP 202 with no content. The profile is deleted. ## Creating/updating multiple profiles Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/BatchAddOrUpdateClients). Customer profiles can be added or updated in batch. When you perform this operation, existing profiles are updated, and data that does not match any profiles results in creating new profiles. When sending the request, include only the fields that you want to update. Sending a null value deletes an attribute (if it's a custom attribute) or sets it to null/default value (if the attribute is Synerise-native). Empty strings are not accepted. The following request creates two new profiles and updates the `firstName` field of the customer created in [Creating profiles](#creating-profiles):
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/v4/clients/batch' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJhb...EGRXjc' \
--data-raw '[
   {
      "email": "newclient@synerise.com"
   },
   {
      "customId": "newClientCustomId"
   },
   {
      "email": "sampleclient@synerise.com",
      "firstName": "Michael"
   }
]'
**Result:** The response is HTTP 202 with co content. The operation is queued.
Completing a batch operation may take some time, depending on request size and server load.
# Merging profiles with the API
**Upcoming breaking change (effective July 6, 2026):** Synerise is introducing changes to how user identifiers and UUIDs are handled. These changes may affect profiles with accented or diacritical characters in identifiers, profiles with leading or trailing whitespace in identifiers, and profiles with duplicate UUIDs. For details and recommended actions, see [Upcoming changes to handling identifiers](/docs/settings/configuration/identifier-standardization).
This article describes the endpoints that force merging profiles. For other situations where profiles are merged, see the [User Guide](/docs/crm/merge).
Sometimes, multiple profiles refer to the same customer. In that case, they need to be merged. In such cases, a number of _source_ profiles are merged into a _target_ profile. The source profiles are deleted after merging. After the merge is complete, a [client.merge](/docs/assets/events/event-reference/profiles#clientmerge) event is saved to the target profile. With the endpoints described below, you can force a merge. This can be used to: - merge recognized profiles. In this case, the identifiers (such as email or customId) of the source profiles are lost, as described in ["Properties, tags, and attributes"](#properties-tags-and-attributes). - merge a recognized profile into an anonymous one. In this case, the target profile remains anonymous.
- This operation is **irreversible**. Use it carefully. - The source profiles are **deleted**. - Don't merge more than 20 accounts at once.
## Identities and event history UUIDs (including historical UUIDs) of the source profiles are added to the historical UUIDs of the target profile. Thanks to this, events of source profiles become associated with the target profile.
Moving identities and events when merging
Moving identities and events when merging
The identities (UUIDs) can be found on the profile's card:
Location of the Identities list on a profile's card
Location of the Identities list on a profile's card.
## Properties, tags, and attributes _Properties_ are the data stored **outside of the `attributes` object** of a profile's data: `clientId, email, phone, customId, uuid, firstName, lastName, displayName, company, address, city, province, zipCode, countryCode, birthDate, sex, avatarUrl, anonymous, agreements (object), tags (list)` _Attributes_ are the data stored in the `attributes` object. **When [non-unique emails](/docs/settings/configuration/non-unique-emails) are enabled, the profile's email and marketing agreement are attributes!** To see the properties and attributes of a profile, fetch its data with [`/v4/clients`](https://hub.synerise.com/api-reference/profile-management#operation/GetClientData). When profiles are merged: - All properties (including tags) of the source profiles are ignored and lost. - If an attribute already exists in the target profile, it's not modified. In this case, attribute values from the source profiles are lost. - If an attribute from a source profile doesn't exist in the target profile, it's copied into the target profile.
Moving data when merging
Moving data when merging
## Merging with customId
- This operation is **irreversible**. Use it carefully. - The source profiles are **deleted**. - Don't merge more than 20 accounts at once.
The following request merges profiles `lue42` and `mjz84` into a third profile: `tla114`.
curl --location --request POST \
'https://{SYNERISE_API_BASE_PATH}/v4/clients/merge/from/custom-ids/lue42,mjz84/to/custom-id/tla114' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJh...ey4'
For more details, see the [API reference](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/MergeClientsByCustomId). ## Merging with clientId
- This operation is **irreversible**. Use it carefully. - The source profiles are **deleted**. - Don't merge more than 20 accounts at once.
The following request merges profiles `123` and `456` into a third profile: `789`.
curl --location --request POST \
'https://{SYNERISE_API_BASE_PATH}/v4/clients/merge/from/ids/123,456/to/id/789' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJh...ey4'
For more details, see the [API reference](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/MergeClientsByClientId). # Recommendation API requests You can make requests for: - results of a [campaign created in the Synerise Portal](/docs/ai-hub/recommendations-v2/creating-recommendation-campaign). With this option, you can create a campaign with filters instead of defining them for each request. You can still tweak filters when making the request. This is the most commonly used method. - recommendations served [by a recommendation model](#requests-to-a-model) without creating a campaign. With this option, you can make requests without preparing a campaign first, but you need to send the settings that are normally part of the campaign. ## Before you begin - Ensure that the model for the type of recommendations you want to request is enabled in the [settings of an item feed](/docs/settings/configuration/ai-engine-configuration/engine-configuration-for-recommendations#selecting-recommendation-types-and-default-filters). - You should be familiar with recommendation types and filter types: - [Recommendation types](/docs/ai-hub/recommendations-v2/recommendation-types) - [Recommendation filter types](/docs/ai-hub/recommendations-v2/recommendation-filters#filter-types) ## Elements of the request ### Context Each recommendation is made in context of a Profile. The profile's attributes can be used in filters.
When making requests from a website, you can find the profile's UUID in the `_snrs_uuid` cookie.
You can also add item context to your requests, for example when generating complementary purchase recommendations for a product. The context item's attributes can be used in filters. In some recommendations, the item context is required. When it's not required, it can still be included in order to use the context item's attributes in filters. ### Address The domain of the recommendations API depends on your workspace. - `https://api.synerise.com` for Microsoft Azure EU environment - `https://api.azu.synerise.com` for Microsoft Azure USA environment - `https://api.geb.synerise.com` for Google Cloud Platform environment - If you have a [custom tracking domain](/developers/web/first-party-tracking) configured, use the custom domain (only for requests made from sites which have a [Tracking Code](/developers/web/installation-and-configuration)).
With the custom tracking domain, you must [add `/ai` before the endpoint path in addition to changing the domain](/developers/web/first-party-tracking#updating-your-synerise-api-requests).
### Authentication The requests can be authenticated in the following ways: - **Recommended method**: With the key from your [tracking code](/developers/web/installation-and-configuration). This tracker key is added to the request in the `token` query parameter. This method is used in most examples in this guide. - [With a Workspace JWT (Bearer auth) or Basic authentication](/developers/api/api-authorization/workspace-login).
Workspace JWTs and Basic Authentication can be used ONLY FOR SERVER-TO-SERVER communication. DO NOT use them in your mobile applications or websites.
The following examples show the two methods of authentication.
This is the recommended method. The tracker key is included in the `token` parameter.
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns/DkhvrZoTKthD?token=98A5FC55-0000-0000-0000-98339BDECAE6&clientUUID=cf9e9b57-7776-51bc-b7bc-75cc75abdf59'
                                                                                              <-------------- tracker key ------------->
where: - `DkhvrZoTKthD` is an example campaign ID. You can also refer to a campaign by its slug. - `98A5FC55-0000-0000-0000-98339BDECAE6` is an example tracker key. - `cf9e9b57-7776-51bc-b7bc-75cc75abdf59` is an example profile UUID.
The JWT is included in the `Authorization` header.
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns/DkhvrZoTKthD?clientUUID=cf9e9b57-7776-51bc-b7bc-75cc75abdf59' \
--header 'Authorization: Bearer eyJhbGciOiJSUzUx.edWIiOiIyYzU2Yjk5NmR...g7ToscgR9au6fQDhbs'
where: - `DkhvrZoTKthD` is an example campaign ID. You can also refer to a campaign by its slug. - `cf9e9b57-7776-51bc-b7bc-75cc75abdf59` is an example profile UUID.
## Making a request ### Campaign results You can use two HTTP methods: - GET: elements of the query are passed as query parameters. This method is recommended for making requests from a website. - POST: elements of the query are passed in the request body.
For details of all the parameters available for these endpoints, see the API Reference: - [GET](https://hub.synerise.com/api-reference/ai-recommendations#operation/GetRecommendationsByCampaignV2) - [POST](https://hub.synerise.com/api-reference/ai-recommendations#operation/PostRecommendationsByCampaignV2)
**Examples**:
In GET requests, the item context is sent in the `itemId` attribute. In campaigns which accept multiple items in the context (cart recommendations), send the attribute multiple times. See example:
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns/DkhvrZoTKthD?itemId=0196499479257&itemId=0000301448594&itemId=0000301826378&token=98A5FC55-0000-0000-0000-98339BDECAE6&clientUUID=cf9e9b57-7776-51bc-b7bc-75cc75abdf59'
where: - `DkhvrZoTKthD` is an example campaign ID. You can also refer to a campaign by its slug. - `itemId=0196499479257&itemId=0000301448594&itemId=0000301826378` are 3 example items for context. The `itemId` parameter must be sent multiple times to include multiple items. If the campaign doesn't require an item context and you don't want to use it in filters, skip the `itemId` parameter entirely. - `98A5FC55-0000-0000-0000-98339BDECAE6` is an example tracker key. - `cf9e9b57-7776-51bc-b7bc-75cc75abdf59` is an example profile UUID.
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns?token=98A5FC55-0000-0000-0000-98339BDECAE6' \
--header 'Content-Type: application/json' \
--data '{
    "clientUUID": "cf9e9b57-7776-51bc-b7bc-75cc75abdf59",
    "campaignId": "DkhvrZoTKthD"
}'
where: - `DkhvrZoTKthD` is an example campaign ID. You can also refer to a campaign by its slug. - `98A5FC55-0000-0000-0000-98339BDECAE6` is an example tracker key. - `cf9e9b57-7776-51bc-b7bc-75cc75abdf59` is an example profile UUID.
This example shows an XHR request with error handling.
var xhr = new XMLHttpRequest();

// Add an event listener for 'readystatechange' to handle the response
xhr.addEventListener("readystatechange", function() {
  if(this.readyState === XMLHttpRequest.DONE) {
    if (this.status >= 200 && this.status < 300) {
      // Successful response
      console.log(this.responseText);
    } else {
      // Handle errors
      console.error('Request failed with status:', this.status, 'and response:', this.responseText);
    }
  }
});

// Open a GET request
xhr.open("GET", "https://api.synerise.com/recommendations/v2/recommend/campaigns/DkhvrZoTKthD?token=98A5FC55-0000-0000-0000-98339BDECAE6&clientUUID=cf9e9b57-7776-51bc-b7bc-75cc75abdf59", true);

// Send the request
xhr.send();
where: - `DkhvrZoTKthD` is an example campaign ID. You can also refer to a campaign by its slug. - `98A5FC55-0000-0000-0000-98339BDECAE6` is an example tracker key. - `cf9e9b57-7776-51bc-b7bc-75cc75abdf59` is an example profile UUID.
### Requests to a model Instead of getting the results of a recommendation campaign, you can make ad-hoc requests to recommendation models. In this case, each model has separate endpoints (see [API Reference](https://hub.synerise.com/api-reference/ai-recommendations#tag/Recommendations) for a list).
- In these requests, you can pass a `campaignId` parameter. This parameter is added as `utm_campaign` to the links in the recommendation response for use in Decision Hub. It doesn't need to point to any existing recommendation campaign. - Some recommendation types require additional information, for example the "Recent interactions" model needs an aggregate that defines the interactions to take into account. For details, see the API reference of a particular recommendation type.
**Examples**:
This request fetches a personalized recommendation without any item context or filters.
curl --location 'https://api.synerise.com/recommendations/v2/recommend/items/users/cf9e9b57-7776-51bc-b7bc-75cc75abdf59?token=98A5FC55-0000-0000-0000-98339BDECAE6'
where: - `cf9e9b57-7776-51bc-b7bc-75cc75abdf59` is an example profile UUID - `98A5FC55-0000-0000-0000-98339BDECAE6` is an example tracker key For more details, see [API Reference](https://hub.synerise.com/api-reference/ai-recommendations#operation/RecommendForUserV2)
This request fetches a recommendation of complementary items for a cart. It lists two items (items in the cart) as the context and explicitly declares the catalog (if not declared, the catalog name is `default`)
curl --location 'https://api.synerise.com/recommendations/v2/recommend/items/complementary?clientUuid=cf9e9b57-7776-51bc-b7bc-75cc75abdf59&itemId=0000300395769&itemId=0000323544569&itemCatalogId=shoestore&token=98A5FC55-0000-0000-0000-98339BDECAE6&'
where: - `cf9e9b57-7776-51bc-b7bc-75cc75abdf59` is an example profile UUID - `itemId=0000300395769&itemId=0000323544569` are 2 example items for context (items in the cart) The `itemId` parameter must be sent multiple times to include multiple items. - `shoestore` is an example item catalog ID If the `itemCatalogId` parameter isn't included, it defaults to `default` - `98A5FC55-0000-0000-0000-98339BDECAE6` is an example tracker key For more details, see [API Reference](https://hub.synerise.com/api-reference/ai-recommendations#operation/ComplementItems)
## Learn more A comprehensive list of all endpoints, settings, and parameters is available in the [API Reference](https://hub.synerise.com/api-reference/ai-recommendations#tag/Recommendations). # Authorization Synerise uses [JSON Web Token (JWT)](https://jwt.io/) as the authorization method in most of the API endpoints (some may require only the API key or no authorization at all). # Profile authentication When authenticating as a profile, the following methods may be available (depending on the endpoint you're trying to access): - [Generating a JSON Web Token (JWT)](#jwt-authentication). For this you need a [profile API key](/docs/settings/tool/api). - [Using the tracker key from the tracking script](#tracker-key-authentication). - ~~Inserting an API key into the request headers.~~ - this is a legacy method which should not be used in new integrations. ## JWT authentication These methods of authentication generate a JWT, which is then added to the headers of API requests.
- Keep the API keys secret. A leaked key must be deactivated **immediately**! - When [creating the API key](/docs/settings/tool/api#adding-api-keys), you can use [allowlisting](/docs/settings/tool/api#allowlist) or [denylisting](/docs/settings/tool/api#denylist) to only allow the events you intend to use.
### Authenticating as a recognized customer You can use the following endpoints to authenticate as a customer: - [Registers an account (unless the account already exists) when logging in using Facebook, Google, Sign in with Apple, or OAuth](https://hub.synerise.com/api-reference/identity-and-access-management#operation/authenticateUsingPOST_v3) - [Does not register an account](https://hub.synerise.com/api-reference/identity-and-access-management#operation/authenticateConditionalUsingPOSTv3) Both endpoints accept the same payload. If you use Synerise RaaS authentication, none of the endpoints above can be used to register an account. See [Customer registration](/developers/api/clients/registration). #### Example: Synerise RaaS authentication The example includes only the fields that are required.
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/v3/auth/login/client 
  --header 'content-type: application/json' 
  --data '{
      "apiKey": "1c586ac4-cb47-4c45-a7cf-e0fb74e8e5f4",
      "identityProvider": "SYNERISE",
      "password": "Pass1!",
      "uuid": "5f89a52f-e526-4c7d-a50c-3f5c744d3162",
  }'
The response is a JSON Web Token (JWT) that must be included in the `Authorization` header of further requests. By default, the token is valid for 60 minutes. #### Example: Facebook authentication, no registration if account does not exist The example includes only the fields that are required.
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/v3/auth/login/client/conditional 
  --header 'content-type: application/json' 
  --data '{
      "apiKey": "1c586ac4-cb47-4c45-a7cf-e0fb74e8e5f4",
      "identityProvider": "FACEBOOK",
      "identityProviderToken": "EAAfsMmaWLW0BAJZC3BWUZBi0izUcN9YntYLOZCtTkoPDrkcugIubbwrcXPPUPGKR6q4rdJdaK1sgNg4ARxVBQfUab8hafhPc2sXafL4wHVpS5mnEqrFTKbSHqj3ZBjX6HzMXXZA6qYnfNlzOQvjCEabjqgUdNQE6SrtPNQ7s7gZAOzFP3Ad1QB5vqxb276JM9yhBjVRp5SCdwZDZD"
  }'
The response is a JSON Web Token (JWT) that must be included in the `Authorization` header of further requests. By default, the token is valid for 60 minutes. ### Authenticating as an anonymous customer You can find the method under the ["Authenticate Anonymously" section in the API reference](https://hub.synerise.com/api-reference/identity-and-access-management#operation/LogInAnonymouslyV3). You can generate a JWT for a customer who does not have an account.
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/v3/auth/login/client/anonymous 
  --header 'content-type: application/json' 
  --data '{
    "apiKey":"1c586ac4-cb47-4c45-a7cf-e0fb74e8e5f4",
    "deviceId":"b8af0626-d5cf-44d6-b12a-ec72f946db6f",
    "uuid":"07243772-008a-42e1-ba37-c3807cebde8f"
  }'
The response is a JSON Web Token (JWT) that must be included in the `Authorization` header of further requests. By default, the token is valid for 60 minutes. ### Refreshing JWT You can find the method under the ["Refresh a Profile token" section in the API reference](https://hub.synerise.com/api-reference/identity-and-access-management#operation/RefreshAClientTokenV3). When the token is about to expire, you can obtain a new one without logging in again. This is not possible if the token has already expired.
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/v3/auth/refresh/client 
  --header 'Authorization: Bearer _YOUR_JWT_TOKEN_' 
  --header 'content-type: application/json' 
  --data '{
    "apiKey":"1c586ac4-cb47-4c45-a7cf-e0fb74e8e5f4"
    }'
The response is a new token. ## Tracker key authentication This method is available for some endpoints that relate to the AI engine, such as search and recommendation endpoints. The tracker key is the same as in the [tracking code](/developers/web/installation-and-configuration#creating-a-tracking-code) of your website and is included in the `token` query parameter of a request. If needed, you can generate a new tracking code to have a separate authentication key for API requests made by your website. Example:
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns/DkhvrZoTKthD?token=98A5FC55-0000-0000-0000-98339BDECAE6&clientUUID=cf9e9b57-7776-51bc-b7bc-75cc75abdf59'
                                                                                              <-------------- tracker key ------------->
where: - `DkhvrZoTKthD` is an example campaign ID. - `98A5FC55-0000-0000-0000-98339BDECAE6` is an example tracker key. - `cf9e9b57-7776-51bc-b7bc-75cc75abdf59` is an example profile UUID. Example endpoint: [GET personalized recommendations](https://hub.synerise.com/api-reference/ai-recommendations#tag/Recommendations/operation/RecommendForUserV2) # API ## Synerise API In this section, the cURL examples use a `{SYNERISE_API_BASE_PATH}` variable in the endpoint URLs. This value depends on where your instance of Synerise is hosted: - `https://api.synerise.com` for Microsoft Azure EU environment - `https://api.azu.synerise.com` for Microsoft Azure USA environment - `https://api.geb.synerise.com` for Google Cloud Platform environment # Customer registration Customers can create accounts that let them authorize and perform operations such as redeeming coupons, making purchases, managing their own data, and more. The data is available for you to see and modify in the customer's profile; the primary unique identifier in Synerise is the email address (unless configured differently, see [Identifiers](/docs/settings/configuration/non-unique-emails)). A customer can also exist in the database if they don't have a self-managed account. For more details on profiles, see [Customer profiles](/developers/api/clients/profiles). ## Registering a customer with RaaS Registration as a Service (RaaS) creates an account in Synerise without any third-party integrations. It may be configured to require email confirmation. The basic request only requires an email, password, an UUID, but you can provide additional information. See [method reference](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/RegisterAClient). To authenticate this request, you need a [JWT of an anonymous profile](/developers/api/api-authorization/client-login#authenticating-as-an-anonymous-customer).
curl --location --request \
POST 'http://{SYNERISE_API_BASE_PATH}/sauth/clients/registered' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJhb...Ndo' \
--data-raw '{
    "email":"sampleclient@synerise.com",
    "password":"strongpassword",
    "uuid":"b3f56868-9667-4843-a8e5-0509456baa9b"
}'
Alternatively, you can use the [authentication endpoint](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/authenticateUsingPOST_v3). If an account doesn't exist, the authentication endpoint creates one. ## Account activation Synerise RaaS may be configured for three types of account confirmation: - Automatic: the account is ready to use immediately. The `snrs_email_confirmed` attribute in the customer is FALSE. - Email confirmation required: the account is ready to use, but confirmation is required to set the `snrs_email_confirmed` attribute in the customer profile to TRUE. - Email activation required: the account cannot be accessed until it is confirmed. Activation sets the `snrs_email_confirmed` attribute in the customer profile to TRUE. - PIN activation: the customer receives a PIN code instead of a confirmation link. Activation sets the `snrs_email_confirmed` attribute in the customer profile to TRUE. ### Setting the activation method
When changing the settings, any values you do not send are changed to default!
1. Get the current settings for your workspace. Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getGeneralConfigUsingGET).
curl --location --request GET 'https://{SYNERISE_API_BASE_PATH}/sauth/settings/general' \
   --header 'Authorization: Bearer eyJh...qU'
1. From the response, copy the current settings. 2. Change the copied settings and send an update request. Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updateGeneralSettingsUsingPOST). The following is an example of enabling PIN activation.
Remember about additional settings for each confirmation type, such as PIN length or confirmation redirect link.
curl --location --request POST 'https://{SYNERISE_API_BASE_PATH}/sauth/settings/general' \
--header 'Authorization: Bearer eyJ...JwqU' \
--header 'Content-Type: application/json' \
--data-raw '{
    "registrationType": "REQUIRE_PIN_CONFIRMATION",
    "tokenLifetimeInSeconds": 3600,
    "confirmationRedirectLink": null,
    "voucherPoolUuid": null,
    "allowOverwriteCustomIdentify": false,
    "allowEmailChangeFromWebForm": false,
    "pinConfirmationType": "ON_CONFLICT_WITH_EXTERNAL_ACCOUNT",
    "pinConfirmationLength": 6,
    "pinConfirmationValidInSeconds": 300,
    "allowPinResendFromDifferentDeviceId": false
}'
### Confirming the account by PIN Confirming the account by PIN has two modes, selected with the `pinConfirmationType` setting: - `ON_CONFLICT_WITH_EXTERNAL_ACCOUNT` (default setting) requires the PIN only if an account with the same unique identifier already exists and was registered with a third-party Identity Provider. - `EVERYONE` requires the PIN for all registrations. #### Activating/confirming the account Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/confirmByPinCodeUsingPOST). The activation request must always be sent from last device that requested a PIN. If you [re-send a PIN](#re-sending-an-activationconfirmation-pin) from a different device than the one that sent the registration request, the activation request must be made from the device that requested re-sending the PIN. **Prerequisites** - [Email sender integration](/docs/settings/tool/integrating-email-providers) must be enabled. - The [confirmation mail template](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getTemplateSettingsUsingGET) must include a `{{pin_code}}` insert. The PIN is sent to the customer's email automatically after registration.
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/clients/activation/by-pin-code/confirmation 
  --header 'Authorization: Bearer eyJ...JwqU' 
  --header 'content-type: application/json' 
  --data '{
    "deviceId":"5966145e-412d-44db-b826-7d53e6cfd300",
    "email":"john.doe@synerise.com",
    "pinCode":"123456",
    "uuid":"07243772-008a-42e1-ba37-c3807cebde8f"
    }'
**Result:** The account is activated/confirmed and ready to use. #### Re-sending an activation/confirmation PIN Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/resendByPinCodeUsingPOST). If the PIN expired, re-send it. By default, you can only request the re-sending from the last device that requested a PIN previously. If you want to allow requesting a PIN from other devices, set `allowPinResendFromDifferentDeviceId` to TRUE. The activation request can only be sent from the last device that requested a PIN, regardless of the settings. **Prerequisites** - [Email sender integration](/docs/settings/tool/integrating-email-providers) must be enabled. - The [confirmation mail template](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getTemplateSettingsUsingGET) must include a `{{pin_code}}` insert.
curl --request POST 
    --url https://{SYNERISE_API_BASE_PATH}/sauth/clients/activation/by-pin-code/request 
    --header 'Authorization: Bearer eyJ...JwqU' 
    --header 'content-type: application/json' 
    --data '{
      "deviceId":"5966145e-412d-44db-b826-7d53e6cfd300",
      "email":"john.doe@synerise.com",
      "uuid":"07243772-008a-42e1-ba37-c3807cebde8f"
      }'
**Result:** The activation PIN is re-sent. ### Confirming the account by activation link #### Activating/confirming the account Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/ConfirmAClientAccount). **Prerequisites**: [Email sender integration](/docs/settings/tool/integrating-email-providers) must be enabled. The token is sent to the customer's email automatically after registration.
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/clients/activation/confirmation 
  --header 'authorization: Bearer eyJh...JxkM5o' 
  --header 'content-type: application/json' 
  --data '{
      "token":"eyJh...JwcR4z"
    }'
**Result:** The account is activated/confirmed and ready to use. #### Requesting a new activation/confirmation token Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/resendUsingPOST). **Prerequisites**: [Email sender integration](/docs/settings/tool/integrating-email-providers) must be enabled. If the activation token expires or the message was not delivered, you can request a new token.
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/clients/activation/request 
  --header 'authorization: Bearer eyJh...JxkM5o' 
  --header 'content-type: application/json' 
  --data '{
      "email":"sampleclient@synerise.com"
    }'
**Result:** The email with the token is re-sent. ## Registering customers with third-party mechanisms You can register a customer by using Facebook, Google sign-in, OAuth, or Sign in with Apple. - Registering a customer with Facebook Login requires that your application is integrated with Facebook. For more details, see the [Facebook Developer Documentation](https://developers.facebook.com/docs/). - Registering a customer with Sign in with Apple requires that your application is integrated with Sign in with Apple. For more details, see the [Apple Developer Documentation](https://developer.apple.com/documentation/). - Registering a customer with Google requires that your application is integrated with Google. For more details, see the [Google Identity documentation](https://developers.google.com/identity/protocols/oauth2). - Registering with OAuth creates a customer account in Synerise, but a customer account must also exist in your own database to serve as a basis for OAuth authentication.
This endpoint can be used for logging in - if an account already exists, the response is a Synerise JWT that can be used for authorizing further requests as the customer.
The following is a basic request for Facebook authentication, but you can provide more information or change the Identity Provider. See [method reference](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/authenticateUsingPOST_v3). `accessToken` is the token that is sent by Synerise backend to your OAuth implementation.
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/sauth/auth/v3/login/client' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data-raw '{
    "apiKey":"01234abc-1234-5678-9abc-def012345678",
    "identityProvider": "FACEBOOK",
    "identityProviderToken": "70fb8a02-0a6e-48ca-96d5-0212ee140eae"
}'
The response is an authentication token. # Sending events Synerise uses two APIs to send events, depending on the event type: - the [`v4/events` API](https://hub.synerise.com/api-reference/data-management#tag/Events) is used to send most events, including custom ones. This API offers multiple endpoints specific to a particular event type. In this article, we will take a closer look at using the "Send Custom Event" endpoint and at the "Batch send events" endpoint. - the `v4/transactions` API (for [single transactions](https://hub.synerise.com/api-reference/data-management#operation/CreateATransaction) and [batches](https://hub.synerise.com/api-reference/data-management#operation/BatchAddOrUpdateTransactions)) is used to record `transaction.charge` events and automatically creates `product.buy` events for each transaction. ## "Send Custom Event" endpoint
DO NOT send `transaction.charge` events as custom events.
Transactions must be tracked with these endpoints: - [`/v4/transactions`](https://hub.synerise.com/api-reference/data-management#operation/CreateATransaction) (single transaction) - [`/v4/transactions/batch`](https://hub.synerise.com/api-reference/data-management#operation/BatchAddOrUpdateTransactions) (multiple transactions)
API reference available [here](https://hub.synerise.com/api-reference/data-management#operation/CustomEvent). This endpoint can be used to send custom events required by your integration. When you use this endpoint to send an event whose [definition](/docs/assets/events/event-definitions) doesn't exist in the system, a definition is created automatically. The request body must contain the following properties: - `action` is the type of event, for example `page.visit` (default event), `dog.bark` (custom event). When you use a dedicated endpoint for an event type, this parameter is not used. - `client` is an object with profile identifiers. It must contain at least one of the following identifiers: - `id` - `customId` - `uuid` - `email` - `label` must be a non-empty string. It is a legacy property, currently not used by Synerise and not saved in persistent storage. The following properties are optional: - `params` is an object with additional event parameters that you want to add to the request. Some names are reserved for system use (see API reference for details). - `time` is the time when the event occurred (for example, the time when a customer clicked a button), formatted according to [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601). **Example**: If your timezone is UTC-4 and your local time is 09:00:00, May 23, 2022: - You can send the time as UTC: `2022-05-23T13:00:00Z` - You can send the same time with your timezone: `2022-05-23T09:00:00-04:00` - You can send the same time with a different timezone, if necessary: `2022-05-23T07:00:00-06:00` All the above examples indicate the same date and time, written in different ways. You can include milliseconds, for example `2022-05-23T13:00:00.176Z` The time sent in this parameter is not affected by the time zone of your workspace. You can use any timezone or the UTC standard. When you retrieve an event later, the time is always returned as UTC.
- If no time is provided, the time when the event was received by Synerise is saved as the occurrence time. - **If the provided time is in the future, it is rejected** and the time when the event was received by Synerise is saved as the occurrence time. In the above example, future times would be: - later than `2022-05-23T13:00:00Z` - later than `2022-05-23T09:00:00-04:00` - later than `2022-05-23T07:00:00-06:00`
- `eventSalt` is a special parameter. Its usage is described in [Overwriting events](/developers/api/events/overwriting-events). The request can be authorized with a JWT of a profile (formerly called a client) or a workspace (formerly called a business profile). #### Example The following cURL request is an example of a custom `dog.bark` event with a few custom properties: `loudness`, `mood`, and `mailmanScared`:
curl --location --request POST 'https://{SYNERISE_API_BASE_PATH}/v4/events/custom' \
--header 'Authorization: Bearer ey...RtH_g' \
--header 'Api-Version: 4.4' \
--header 'Content-Type: application/json' \
--data-raw '{
    "action": "dog.bark",
    "client": {
        "id": 5092159999
    },
    "time": "2022-11-28T12:18:27Z",
    "params": {
        "loudness": 3,
        "mood": "happy",
        "mailmanScared": true
    },
    "label": "bark"
}'
### Sending a batch of events You can also send a number of events at once. A batch can include different event types saved to different profiles. The request body is an array of events similar to when sending a single events, with the following modification: - if the event is custom, add the `"type": "custom"` parameter - if the event has a dedicated endpoint: - add the `type` parameter with the value that corresponds to the name of the dedicated endpoint. For example, if the endpoint of the event is `/v4/events/shared`, the type is `shared`. - remove the `action` parameter. #### Example The following cURL request is a batch of two events: - the same `dog.bark` event from the [previous example](#send-custom-event-endpoint) - a `client.hitTimer` event (the dedicated endpoint is `/v4/events/hit-timer`), sent to a different profile
curl --location --request POST 'https://{SYNERISE_API_BASE_PATH}/v4/events/batch' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --header 'Api-Version: 4.4' \
  --header 'Authorization: Bearer ey...RtH_g' \
  --data-raw '[
      {
          "action": "dog.bark",
          "type": "custom",
          "client": {
              "id": 5092159999
          },
          "time": "2022-11-28T12:18:27Z",
          "params": {
              "loudness": 3,
              "mood": "happy",
              "mailmanScared": true
          },
          "label": "bark"
      },
      {
          "type": "hit-timer",
          "time": "2022-11-26T13:13:48Z",
          "client": {
              "id": 267498412
          },
          "label": "string"
      }
  ]'
# Workspace authentication In today's interconnected world, secure authentication mechanisms are crucial for machine-to-machine (M2M) integrations to ensure the confidentiality, integrity, and availability of data. In Synerise, M2M integrations are handled by [Workspace API keys](/docs/settings/tool/api). In each Workspace, you can create multiple API keys with different permissions.
- Keep the API keys secret. A leaked key must be deactivated **immediately**! - When creating the API key, use allowlisting or denylisting to only allow the events you intend to use. - Workspace API keys can be used to access all customer data, analytics, and manage the workspace. Workspace authentication should only be used in server-to-server communication for integrations. DO NOT use workspace API keys in your mobile applications and websites.
Two commonly used methods for API authentication are: - JSON Web Tokens (JWT): this is the default method for authenticating request made when using a Workspace API key. In this scenario, the API key is used to generate a JWT that expires after some time (60 minutes by default) - API keys (Basic authentication): this is an additional method for authenticating as a Workspace that needs to be enabled separately [in the settings of an API key](/docs/settings/tool/api#basic-workspace-authentication). The GUID of the workspace is used as the login, and the API key as the password. This authentication doesn't have an expiration time. This article explores the differences between these two approaches, compares their features, and highlights the ideal usage scenarios for each variant. By understanding their advantages and disadvantages, developers can make informed decisions to implement robust and secure authentication mechanisms. ## API authentication with JWT JWT are a compact, self-contained, and digitally signed authentication mechanism. They are commonly used for stateless authentication in distributed systems. A JWT token consists of three parts: a header, a payload, and a signature. The header contains information about the token's signing algorithm, while the payload contains relevant user or client data. The signature is generated using a secret key and ensures the token's integrity. In Synerise, the token is generated for you when you authenticate as a workspace. You don't need encode/decode it, or manipulate any data that's included in the token. When you use the token to authenticate a request, Synerise decodes it and checks if that token grants the authorization for the operation you're trying to perform. ### Advantages - Stateless: JWTs do not require server-side storage, making them suitable for scaling and load-balanced environments. - Flexibility: JWTs can carry custom data in their payload, allowing for additional information beyond authentication. - Granular Authorization: Tokens can include claims and scopes to control access to specific resources or functionalities. ### Disadvantages - Token Revocation: Since JWTs are stateless, revoking a token before its expiration requires additional mechanisms, such as maintaining a token denylist or short token expiration periods. - Token Size: JWTs can be larger in size compared to API keys, leading to increased bandwidth consumption. ### Usage 1. Obtain a JWT from the [workspace authentication endpoint](https://hub.synerise.com/api-reference/identity-and-access-management#operation/profileLogin):
curl --request POST 
   --url https://{SYNERISE_API_BASE_PATH}/uauth/v2/auth/login/profile 
   --header 'accept: application/json' 
   --header 'api-version: 4.4' 
   --header 'content-type: application/json' 
   --data '{"apiKey":"01234abc-1234-5678-9abc-def012345678"}'
The response is a JSON Web Token (JWT) that must be included in the `Authorization` header of further requests. By default, the token is valid for 60 minutes. 2. Include the token (preceded by `"Bearer"`) in the `Authorization` header of the requests you make, for example:
curl --location 'https://api.synerise.com/v4/events/custom' \
   --header 'Authorization: Bearer eyJhbGciOiJSUzUxMiJ9.eyJzdWIiOiJjYTQzMTA4ZGVkNWFhYmM3NzkzZDNmOWI5MjhjZGQ1NCIsImF1ZCI6IkFQSSIsInJsbSI6ImJ1c2luZXNzX3Byb2ZpbGUiLCJjdGQiOjE2ODY3NDEyNzE2NTIsImlzcyI6IlN5bmVyaXNlIiwiYnBpIjoyMzcwLCJzZXNzaW9uSWQiOiI3MjIzMTgzMC02ZDVhLTQwNGUtYjVlMy1hMTZlMDkxNzcyODIiLCJleHAiOjE2ODY3NDQ4NzEsImFwayI6ImFlZTM0NzdiLTY0YWItNDFkYy1iMThjLWRhMjQwZmI0ZjdlYyJ9.w9p94Owhdygw7w4EnZnA1nDXQCFyMinvalidANNobb4vukXFtsb_gCAyxCFpS35SDctCtzgMXKetNErhEJKrovrOhlQ2GhxvuAHDf_Rz8EawlEiSuPvaUV0djfqJdZujkD1wPPylRj2neqFy6El5D3gsqByKRZMVekackbmjTr8KQMbfiddeUtZPtIoDcSxsv6SozRruCNjEulczc4Tgn44Ht7ZhiNJDPTfyR2nINcTfuBdMngDG5ye39QzwW7WAgLxKerBKIwS34Ul10gpUD11UJebtGc9B16WWmlXD5iY90HR6cjiexSQ1kTcjkA3yQgVkyNXrRF2e1mpM5cXbWfvcyh0_W-U-kUfRFu4DQcYIvh5M4nT4eiC4RsxsoeJSUEhvfg7bLe085w_ug_f1PBCxiHM' \
   --header 'Api-Version: 4.4' \
   --header 'Content-Type: application/json' \
   --data '{
       "action": "auth.test",
       "client": {
           "id": 6501571767
       },
       "params": {
           "test": true
       },
       "label": "string"
   }'
## Basic API authentication with API keys When creating or editing a workspace API key, you can enable basic authentication. When you do so, you can authenticate with the workspace GUID as the login and the API key as the password. This is available for all endpoints with workspace authentication. The login/password combination is encoded with base64 and the result is sent in the `Authorization` header of an API request. This authentication doesn't have an expiry date and doesn't need additional API calls to obtain JWTs (but the API key can still be used to generate them as [described earlier](#api-authentication-with-jwt)). ### Advantages - Simplicity: API keys are straightforward to implement, making them an ideal choice for simple integrations or quick prototyping. - Easy Revocation: You can revoke access by disabling or deleting an API key, instantly preventing further authentication. - Performance: API keys are typically smaller in size than JWT tokens, resulting in reduced bandwidth consumption. ### Disadvantages - Key Management: Managing and securing a large number of API keys can be challenging, requiring robust key rotation and storage practices. - Insecure Transmission: API keys sent in plain text via URLs or headers may be vulnerable to interception, necessitating additional security measures like HTTPS and sender/receiver environment security controls. ### Usage In the settings of the workspace API key, [enable Basic workspace authentication](/docs/settings/tool/api#basic-workspace-authentication). In the following examples, these values are used: - Workspace GUID (login): `a919b437-c958-46a5-a82e-b1b2d9b68f61` - API key (password): `065e6fe6-8515-44b3-8427-d8a764295ba2` 1. Encode the `workspaceGuid:apiKey` combination with base64. **Example:**
```java import java.nio.charset.StandardCharsets; import java.util.Base64; class Scratch { public static void main(String[] args) { System.out.println(new String(Base64.getEncoder().encode("a919b437-c958-46a5-a82e-b1b2d9b68f61:065e6fe6-8515-44b3-8427-d8a764295ba2".getBytes(StandardCharsets.UTF_8)))); } } ```
```python import base64 loginAndPassword = b'a919b437-c958-46a5-a82e-b1b2d9b68f61:065e6fe6-8515-44b3-8427-d8a764295ba2' print(base64.b64encode(loginAndPassword).decode('utf-8')) ```
**Result:** ``` YTkxOWI0MzctYzk1OC00NmE1LWE4MmUtYjFiMmQ5YjY4ZjYxOjA2NWU2ZmU2LTg1MTUtNDRiMy04NDI3LWQ4YTc2NDI5NWJhMg== ``` 1. Include the result (preceded by `"Basic"`) in the `Authorization` header of the request:
curl --location 'https://api.synerise.com/v4/events/custom' \
   --header 'Authorization: Basic YTkxOWI0MzctYzk1OC00NmE1LWE4MmUtYjFiMmQ5YjY4ZjYxOjA2NWU2ZmU2LTg1MTUtNDRiMy04NDI3LWQ4YTc2NDI5NWJhMg==' \
   --header 'Api-Version: 4.4' \
   --header 'Content-Type: application/json' \
   --data '{
       "action": "auth.test",
       "client": {
           "id": 6501571767
       },
       "params": {
           "test": true
       },
       "label": "string"
   }'
# Customer account management When a customer registers, they become the owner of their account. They can change their own data and security settings. The requests for self-management do not require parameters that identify the customer. Identity information is encoded in the JSON Web Token used for authorization. ## Retrieving customers' own data Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/getAccountDataGET). A customer can access their own data stored in the database.
curl --location --request \
GET 'https://{SYNERISE_API_BASE_PATH}/v4/my-account/personal-information' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJh...1FG5M'
The response includes all of the customer's data from the database. ## Updating customers' own data Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/updateAccountDataUsingPOST). A customer can update their personal data. When sending the request, include only the fields that you want to update. Sending a null value deletes an attribute (if it's a custom attribute) or sets it to null/default value (if the attribute is Synerise-native). Empty strings are not accepted. The following example request updates the customer's avatar:
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/v4/my-account/personal-information' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJh...JxkM5o' \
--data-raw '{
    "avatarUrl": "https://www.gravatar.com/avatar/21b3b5d704c1a5169d16cef176ad4415?s=100&r=g&d=blank"
}'
## Changing email addresses A customer can change their own email address. **Prerequisites**: [SMS sender integration](/docs/settings/tool/integrating-sms-gateways) must be enabled.
Email address is the primary unique identifier of a recognized/authenticated customer.
1. [Request an email change](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/requestClientEmailChange).
curl --request POST 
     --url https://{SYNERISE_API_BASE_PATH}/sauth/my-account/email-change/request 
     --header 'authorization: Bearer eyJh...JxkM5o' 
     --header 'content-type: application/json' 
     --data '{
         "email":"newemail@synerise.com",
         "password":"strongpassword",
         "uuid":"07243772-008a-42e1-ba37-c3807cebde8f",
         "deviceId":"b3f56868-9667-4843-a8e5-0509456baa9b"
       }'
**Result:** A confirmation token is sent to the customer's phone number. 2. [Confirm email change](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/confirmClientEmailChange). You can also use this request to enable newsletter agreements for the new email.
curl --request POST 
     --url https://{SYNERISE_API_BASE_PATH}/sauth/my-account/email-change/confirmation 
     --header 'authorization: Bearer eyJh...JxkM5o' 
     --header 'content-type: application/json' 
     --data '{
         "token":"string",
         "newsletterAgreement":true
       }'
## Changing phone numbers A customer can change their own phone number. **Prerequisites**: [SMS sender integration](/docs/settings/tool/integrating-sms-gateways) must be enabled. 1. [Request a phone number change](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/RequestClientPhoneNumberChange).
curl --request POST 
     --url https://{SYNERISE_API_BASE_PATH}/v4/my-account/phone-update/request 
     --header 'authorization: Bearer eyJh...JxkM5o' 
     --data '{
         "phone":"555015332"
       }'
**Result:** A confirmation token is sent to the new phone number. 2. Confirm the phone number change. You can also use this request to enable SMS marketing permissions for the new number.
curl --request POST 
     --url https://{SYNERISE_API_BASE_PATH}/v4/my-account/phone-update/confirmation 
     --header 'authorization: Bearer eyJh...JxkM5o' 
     --data '{
         "phone":"string",
         "confirmationCode":"string",
         "deviceId":"string",
         "smsAgreement":true
       }'
## Account deletion Customers can delete their own accounts. Depending on the registration method, you need to use one of the following methods: - [Delete RaaS account](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/deleteAccountUsingPOST) - [Delete OAuth account](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/deleteOauthClientUsingPOST) - [Delete Log in with Facebook account](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/DeleteAFacebookClientAccount) - [Delete Sign in with Apple account](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/deleteAppleClientUsingPOST) When an account is deleted, its events (anonymized) are retained in the database. The customer profile stops being visible in the list of profiles and is deleted. # Customers - A **profile** is the customer data stored in our database. It can be anonymous or recognized. - An **account** is created for a profile when a customer registers and allows them to authorize and access their own data. # Managing newsletter agreements with API
**Upcoming breaking change (effective July 6, 2026):** Synerise is introducing changes to how user identifiers and UUIDs are handled. These changes may affect profiles with accented or diacritical characters in identifiers, profiles with leading or trailing whitespace in identifiers, and profiles with duplicate UUIDs. For details and recommended actions, see [Upcoming changes to handling identifiers](/docs/settings/configuration/identifier-standardization).
## Enabling with single/double opt-in Ensure that a [workflow for collecting newsletter agreements](/docs/settings/configuration/newsletter-sign-up) is running. Send a create/update API call with the `"newsletter_agreement_enabled": "enabled"` attribute. API reference is available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/BatchAddOrUpdateClients).
curl --location --request POST 'https://{SYNERISE_API_BASE_PATH}/v4/clients/batch' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJ...G2DI' \
--data-raw '[
   {
      "clientId": 12345,
      "attributes": {
          "newsletter_agreement_enabled": "enabled"
      }
   }
]'
This information is processed in the following way: 1. The customer's profile is updated with the `'newsletter_agreement_enabled': 'enabled'` attribute. 2. An event with details of the profile update is created and triggers the [workflow that collects newsletter agreements](/docs/settings/configuration/newsletter-sign-up). 3. One of the following happens: - If single opt-in is used, the agreement is enabled. Depending on the workflow configuration, the customer may receive an email with a notification. - If double opt-in is used, the customer receives an email and must click the link in that email to confirm the subscription. ## Enabling immediately You can also immediately enable an agreement over the API, without asking for confirmation or notifying the customer. If you use email address as a unique identifier, send a create/update API call with the `agreements.email` param set to `true`.
curl --location --request POST 'https://{SYNERISE_API_BASE_PATH}/v4/clients/batch' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJ...G2DI' \
--data-raw '[
   {
      "clientId": 12345,
      "agreements": {
         "email": true
         }
   }
]'
If you configured [non-unique emails](/docs/settings/configuration/non-unique-emails), send a create/update API call which changes the attribute you set as the agreement indicator to `enabled`
curl --location --request POST 'https://{SYNERISE_API_BASE_PATH}/v4/clients/batch' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJ...G2DI' \
--data-raw '[
   {
      "clientId": 12345,
      "attributes": {
         "the-newsletter-agreement-attribute-you-set-up": "enabled"
         }
   }
]'
The agreement is enabled immediately. API reference is available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/BatchAddOrUpdateClients). ## Disabling a newsletter agreement If you use email address as a unique identifier, send a create/update API call with the `agreements.email` param set to `false`. API reference is available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/BatchAddOrUpdateClients).
curl --location --request POST 'https://{SYNERISE_API_BASE_PATH}/v4/clients/batch' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJ...G2DI' \
--data-raw '[
   {
      "clientId": 12345,
      "agreements": {
         "email": false
         }
   }
]'
If you configured [non-unique emails](/docs/settings/configuration/non-unique-emails), send a create/update API call which changes the attribute you set as the agreement indicator to `disabled`
curl --location --request POST 'https://{SYNERISE_API_BASE_PATH}/v4/clients/batch' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJ...G2DI' \
--data-raw '[
   {
      "clientId": 12345,
      "attributes": {
         "the-newsletter-agreement-attribute-you-set-up": "disabled"
         }
   }
]'
The agreement is disabled immediately. # Synerise user authorization The user is the person who logs in to the [Synerise Application](https://app.synerise.com/). They can have access to one or more workspaces, with different permissions in each profile. After a user logs in, they must choose a workspace to work with. Users may be required to log in using multi-factor authentication. ## Logging in as a user API reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/userLogin). To log in as a user, you need the username and the password.
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/uauth/auth/login/user' \
--header 'Content-Type: application/json' \
--data-raw '{
    "username": "user@synerise.com",
    "password": "strongPassword"
}'
The response includes: - JSON Web Token (JWT) needed to authorize when selecting a workspace or modifying user data. This token cannot be used to perform operations within a workspace. - Information about the multi-factor authentication method - Information about the user. Note that no workspace is selected, the user has no permissions (authorities) and no roles.
{
      // JWT
      "token": "eyJhbGciOiJinvalidXyw0TAc",
      // User info
      "consumer": {
          "type": "USER",
          "businessProfileId": null,
          "name": "user@synerise.com",
          "id": 12345,
          "authorities": [],
          "roles": "-2",
          "type": "USER"
      },
      // multi-factor authentication method, if required
      "mfaMethods": [
          "TOTP_AUTHENTICATOR"
      ]
  }
- If `mfaMethods` is **not** empty, you must [confirm the multi-factor authentication](#confirming-multi-factor-authentication). - If `mfaMethods` is empty, [select a workspace](#workspace-selection). ## Confirming multi-factor authentication API reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/userMfaLogin).
After a user logs on, they don't need to enter the authentication code on the same device for 8 hours.
You need the JWT obtained from the login request and a token from your authentication app.
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/uauth/auth/login/user/mfa/verification?mfaType=TOTP_AUTHENTICATOR' \
--header 'Authorization: Bearer eyJhbG...2KIh6IU' \
--header 'Content-Type: application/json' \
--data-raw '{
    "verificationCode": "938538"
}'
The response is the same as in the login endpoint. Proceed to [workspace selection](#workspace-selection). ## Workspace selection After authentication, a user must select a workspace to work in. ### Checking available workspaces API reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getBusinessProfilesUsingGET). You need a JWT obtained from [logging in](#logging-in-as-a-user); [multi-factor authentication](#confirming-multi-factor-authentication) (if enabled); or with a workspace already selected (when switching between profiles). The following request checks the workspaces available to a user:
curl --location --request \
GET 'https://{SYNERISE_API_BASE_PATH}/uauth/business-profile/' \
--header 'Authorization: Bearer eyJhbGciOiJSUz...qDTl72iqwIji4'
The response is an array of workspaces available to a user. The UUID is stored in the `businessProfileGuid` field.
[
    {
        "id": 48,
        "name": "Sample Profile",
        "logo": "https://synerise.com/sample.png",
        "businessProfileGuid": "01234abc-1234-5678-9abc-def012345678",
        "created": "2020-07-21T12:41:59Z",
        "subdomain": "sample-profile",
        "ipRestricted": false,
        "mfaRequired": true
    }
]
### Selecting a workspace API reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/userProfileLoginUsingPOST). You need: - a JWT obtained from [logging in](#logging-in-as-a-user); [multi-factor authentication](#confirming-multi-factor-authentication) (if enabled); or with a workspace already selected (when switching between profiles). - the [UUID of the workspace](#checking-available-workspaces)
curl --location --request \
  POST 'https://{SYNERISE_API_BASE_PATH}/uauth/auth/login/user/profile/01234abc-1234-5678-9abc-def012345678' \
  --header 'Authorization: Bearer eyJh...d886bpyWWZKvQESsM8cUYWuVqfSI'
The response includes: - JWT needed to perform operations as a user within a workspace (most operations performed as Synerise User require this token) - Information about the user and their authorities (permissions) in the workspace. These permissions correspond to the ones listed as required in the API reference.
{
      "token": "eyJhbGciOiJSU...tIarjyXFFCv_Ek6M",
      "consumer": {
          "type": "USER",
          "businessProfileId": 48,
          "name": "user@synerise.com",
          "id": 12345,
          "authorities": [
              "ROLE_ADMIN_EDITUSER",
              "ROLE_ANALYTICS_SHOW",
              "ROLE_API_ADD",
              "ROLE_API_CREATE",
              "ROLE_API_DELETE",
              ...
          ],
          "roles": "16",
          "type": "USER"
      }
  }
# Customer devices A workspace [may be configured](/developers/api/clients/security#device-authorization) so that customers must confirm logging in from unknown devices. When a customer registers, the device they are using is added to the list of known devices automatically. ## Authenticating devices by email token Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/authenticateDevice). **Prerequisites**: [Email sender integration](/docs/settings/tool/integrating-email-providers) must be enabled. When a customer logs in from a new device, an authentication token is sent to the customer's email address. The device is not allowed to log in to the customer's account until that token is sent.
curl --request GET 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/client/device-control/53b1e613-826b-4b9e-8ee3-2ff7dde2f1e4
## Adding device to current account Method reference available [here](https://hub.synerise.com/api-referenceClientManagement/ClientManagement.html#operation/LinkAClientDeviceToCurrentlyLoggedInClient). You can add a device to the trusted device list of the currently authenticated customer. `deviceId` is the only obligatory parameter. The format of the ID depends on the OS.
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/v4/my-account/linked-devices 
  --header 'authorization: Bearer eyJh...JxkM5o' 
  --data '{
      "deviceId":"ec9d4410-4048-43e5-b755-f7d53d00656c",
    }'
# Recommendation API responses The response depends on the type of recommendation and the configuration of the item feed.
When [configuring the item feed](/docs/settings/configuration/ai-engine-configuration/engine-configuration-for-recommendations#selecting-response-attributes), in the **Response attributes** section, add only the attributes that you plan to use.
### Item recommendations These recommendations offer items. In an item recommendation response: - the `data` array lists items as objects. `itemId` is always included in each item's object. Adding more details can be enabled in the ["Response attributes" settings of the item feed](/docs/settings/configuration/ai-engine-configuration/engine-configuration-for-recommendations#selecting-response-attributes). - the `extras` object contains: - Slots (if applicable) with the IDs of the items they include. The details of those items are in `data`. - IDs of context items, if applicable. - A `correlationId` used for identifying [which events result from which request](/developers/api/recommendations/events). This is used in [recommendation statistics](/docs/ai-hub/recommendations-v2/recommendation-statistics) and in analytics. To display the results, you need to get item details from `data`. If you use multiple slots, you can use the data from `extras.slots` to arrange the results in the customer's view. **Response example**:
{
    // an array of items in the recommendation:
    "data": [
        { // one item as an object
            "itemId": "0196818716fta", // unique ID of the item from the item feed

            // additional attributes from item feed configuration:
            "title": "Baseball cap", 
            // the `link` attribute is automatically enriched with campaign/request metadata for tracking in Decision Hub and Automation Hub
            "link": "https://example.com/baseball-cap?snrai_campaign=DkhvrZoTKthD&snrai_id=75ea91a9-3a27-4dbf-addc-b7006cf70d52",
            "color": "red"
        },
        ... // more items from the recommendation:
        {
            ...
        },
        {
            ...
        }
    ],

    // other data:
    "extras": {
        "contextItems": null, // context items, if applicable
        "correlationId": "75ea91a9-3a27-4dbf-addc-b7006cf70d52", // unique ID of this recommendation request

        // items sorted into slots:
        "slots": [
            { // one slot as an object
                "id": 2, // ID of the slot
                // a list of items in this slot (only IDs): 
                "itemIds": [
                    "0196818716fta", // a single item ID
                    ...
                ],
                "name": "no shoes", // name of the slot
                "rows": null // not used in item recommendation campaigns
            },
            // more slots:
            {
                ...
            },
            {
                ...
            }
        ]
    }
}
### Section page recommendations This type of recommendation offers items sorted into sections. The sections are created by selecting an attribute. All items within one section will have the same attribute value. To learn about creating section page recommendations, read [Creating section page recommendations](/docs/ai-hub/recommendations-v2/creating-section-recommendations). In a section page recommendation response: - the `data` array contains the details of all the items in the recommendation. It works the same as in [item recommendations](#item-recommendations). - the `extras` objects contains slots. In each slot, the `rows` array is a list of sections (objects) with item IDs and the attribute value that is common for the items in that section. The number of sections and items in each section is defined separately for each slot. To display the items, you need to take the section data from `extras.slots.rows` and the item details from `data`. You can also use data from the metadata catalog, such as item descriptions or image URLs. **Response example**: In this example: - the campaign contains 1 slot. - the slot contains 2 sections. - each section contains 3 items. - the selected attribute for creating sections is `color`
{
      // an array of items in the recommendation:
      "data": [
          { // one item as an object
              "itemId": "0196818719002", // unique ID of the item from the item feed

              // additional attributes from item feed configuration:
              "title": "Baseball cap", 
              // the `link` attribute is automatically enriched with campaign/request metadata for tracking in Decision Hub and Automation Hub
              "link": "https://example.com/baseball-cap?snrai_campaign=DkhvrZoTKthD&snrai_id=75ea91a9-3a27-4dbf-addc-b7006cf70d52",
          },
          ... // more items from the recommendation:
          {
              ...
          },
          {
              ...
          }
      // other data:
      ],
      "extras": {
          "contextItems": null, // context items, if applicable
          "correlationId": "75ea91a9-3a27-4dbf-addc-b7006cf70d52", // unique ID of this recommendation request

          // items sorted into slots and sections:
          "slots": [
              { // one slot as an object
                  "id": 0, // ID of the slot
                  "itemIds": null, // not used in section page recommendations
                  "name": "red items", // name of the slot

                  // sections of the recommendation:
                  "rows": [
                      {
                          "attributeValue": "red", // the common value of the selected attribute (color)
                          "itemIds": [
                              "0196818719002", // a single item ID
                              "0196499574457",
                              "0196996669878"
                          ],
                          "metadata": {
                              "imageLink": "https://example.com/section-images/red.png",
                              "title": "Red items"
                          }
                      },
                      {
                          "attributeValue": "green",
                          "itemIds": [
                              "0195953880516",
                              "0196895673303",
                              "0886614236611"
                          ],
                          "metadata": {
                              "imageLink": "https://example.com/section-images/green.png",
                              "title": "Green items"
                          }
                      }
                  ]
              }
          ]
      }
  }
### Attribute recommendations Attribute recommendations are functionally similar to item recommendations. However, instead of merchandise, they return attributes of that merchandise. To learn about creating attribute recommendations, see [Creating attribute recommendations](/docs/ai-hub/recommendations-v2/creating-attribute-recommendations). In an attribute recommendation response: - the `data` array includes the recommended attributes. By default, only the `itemId` (attribute name) is returned. If you want to use more attributes, such as a link to a page listing items with that attribute, you must configure a metadata catalog (see [Creating attribute recommendations](/docs/ai-hub/recommendations-v2/creating-attribute-recommendations)). - the `extras` objects contain slots. Each slot contains the IDs of the attributes it includes. To recommend items, you can: 1. Use the metadata catalog to add links as parameters of the recommended attributes. You can also include other metadata, such as images, titles, descriptions, and so on. 2. Use the links to redirect users to pages that show items with a given attribute. **Response example**: In this example: - the campaign has 2 slots. - both slots use the `color` attribute as **Item attribute**. - a metadata catalog is enabled for the recommendation and includes a `url` attribute for each attribute value.
{
      // an array of attribute values in the recommendation:
      "data": [
          {
              "itemId": "brown", // unique ID of the attribute value

              // additional data from the metadata catalog:
              "url": "https://example.com/items-by-color/brown",
              "imageUrl": "https://example.com/attribute-images/brown.png",
              "description": "Autumn colors for you"
          },
          {
              "itemId": "blonde",
              ...
          },
          {
              "itemId": "blue",
              ...
          },
          {
              "itemId": "orange",
              ...
          },
          {
              "itemId": "white",
              ...
          },
          {
              "itemId": "pink",
              ...
          }
      ],
      "extras": {
          "contextItems": null, // context items, if applicable
          "correlationId": "839f6ae5-af2f-4771-b501-ea609a8e2611", // unique ID of this recommendation request

          // attribute values sorted into slots:
          "slots": [
              {
                  "id": 0, // ID of the slot
                  "itemIds": [
                      "brown", // a single attribute value
                      "blonde",
                      "blue"
                  ],
                  "name": "Unnamed slot",
                  "rows": null // not used in attribute recommendations
              },
              {
                  "id": 1,
                  "itemIds": [
                      "orange",
                      "white",
                      "pink"
                  ],
                  "name": "Unnamed slot",
                  "rows": null
              }
          ]
      }
  }
# Customer security configuration This article presents the API methods for managing customer account security policies. ## General settings The general settings are collected under a single endpoint for your convenience. ### Checking general settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getConfigUsingGET).
curl --location --request \
GET 'https://api.{SYNERISE_API_BASE_PATH}/sauth/settings' \
--header 'Api-Version: 4.4' \
--header 'Authorization: Bearer eyJh6sNQ'
The response is a list of settings:
{
    "confirmationMailSubject": "Confirm your account",
    "confirmationMailBody": "Click <a href=\"{{client_confirmation_link}}\" > here </a> to confirm your account",
    "confirmationMailTemplateId": null,
    "tokenLifetimeInSeconds": 3600,
    "confirmationRedirectLink": null,
    "passwordResetMailTemplateId": null,
    "passwordResetMailSubject": "Reset your password",
    "passwordResetMailBody": "Password reset token: {{password_reset_hash}}",
    "voucherPoolUuid": null,
    "registrationType": "AUTOMATIC",
    "allowOverwriteCustomIdentify": false
}
### Updating general settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updateAllDataUsingPOST).
When updating the settings, send values for **all settings**. Any values that are not sent will be reset to default! Before updating, you can check the current settings and copy the response into the request body, making modifications only to the settings that you want to change.
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/sauth/settings' \
--header 'Authorization: Bearer eyJ...hMpTw' \
--header 'Content-Type: application/json' \
--data-raw '{
    "confirmationMailSubject": "Confirm your account",
    "confirmationMailBody": "Click <a href=\"{{client_confirmation_link}}\" > here </a> to confirm your account",
    "confirmationMailTemplateId": null,
    "tokenLifetimeInSeconds": 1800,
    "confirmationRedirectLink": null,
    "passwordResetMailTemplateId": null,
    "passwordResetMailSubject": "Reset your password",
    "passwordResetMailBody": "Password reset token: {{password_reset_hash}}",
    "voucherPoolUuid": null,
    "registrationType": "AUTOMATIC",
    "allowOverwriteCustomIdentify": false
}'
The response returns the new settings. ## Authorization settings You can use third-party authentication mechanisms. See more in [Profile authentication](/developers/api/api-authorization/client-login). ### Checking OAuth settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getOauthSettingsUsingGET).
curl --request GET 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/oauth 
  --header 'authorization: Bearer eyJh...MpTw'
The response includes the current settings. ### Updating OAuth settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updateOatuhSettingsUsingPOST).
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/oauth 
  --header 'authorization: Bearer eyJ...hMpTw' 
  --header 'content-type: application/json' 
  --data '{
    "name": "self",
    "endpoint": "https://{SYNERISE_API_BASE_PATH}/mockOauth",
    "headers": {
        "Accept": "application/json",
        "Authorization": "Bearer {{ token }}"
    },
    "mapping": {
        "firstname": "firstName",
        "phone": "phone",
        "id": "clientId",
        "email": "email",
        "lastname": "lastName"
    },
    "mappedExternal": true
}'
The response includes the new settings. ### Checking Sign in with Apple settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getAppleAuthSettingsUsingGET).
curl --request GET 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/oauth/apple 
  --header 'authorization: Bearer eyJh...MpTw'
The response includes the current settings. ### Updating Sign in with Apple settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updateAppleAuthSettingsUsingPOST).
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/oauth 
  --header 'authorization: Bearer eyJ...hMpTw' 
  --header 'content-type: application/json' 
  --data '{
    "enabled": true,
    "bundle": "bundleName"
}'
The response includes the new settings. ## Password policy You can enforce the length of passwords and the kind of characters they must include. ### Checking password policy settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getPasswordPolicySettingsUsingGET).
curl --request GET 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/password-policy 
  --header 'authorization: Bearer eyJ...hMpTw'
The response includes the current settings. ### Updating password policy settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updatePasswordPolicySettingsUsingPOST).
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/sauth/settings/password-policy' \
--header 'Authorization: Bearer eyJhb...jzcU' \
--header 'Content-Type: application/json' \
--data-raw '{
    "requireAtLeastOneUppercaseLetter": true,
    "requireAtLeastOneLowercaseLetter": true,
    "requireAtLeastOneNumber": true,
    "requireAtLeastOneNonAlphaNumericCharacter": true,
    "minLength": 6,
    "maxLength": 255
}'
## Bans Bans allow you to limit or block access after a number of unsuccessful log in attempts. ### Checking ban settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getBanSettingsUsingGET).
curl --request GET 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/ban 
  --header 'authorization: Bearer eyJ...hMpTw'
### Updating ban settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updateBanSettingsUsingPOST).
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/ban 
  --header 'authorization: Bearer eyJ...hMpTw' 
  --header 'content-type: application/json' 
  --data '{
        "blockingForClientEnabled": true,
        "firstBanCollectingTime": 60,
        "firstBanThreshold": 3,
        "firstBanDuration": 300,
        "secondBanCollectingTime": 1200,
        "secondBanThreshold": 10,
        "secondBanDuration": 1800,
        "permanentBanCollectingTime": 86400,
        "permanentBanThreshold": 15,
        "permanentBanDuration": 31556926
}'
The response includes the new settings. ## Device authorization You can allow customers to control access from unknown devices. To authorize devices, see [Customer devices](/developers/api/clients/devices). ### Checking device authorization settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getDeviceControlSettingsUsingGET).
curl --request GET 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/device-control 
  --header 'authorization: Bearer eyJ...hMpTw'
### Updating device authorization settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updateDeviceSettingsUsingPOST).
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/device-control 
  --header 'authorization: Bearer eyJ...hMpTw' 
  --header 'content-type: application/json' 
  --data '{
        "deviceControlMode": "ON",
        "hardMailTitle": "New sign-in attempt to your account",
        "hardMailBody": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n</head>\n<body>\n\n<pre>\n\nHello,\n\nWe have noticed new sign-in attempt to your account from device we do not recognise.\n\nIP: {{ ip }}\nCountry: {{ country }}\n\nTime: {{ login_time }}\n\nIf it's you who signed-in from new device please confirm by clicking below link\n    <a href=\"{{ device_control_url }}\">{{ device_control_url }}</a>\n\n    But if you do not recognise this sign-in attempt, we recommend you to change your password from within the App and also check if your email haven't been part os known password leaks, you can do that through <a href=\"https://haveibeenpwned.com/\">https://haveibeenpwned.com/</a> or <a href=\"https://monitor.firefox.com/\">https://monitor.firefox.com/</a>.\nIn case you noticed that there are results related to you on either of these sites please review your passwords across all of the online services you use.\n\nAll the best,\nSynerise Team\n</pre>\n</body>\n</html>",
        "hardTemplateId": null,
        "softMailTitle": "New sign-in to your account",
        "softMailBody": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n    <meta charset=\"UTF-8\">\n</head>\n<body>\n\n<pre>\n\nHello,\n\nWe have noticed a sign-in to your account from the following location.\n\nIP: {{ ip }}\nCountry: {{ country }}\n\nTime: {{ login_time }}\n\n\nBut if you do not recognise this sign-in attempt, we recommend you to change your password from within the App and also check if your email haven't been part os known password leaks, you can do that through <a href=\"https://haveibeenpwned.com/\">https://haveibeenpwned.com/</a> or <a href=\"https://monitor.firefox.com/\">https://monitor.firefox.com/</a>.\nIn case you find results related to you on either of these sites, we strongly recommend to review your passwords across all of the online services you use.\n\nAll the best,\nSynerise Team\n</pre>\n</body>\n</html>",
        "softTemplateId": null
    }'
The response includes the new settings. ## Email change These settings affect the message that a customer receives when they want to change their email address. ### Checking email change settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getClientEmailChangeSettingsUsingGET).
curl --request GET 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/email-change 
  --header 'authorization: Bearer eyJ...hMpTw'
### Updating email change settings Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updateEmailClientChangeSettingsUsingPOST).
curl --request POST 
  --url https://{SYNERISE_API_BASE_PATH}/sauth/settings/email-change 
  --header 'authorization: Bearer eyJ...hMpTw' 
  --header 'content-type: application/json' 
  --data '{
        "clientEmailChangeRequestMailSubject": "Confirm your mail",
        "clientEmailChangeRequestMailBody": "To confirm your mail click <a href=\"{{client_email_change_url}}\" > here </a>",
        "clientEmailChangeRequestMailTemplateId": null,
        "clientEmailChangeNotificationMailSubject": "Your email is going to be changed",
        "clientEmailChangeNotificationMailBody": "You are going to change your mail for {{new_email}}. If it is not you please change your password as soon as possible.",
        "clientEmailChangeNotificationMailTemplateId": null
    }'
The response includes the new settings. # Events Events are used to store the history of a profile's activities (for example, visiting a page) and system activities which target the profile (for example, sending an email). This section describes elements of the event APIs. For event descriptions, configuration, enrichment, and more, see [Managing event definitions](/docs/assets/events/event-definitions). # IP access control Within the scope of a single workspace, you can limit access to a pool of IP addresses. Users trying to access the profile from other addresses are denied. ## Checking IP policy Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/getUserBpIpPolicyUsingGET). **Request:**
curl --location --request \
GET 'https://{SYNERISE_API_BASE_PATH}/uauth/settings/user-bp-ip-policy' \
--header 'Authorization: Bearer eyJhbGc..._tNS0B28LLHc'
The following response shows that IP access control is disabled.
{
    "enabled": false,
    "enableSupportSubnets": true,
    "ipPolicy": []
}
## Updating IP policy Method reference available [here](https://hub.synerise.com/api-reference/identity-and-access-management#operation/updateUserBpIpPolicyUsingPOST). The following request enables IP allowlisting, with two addresses allowed. It also allows access from Synerise support subnets. The subnet IPs depend on the configuration.
You must send a complete list of allowed IPs every time - if a list already exists, it is overwritten by the request.
curl --location --request \
POST 'https://{SYNERISE_API_BASE_PATH}/uauth/settings/user-bp-ip-policy' \
--header 'Authorization: Bearer eyJhbGc..._tNS0B28LLHc' \
--header 'Content-Type: application/json' \
--data-raw '{
    "enabled": true,
    "enableSupportSubnets": true,
    "ipPolicy": [
        "192.0.2.12",
        "192.0.2.15"
    ]
}'
The response includes the new settings:
{
    "enabled": true,
    "enableSupportSubnets": true,
    "ipPolicy": [
        "192.0.2.12",
        "192.0.2.15"
    ]
}
# Recommendations API The recommendation API lets you retrieve results from a campaign you created earlier or make ad-hoc requests (model requests). When making the requests, you can add or modify filters, set the item context, exclude items from the response, and select the attributes included in the response. In this section, you can learn how to: - make different types of recommendation requests - read the response - add or manipulate filters - send events that can be used in Decision Hub and Automation Hub ## Before you begin - Ensure that the model for the type of recommendations you want to request is enabled in the [settings of an item feed](/docs/settings/configuration/ai-engine-configuration/engine-configuration-for-recommendations#selecting-recommendation-types-and-default-filters). - You should be familiar with recommendation types and filter types: - [Recommendation types](/docs/ai-hub/recommendations-v2/recommendation-types) - [Recommendation filter types](/docs/ai-hub/recommendations-v2/recommendation-filters#filter-types) - If you want to add or change filters when making the request, you need to learn the [Items Query Language](/developers/iql). # Recommendation API filters You can manipulate item filters when making the request. ## Filter types
For a detailed description of filter types, see [the User Guide](/docs/ai-hub/recommendations-v2/recommendation-filters#filter-types).
### IQL filters An IQL filter is a string built using the [Items Query Language](/developers/iql). It allows you to combine filters and apply logic such as IF statements to build criteria that an item must meet to be included in the recommendation response. Elastic IQL filters let you supplement the recommendation result with items which don't meet the filter criteria in case the criteria are too restrictive.
- The "equals" operator is `==`. A single `=` is not an operator in IQL. - In the IQL string, the spaces before and after the `AND/OR` operators are required. - When adding filters to POST requests, you must escape any `"` in the filter string in the request body, for example: ```json "additionalFilters": "brand!=\"foo\" AND brand!=\"bar baz\"", ```
When you add filters to a campaign in the Synerise Web Application, you can [use the API to fetch the campaign's settings, including filters](https://hub.synerise.com/api-reference/ai-recommendations#operation/GetRecommendationCampaignV2). You can use this to learn IQL by seeing how filters created with the GUI are saved into IQL strings. To see the filters, check the `slots[].filterRules` object in the response.
### Distinct filters Distinct filters regulate how many items with certain properties can be recommended at the same time. - In campaign result requests, the filters are set by the campaign and can't be changed when making the request. - In model requests, you can add a distinct filter when making the request. ## Manipulating filters in campaign results In campaign requests, you can use the `additionalFilters` and `additionalElasticFilters` parameters to modify or replace the filters from the campaign settings. When you do that, you must the use `filtersJoiner` and `elasticFiltersJoiner` parameters to set the logic of combining the filters: - `AND` means that an item must match both the filter you send and the one from the campaign. - `OR` means that an item must match the filter you send, the filter from the campaign, or both. - `REPLACE` means that an item must match the filter you send and the filter from the campaign is ignored. Distinct filters are defined in the campaign settings and can't be changed when making a request. **Examples**:
In this example, the item must meet at least both of the following: - the conditions of elastic filter from the campaign - elastic filter: price must be more than 50 Usage example: a cart recommendation which shows items with a price that will increase the cart's value to the threshold of free shipping.
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns?token=...' \
--header 'Content-Type: application/json' \
--data '{
    "clientUUID": "cf9e9b57-7776-51bc-b7bc-75cc75abdf59",
    "campaignId": "DkhvrZoTKthD",
    "additionalElasticFilters": "price.value>50",
    "elasticFiltersJoiner": "AND"
}'
In this example, the item must meet at least one of the following: - the conditions of elastic filter from the campaign - elastic filter: price must be between 50 and 100
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns?token=...' \
  --header 'Content-Type: application/json' \
  --data '{
      "clientUUID": "cf9e9b57-7776-51bc-b7bc-75cc75abdf59",
      "campaignId": "DkhvrZoTKthD",
      "additionalElasticFilters": "price.value<100 AND price.value>50",
      "elasticFiltersJoiner": "OR"
  }'
In this example, the filter from the campaign is replaced. The new filter is that the item's brand can't be "foo" or "bar baz".
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns/DkhvrZoTKthD?&additionalFilters=brand!%3D%22foob%22%20AND%20brand!%3D%22bar%20baz%22&filtersJoiner=REPLACE&token=...&clientUUID=...'
In this example, the item must meet both of the following: - the conditions of filter from the campaign - color is `red`
curl --location 'https://api.synerise.com/recommendations/v2/recommend/campaigns?token=...' \
  --header 'Content-Type: application/json' \
  --data '{
      "clientUUID": "cf9e9b57-7776-51bc-b7bc-75cc75abdf59",
      "campaignId": "DkhvrZoTKthD",
      "additionalFilters": "color==\"red\"",
      "filtersJoiner": "AND"
  }'
## Requests to a model In requests to a model, you can add the following parameters: - `filters` is an [IQL filter](/developers/iql) - `elastic:filters` is an elastic [IQL filter](/developers/iql) - `distinctFilter` is an object:
"distinctFilter": {
  "elastic": boolean, // when `true`, if there are not enough items which meet the criteria,
                      // other items can be added to meet the minimum number of items in the slot
  "filters": // an array of filters
      [
          {
              "field": "color", // attribute name
              "maxNumItems": n, // max number of items with the same attribute value
              "levelRangeModifier": n // only used when field is 'category'.
                                      // Removes the last n category levels
          }
      ]
  }
The available filter types depend on the recommendation type. For details, refer to each endpoint's [reference documentation](https://hub.synerise.com/api-reference/ai-recommendations#tag/Recommendations).
**Example**: A request to the "Personalized" model with a filter that uses an attribute from the profile which made the request:
curl --location 'https://api.synerise.com/recommendations/v2/recommend/items/users/8ae22439-f72b-4fe7-98e5-da3217215c54?filters=colors%3D%3Dclient.attributes.favoriteColor&token=98A5FC55-0000-0000-0000-98339BDECAE6'
curl --location 'https://api.synerise.com/recommendations/v2/recommend/items/users/8ae22439-f72b-4fe7-98e5-da3217215c54?token=98A5FC55-0000-0000-0000-98339BDECAE6' \
--header 'Content-Type: application/json' \
--data '{
    "clientUuid": "8ae22439-f72b-4fe7-98e5-da3217215c54",
    "slots": [
        {
            "filters": "colors==client.attributes.favoriteColor"
        }
    ]
}'
# Overwriting events You can overwrite an existing event, for example to change a parameter value or correct an error. This is done by sending an event (as described in [Sending events](/developers/api/events/sending-events)) with the same action, occurrence time, and event salt as an existing event. When you overwrite the event: - All data in the event payload (parameters) is overwritten with data from the new event. - The UUID stays the same. - The time of occurrence stays the same. In `v4/transaction` endpoints, this parameter is called `recordedAt`. - The time of saving in the database changes to the new event. - In Automations that use the overwritten event as a trigger, the automation is triggered if the new event is sent more than 72 hours after the original. This is because the event UUID stays the same, and Automation treats events with the same UUID within 72 hours as duplicates that were sent due to an error. ## Requirements and limitations - The original event (the one which you want to overwrite) had to be sent with an `eventSalt` parameter. - An `eventSalt` must be unique. For example, you can concatenate the action, profile ID, and timestamp. - The `eventSalt` can't be retrieved with an event! You need to implement your own mechanism for keeping the values for later use or create the value in such a way that it can be re-created. - `eventSalt` can't be added to an existing event. - Both events must have the same action. - Both events must belong to the same profile's history. - Both events must have the same `time` - In transaction events, this parameter is called `recordedAt` - It isn't possible to change the time of occurrence by overwriting an event. - This must be the time saved in the database. If your original event had a timestamp that was in the future in relation to the time of sending the event, that timestamp was rejected and you must first retrieve the event and check the time it was saved with (in such a case, it will be the same as the time of receiving the event in Synerise). ## Example ### Send first event This is the original event:
curl --location --request POST 'https://api.synerise.com/v4/events/custom' \
--header 'Authorization: Bearer ey...RtH_g' \
--header 'Api-Version: 4.4' \
--header 'Content-Type: application/json' \
--data-raw '{
    "action": "dog.bark",
    "eventSalt": "dogbark50921599992022-12-13T15:25:08.861Z",
    "client": {
        "id": 5092159999
    },
    "time": "2022-12-13T15:25:08.861Z",
    "params": {
        "loudness": 3,
        "mood": "happy",
        "mailmanScared": true
    },
    "label": "bark"
}'
### Get original event This is the event when you retrieve it (for example, by [getting all events from a profile](https://hub.synerise.com/api-reference/data-management#operation/GetClientEvents)):
{
    "time": "2022-12-13T15:24:49Z",
    "action": "dog.bark",
    "label": "",
    "client": {
        "id": 5092159999,
        "email": "e0097757-d1e2-44ac-ba3c-d97979a354c1@anonymous.invalid",
        "uuid": "e0097757-d1e2-44ac-ba3c-d97979a354c1"
    },
    "params": {
        "eventCreateTime": "2022-12-13T15:25:08.861Z",
        "mood": "happy",
        "ip": "13.93.68.194",
        "loudness": 3,
        "mailmanScared": true
    }
}
Note that the `eventSalt` is not retrieved, and some parameters were added automatically when the event was processed. ### Overwrite event Let's overwrite the event by: - changing the `loudness` parameter - removing the `mailmanScared` parameter - adding the `mailDelivered` parameter
curl --location --request POST 'https://api.synerise.com/v4/events/custom' \
  --header 'Authorization: Bearer ey...RtH_g' \
  --header 'Api-Version: 4.4' \
  --header 'Content-Type: application/json' \
  --data-raw '{
      "action": "dog.bark",
      "eventSalt": "dogbark50921599992022-12-13T15:25:08.861Z",
      "client": {
          "id": 5092159999
      },
      "time": "2022-12-13T15:25:08.861Z",
      "params": {
          "loudness": 1,
          "mood": "happy",
          "mailDelivered": true
      },
      "label": "bark"
  }'
### Get overwritten event When you retrieve the same event: - the parameters are changed according to the new data you sent. - the `eventCreateTime` parameter is the time of saving the new instance in the database, and event retention takes the new time into account. - the occurrence time (`time`) is the same. - the updated event also replaces the original event on the [profile's card](/docs/crm/crm-profile#activity-list) view.
{
      "time": "2022-12-13T15:25:08.861Z",
      "action": "dog.bark",
      "label": "",
      "client": {
          "id": 5092159999,
          "email": "e0097757-d1e2-44ac-ba3c-d97979a354c1@anonymous.invalid",
          "uuid": "e0097757-d1e2-44ac-ba3c-d97979a354c1"
      },
      "params": {
          "eventCreateTime": "2022-12-13T15:48:02.746Z",
          "mood": "happy",
          "ip": "13.93.68.194",
          "loudness": 1,
          "mailDelivered": true
      }
  }
# Recommendation API events When you make recommendation requests to the API, a `recommendation.generated` event is created automatically. If you want to use [campaign statistics](/docs/ai-hub/recommendations-v2/recommendation-statistics) or build your own analyses and workflows, you must also send the following events: - a `recommendation.view` event when the recommendation is displayed (shown on the screen or scrolled into view). - [Send with JS SDK](/developers/web/methods-reference#send-a-recommendationview-event) - [Send with Mobile SDK](/developers/mobile-sdk/event-tracking#recommendation-viewed) - [Send with API](#recommendationview) - a `recommendation.click` event when a result is clicked or tapped. - [Send with JS SDK](/developers/web/methods-reference#send-a-recommendationclick-event) - [Send with Mobile SDK](/developers/mobile-sdk/event-tracking#recommendation-clicked) - [Send with API](#recommendationclick) In these events, the `correlationId` parameter from the recommendation results and the `campaignId` parameter are used to correlate the events with a request and campaign that caused them. This can be used in Statistics, Decision Hub, and Automation Hub. ### recommendation.view Send this event when the recommendation appears in the customer's view. In the request, the `correlationId` must be the same as the `correlationId` from the recommendation response that was used to display the content. For more details, see the [API Reference](https://hub.synerise.com/api-reference/data-management#operation/publishAiCompatRecommendationViewUsingPOST). If you have a [custom tracking domain](/developers/web/first-party-tracking) configured: - Use the custom domain in the URL. - [Add `/ai` before the endpoint path](/developers/web/first-party-tracking#updating-your-synerise-api-requests).
curl --location 'https://api.synerise.com/v4/events/ai-compat/recommendation.view?token=98A5FC55-0000-0000-0000-98339BDECAE6' \
--header 'Content-Type: application/json' \
--data '{
    "correlationId": "ac371d07-f8a2-4cae-9058-22e00b1f45b3",
    "clientUUID": "cf9e9b57-7776-51bc-b7bc-75cc75abdf59",
    "items": [
        "0196895673303",
        "0192309816199",
        "0196505285612"
    ],
    "campaignId": "DkhvrZoTKthD" // ADD THIS PARAMETER ONLY IN CAMPAIGN RESULT REQUESTS
}'
### recommendation.click Send this event when an item from the recommendation is clicked or tapped, including buttons such as "Add to cart" or "Buy now". In the request, the `correlationId` must be the same as the `correlationId` from the recommendation response that was used to display the content. For more details, see the [API Reference](https://hub.synerise.com/api-reference/data-management#operation/publishAiCompatRecommendationClickUsingPOST). If you have a [custom tracking domain](/developers/web/first-party-tracking) configured: - Use the custom domain in the URL. - [Add `/ai` before the endpoint path](/developers/web/first-party-tracking#updating-your-synerise-api-requests).
curl --location 'https://api.synerise.com/v4/events/ai-compat/recommendation.click?token=98A5FC55-0000-0000-0000-98339BDECAE6' \
--header 'Content-Type: application/json' \
--data '{
    "correlationId": "ac371d07-f8a2-4cae-9058-22e00b1f45b3",
    "clientUUID": "cf9e9b57-7776-51bc-b7bc-75cc75abdf59",
    "item": "0196895673303",
    "campaignId": "DkhvrZoTKthD" // ADD THIS PARAMETER ONLY IN CAMPAIGN RESULT REQUESTS
}'
# Index