# Introduction

## Okendo Technical Reference

Welcome to the Okendo Technical Reference guide! Here you'll learn all about integrating Okendo with your custom technology stack.

### Support

If you require additional assistance or have questions about the contents of this guide, please reach out via email to <solutions@okendo.io>. For additional resources, consult our [Knowledge Base](https://support.okendo.io).


# Merchant REST API

## Usage

This is an authenticated API that is intended to be used by a merchant to retrieve or configure data within Okendo. It is **not** intended to be used on-site or in any client-side code and doing so will put your data at risk. For public and client-side use, see the [Storefront REST API](/on-site/storefront-rest-api).

## Basics

This API is organised around REST with resource-based CRUD operations. Parameters for GET requests should be provided in the query string whereas POST/PUT request parameters should be provided as JSON in the body. JSON is also used for responses, including errors.

## Authentication

Authentication to the API is performed via HTTP Basic Auth. The username is your Okendo User ID and the password is a unique, 32-character string. Both your username and password can be found in the integration settings section of the Okendo app. An example authorisation header is provided below:

`Basic MDAwMDAwMDAtMDAwMC0wMDAwLTAwMDAtMDAwMDAwMDAwMDAwOldlTG92ZVRoYXRZb3VUb29rVGhlVGltZVRvRG9UaGlz`

All requests must be made over HTTPS.

## Pagination

When listing large amounts of data, not all of it can be returned in a single request. We use pagination to break data up into reasonably sized chunks. When listing a resource, the response may include a `nextUrl` property to indicate that another page of results is available:

```json
{
    "reviews": [],
    "nextUrl": "/reviews..."
}
```

Append the `nextUrl` to the base path and make a GET request to that URL to retrieve the next page of results. Repeat this process until you have all the results you need or there are no more pages of results (there will be no `nextUrl`).

## Rate Limiting

This API allows a consistent rate of 2 requests per second, with a small burst capacity above that. Exceeding this limit will result in requests failing with an HTTP 429 (Too Many Requests) error code.

## Versioning

Versioning is done via an HTTP header containing the required version. New versions of the API are released periodically. Provide the `okendo-api-version` header with a valid value in all requests. Valid versions:

* 2025-02-01


# Quick Start

Get started in minutes with Okendo's Merchant REST API

{% hint style="info" %}
The [Merchant REST API](/merchant-rest-api) API is **not** intended for client-side use.

For public and client-side use, see the [Storefront REST API](/on-site/storefront-rest-api).
{% endhint %}

## Get Your Credentials

Your API requests are authenticated using your Okendo User ID and an API Key. You can get these details from the integration settings section of the Okendo app.

## Make Your First Request

To make your first request, send an authenticated request to the `/reviews` endpoint. This will fetch some of your published `reviews`.

## List Reviews

> Returns a list of Reviews for the requested store

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"reviews"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/reviews":{"get":{"tags":["reviews"],"summary":"List Reviews","description":"Returns a list of Reviews for the requested store","parameters":[{"description":"A limit on the number of items returned. Between 1 and 100. Default 25.","in":"query","name":"limit","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"lastEvaluated","description":"The URL-encoded JSON object representing the cursor for the next page of results.","in":"query","required":false,"schema":{"type":"string"}},{"name":"orderBy","description":"The sort order of the reviews. Format: '(date|rating) (asc|desc)'. Default 'date desc'","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","description":"A filter on the Reviews based on the review's moderation status. The value must be one of 'approved', 'pending', 'rejected'. Default 'approved'.","in":"query","required":false,"schema":{"type":"string","enum":["approved","pending","rejected"],"description":"The moderation status of the review."}}],"responses":{"200":{"description":"An object containing a list of Reviews and a relative link to the next page of results if available.","content":{"application/json":{"schema":{"type":"object","properties":{"reviews":{"type":"array","items":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user id within Okendo.","format":"uuid"},"reviewId":{"type":"string","format":"uuid"},"productId":{"type":"string","description":"The product ID prefixed by a platform identifier."},"attributesWithRating":{"type":"array","items":{"type":"object","properties":{"minLabel":{"type":"string","description":"The label for the leading edge of an attribute bar."},"midLabel":{"type":"string","description":"The label for the midpoint of a centered-range attribute bar."},"maxLabel":{"type":"string","description":"The label for the trailing edge of an attribute bar."},"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["centered-range","range"]},"value":{"type":"number","description":"The value selected on the attribute scale. For attribute of type 'range' this is between 1 and 5. For 'centered-range', between -1 and 1."}},"required":["title","type","value"]}},"body":{"type":"string","description":"The content of the review."},"containsProfanity":{"type":"boolean","description":"true if the title or body contain words on the profanity list, otherwise false."},"dateCreated":{"type":"string","format":"date-time"},"helpfulCount":{"type":"integer","format":"int32","description":"The number of upvotes a review has received."},"isIncentivized":{"type":"boolean"},"isRecommended":{"type":"boolean"},"media":{"type":"array","items":{"type":"object","properties":{"streamId":{"type":"string","format":"uuid"},"fullSizeUrl":{"type":"string","format":"uri"},"largeUrl":{"type":"string","format":"uri"},"thumbnailUrl":{"type":"string","format":"uri"},"type":{"type":"string","enum":["image","video"]},"isHidden":{"type":"boolean"}},"required":["fullSizeUrl","thumbnailUrl","type","streamId","isHidden"]},"minItems":1},"productAttributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"productName":{"type":"string"},"order":{"type":"object","properties":{"orderId":{"type":"string"},"orderNumber":{"type":"string"}}},"rating":{"type":"integer","format":"int32","minimum":1,"maximum":5,"description":"The number of stars a review has received."},"reply":{"type":"object","properties":{"body":{"type":"string","format":"html","description":"The html representation of the review reply."},"dateCreated":{"type":"string","format":"date-time"},"rawBody":{"type":"string","description":"The reply entered by the user. (Note: can include markdown syntax)."},"isPrivate":{"type":"boolean","description":"true if the reply is unpublished otherwise false."}},"required":["body"]},"reviewer":{"type":"object","properties":{"attributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"avatarUrl":{"type":"string","format":"uri"},"displayName":{"type":"string","description":"The full name entered by the reviewer with the last name truncated."},"email":{"type":"string","format":"email"},"isVerified":{"type":"boolean"},"location":{"type":"object","properties":{"country":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"zoneCode":{"type":"string"}}},"name":{"type":"string","description":"The full name entered by the reviewer."},"socialConnection":{"type":"string","enum":["facebook","google"]},"verifiedStatus":{"type":"string","enum":["Verified Buyer","Verified Reviewer"],"description":"'Verified Buyer' if the reviewer could be connected to a valid order. 'Verified Reviewer' if the reviewer could not be connected to a valid order but verified their email address."}},"required":["displayName","name"]},"reward":{"type":"object","properties":{"description":{"type":"string"},"integration":{"type":"string"},"type":{"type":"string","enum":["coupon","points","event"]},"value":{"type":"string"},"isCouponUpgrade":{"type":"boolean"}},"required":["type","value"]},"sentiment":{"type":"string","enum":["positive","negative","neutral","mixed"],"description":"The natural language sentiment of the review title and body."},"status":{"type":"string","enum":["approved","pending","rejected"],"description":"The moderation status of the review."},"tags":{"type":"array","items":{"type":"string"},"description":"The names of any tags added to the review."},"title":{"type":"string","description":"The title of the review."},"unhelpfulCount":{"type":"integer","format":"int32","description":"The number of downvotes a review has received."},"variantId":{"type":"string","description":"The id of the reviewed Shopify product variant."},"variantName":{"type":"string","description":"The name of the reviewed Shopify product variant."}},"required":["subscriberId","reviewId","productId","body","dateCreated","rating","reviewer","status","title","unhelpfulCount"]}},"nextUrl":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."}}}}}}
```

To make the request, use a networking client of your choice or follow these examples:

{% tabs %}
{% tab title="Node.js Fetch" %}

```javascript
const response = await fetch('https://api.okendo.io/enterprise/reviews', {
  headers: {
    'Authorization': 'Basic ' + Buffer.from('<okendo_user_id>:<api_key>').toString('base64'),
    'okendo-api-version': '2025-02-01'
  }
});

const data = await response.json();
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X GET "https://api.okendo.io/enterprise/reviews" \
  -u "<okendo_user_id>:<api_key>" \
  -H "okendo-api-version: 2025-02-01"
```

{% endtab %}
{% endtabs %}


# Endpoints

Full specifications of each API endpoint available in Okendo's Merchant REST API

## Getting Started

Before diving into the details, check out the usage guidelines ([Merchant REST API](/merchant-rest-api)) and the [Quick Start](/merchant-rest-api/quick-start) guide.

## Table of Contents

{% content-ref url="/pages/R6dw18GlNvY0G5VD0mMV" %}
[Reviews](/merchant-rest-api/endpoints/reviews)
{% endcontent-ref %}

{% content-ref url="/pages/hY3uYG33FtWNiOs3fNlu" %}
[Loyalty](/merchant-rest-api/endpoints/loyalty)
{% endcontent-ref %}

{% content-ref url="/pages/t7Mgj0yFq1LQJRoC3pNN" %}
[Surveys](/merchant-rest-api/endpoints/surveys)
{% endcontent-ref %}

{% content-ref url="/pages/UiEeyPUUcjkroURPeBKw" %}
[Quizzes](/merchant-rest-api/endpoints/quizzes)
{% endcontent-ref %}

{% content-ref url="/pages/sdZ7lukOQT8EjxIuOUk8" %}
[Customers](/merchant-rest-api/endpoints/customers)
{% endcontent-ref %}

{% content-ref url="/pages/TGklbKAmaHZAJfGEzxxC" %}
[Webhooks](/webhooks/getting-started)
{% endcontent-ref %}

{% content-ref url="/pages/mWYN6Pdm6YsGx7a6L4bw" %}
[Settings](/merchant-rest-api/endpoints/settings)
{% endcontent-ref %}


# Reviews

Endpoints related to Okendo Reviews and review groups

## Reviews

## List Reviews

> Returns a list of Reviews for the requested store

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"reviews"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/reviews":{"get":{"tags":["reviews"],"summary":"List Reviews","description":"Returns a list of Reviews for the requested store","parameters":[{"description":"A limit on the number of items returned. Between 1 and 100. Default 25.","in":"query","name":"limit","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"lastEvaluated","description":"The URL-encoded JSON object representing the cursor for the next page of results.","in":"query","required":false,"schema":{"type":"string"}},{"name":"orderBy","description":"The sort order of the reviews. Format: '(date|rating) (asc|desc)'. Default 'date desc'","in":"query","required":false,"schema":{"type":"string"}},{"name":"status","description":"A filter on the Reviews based on the review's moderation status. The value must be one of 'approved', 'pending', 'rejected'. Default 'approved'.","in":"query","required":false,"schema":{"type":"string","enum":["approved","pending","rejected"],"description":"The moderation status of the review."}}],"responses":{"200":{"description":"An object containing a list of Reviews and a relative link to the next page of results if available.","content":{"application/json":{"schema":{"type":"object","properties":{"reviews":{"type":"array","items":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user id within Okendo.","format":"uuid"},"reviewId":{"type":"string","format":"uuid"},"productId":{"type":"string","description":"The product ID prefixed by a platform identifier."},"attributesWithRating":{"type":"array","items":{"type":"object","properties":{"minLabel":{"type":"string","description":"The label for the leading edge of an attribute bar."},"midLabel":{"type":"string","description":"The label for the midpoint of a centered-range attribute bar."},"maxLabel":{"type":"string","description":"The label for the trailing edge of an attribute bar."},"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["centered-range","range"]},"value":{"type":"number","description":"The value selected on the attribute scale. For attribute of type 'range' this is between 1 and 5. For 'centered-range', between -1 and 1."}},"required":["title","type","value"]}},"body":{"type":"string","description":"The content of the review."},"containsProfanity":{"type":"boolean","description":"true if the title or body contain words on the profanity list, otherwise false."},"dateCreated":{"type":"string","format":"date-time"},"helpfulCount":{"type":"integer","format":"int32","description":"The number of upvotes a review has received."},"isIncentivized":{"type":"boolean"},"isRecommended":{"type":"boolean"},"media":{"type":"array","items":{"type":"object","properties":{"streamId":{"type":"string","format":"uuid"},"fullSizeUrl":{"type":"string","format":"uri"},"largeUrl":{"type":"string","format":"uri"},"thumbnailUrl":{"type":"string","format":"uri"},"type":{"type":"string","enum":["image","video"]},"isHidden":{"type":"boolean"}},"required":["fullSizeUrl","thumbnailUrl","type","streamId","isHidden"]},"minItems":1},"productAttributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"productName":{"type":"string"},"order":{"type":"object","properties":{"orderId":{"type":"string"},"orderNumber":{"type":"string"}}},"rating":{"type":"integer","format":"int32","minimum":1,"maximum":5,"description":"The number of stars a review has received."},"reply":{"type":"object","properties":{"body":{"type":"string","format":"html","description":"The html representation of the review reply."},"dateCreated":{"type":"string","format":"date-time"},"rawBody":{"type":"string","description":"The reply entered by the user. (Note: can include markdown syntax)."},"isPrivate":{"type":"boolean","description":"true if the reply is unpublished otherwise false."}},"required":["body"]},"reviewer":{"type":"object","properties":{"attributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"avatarUrl":{"type":"string","format":"uri"},"displayName":{"type":"string","description":"The full name entered by the reviewer with the last name truncated."},"email":{"type":"string","format":"email"},"isVerified":{"type":"boolean"},"location":{"type":"object","properties":{"country":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"zoneCode":{"type":"string"}}},"name":{"type":"string","description":"The full name entered by the reviewer."},"socialConnection":{"type":"string","enum":["facebook","google"]},"verifiedStatus":{"type":"string","enum":["Verified Buyer","Verified Reviewer"],"description":"'Verified Buyer' if the reviewer could be connected to a valid order. 'Verified Reviewer' if the reviewer could not be connected to a valid order but verified their email address."}},"required":["displayName","name"]},"reward":{"type":"object","properties":{"description":{"type":"string"},"integration":{"type":"string"},"type":{"type":"string","enum":["coupon","points","event"]},"value":{"type":"string"},"isCouponUpgrade":{"type":"boolean"}},"required":["type","value"]},"sentiment":{"type":"string","enum":["positive","negative","neutral","mixed"],"description":"The natural language sentiment of the review title and body."},"status":{"type":"string","enum":["approved","pending","rejected"],"description":"The moderation status of the review."},"tags":{"type":"array","items":{"type":"string"},"description":"The names of any tags added to the review."},"title":{"type":"string","description":"The title of the review."},"unhelpfulCount":{"type":"integer","format":"int32","description":"The number of downvotes a review has received."},"variantId":{"type":"string","description":"The id of the reviewed Shopify product variant."},"variantName":{"type":"string","description":"The name of the reviewed Shopify product variant."}},"required":["subscriberId","reviewId","productId","body","dateCreated","rating","reviewer","status","title","unhelpfulCount"]}},"nextUrl":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."}}}}}}
```

## GET /reviews/{reviewId}

> Retrieve a Review

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"reviews"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/reviews/{reviewId}":{"get":{"tags":["reviews"],"summary":"Retrieve a Review","parameters":[{"name":"reviewId","description":"The ID of the Review to retrieve.","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"A Review object","content":{"application/json":{"schema":{"type":"object","properties":{"review":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user id within Okendo.","format":"uuid"},"reviewId":{"type":"string","format":"uuid"},"productId":{"type":"string","description":"The product ID prefixed by a platform identifier."},"attributesWithRating":{"type":"array","items":{"type":"object","properties":{"minLabel":{"type":"string","description":"The label for the leading edge of an attribute bar."},"midLabel":{"type":"string","description":"The label for the midpoint of a centered-range attribute bar."},"maxLabel":{"type":"string","description":"The label for the trailing edge of an attribute bar."},"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["centered-range","range"]},"value":{"type":"number","description":"The value selected on the attribute scale. For attribute of type 'range' this is between 1 and 5. For 'centered-range', between -1 and 1."}},"required":["title","type","value"]}},"body":{"type":"string","description":"The content of the review."},"containsProfanity":{"type":"boolean","description":"true if the title or body contain words on the profanity list, otherwise false."},"dateCreated":{"type":"string","format":"date-time"},"helpfulCount":{"type":"integer","format":"int32","description":"The number of upvotes a review has received."},"isIncentivized":{"type":"boolean"},"isRecommended":{"type":"boolean"},"media":{"type":"array","items":{"type":"object","properties":{"streamId":{"type":"string","format":"uuid"},"fullSizeUrl":{"type":"string","format":"uri"},"largeUrl":{"type":"string","format":"uri"},"thumbnailUrl":{"type":"string","format":"uri"},"type":{"type":"string","enum":["image","video"]},"isHidden":{"type":"boolean"}},"required":["fullSizeUrl","thumbnailUrl","type","streamId","isHidden"]},"minItems":1},"productAttributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"productName":{"type":"string"},"order":{"type":"object","properties":{"orderId":{"type":"string"},"orderNumber":{"type":"string"}}},"rating":{"type":"integer","format":"int32","minimum":1,"maximum":5,"description":"The number of stars a review has received."},"reply":{"type":"object","properties":{"body":{"type":"string","format":"html","description":"The html representation of the review reply."},"dateCreated":{"type":"string","format":"date-time"},"rawBody":{"type":"string","description":"The reply entered by the user. (Note: can include markdown syntax)."},"isPrivate":{"type":"boolean","description":"true if the reply is unpublished otherwise false."}},"required":["body"]},"reviewer":{"type":"object","properties":{"attributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"avatarUrl":{"type":"string","format":"uri"},"displayName":{"type":"string","description":"The full name entered by the reviewer with the last name truncated."},"email":{"type":"string","format":"email"},"isVerified":{"type":"boolean"},"location":{"type":"object","properties":{"country":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"zoneCode":{"type":"string"}}},"name":{"type":"string","description":"The full name entered by the reviewer."},"socialConnection":{"type":"string","enum":["facebook","google"]},"verifiedStatus":{"type":"string","enum":["Verified Buyer","Verified Reviewer"],"description":"'Verified Buyer' if the reviewer could be connected to a valid order. 'Verified Reviewer' if the reviewer could not be connected to a valid order but verified their email address."}},"required":["displayName","name"]},"reward":{"type":"object","properties":{"description":{"type":"string"},"integration":{"type":"string"},"type":{"type":"string","enum":["coupon","points","event"]},"value":{"type":"string"},"isCouponUpgrade":{"type":"boolean"}},"required":["type","value"]},"sentiment":{"type":"string","enum":["positive","negative","neutral","mixed"],"description":"The natural language sentiment of the review title and body."},"status":{"type":"string","enum":["approved","pending","rejected"],"description":"The moderation status of the review."},"tags":{"type":"array","items":{"type":"string"},"description":"The names of any tags added to the review."},"title":{"type":"string","description":"The title of the review."},"unhelpfulCount":{"type":"integer","format":"int32","description":"The number of downvotes a review has received."},"variantId":{"type":"string","description":"The id of the reviewed Shopify product variant."},"variantName":{"type":"string","description":"The name of the reviewed Shopify product variant."}},"required":["subscriberId","reviewId","productId","body","dateCreated","rating","reviewer","status","title","unhelpfulCount"]}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## PUT /reviews/{reviewId}

> Update a Review

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"reviews"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/reviews/{reviewId}":{"put":{"tags":["reviews"],"summary":"Update a Review","parameters":[{"name":"reviewId","description":"The ID of the Review to update.","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","description":"The moderation status of the review."}},"required":["status"]}}},"required":true},"responses":{"200":{"description":"A Review object","content":{"application/json":{"schema":{"type":"object","properties":{"review":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user id within Okendo.","format":"uuid"},"reviewId":{"type":"string","format":"uuid"},"productId":{"type":"string","description":"The product ID prefixed by a platform identifier."},"attributesWithRating":{"type":"array","items":{"type":"object","properties":{"minLabel":{"type":"string","description":"The label for the leading edge of an attribute bar."},"midLabel":{"type":"string","description":"The label for the midpoint of a centered-range attribute bar."},"maxLabel":{"type":"string","description":"The label for the trailing edge of an attribute bar."},"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["centered-range","range"]},"value":{"type":"number","description":"The value selected on the attribute scale. For attribute of type 'range' this is between 1 and 5. For 'centered-range', between -1 and 1."}},"required":["title","type","value"]}},"body":{"type":"string","description":"The content of the review."},"containsProfanity":{"type":"boolean","description":"true if the title or body contain words on the profanity list, otherwise false."},"dateCreated":{"type":"string","format":"date-time"},"helpfulCount":{"type":"integer","format":"int32","description":"The number of upvotes a review has received."},"isIncentivized":{"type":"boolean"},"isRecommended":{"type":"boolean"},"media":{"type":"array","items":{"type":"object","properties":{"streamId":{"type":"string","format":"uuid"},"fullSizeUrl":{"type":"string","format":"uri"},"largeUrl":{"type":"string","format":"uri"},"thumbnailUrl":{"type":"string","format":"uri"},"type":{"type":"string","enum":["image","video"]},"isHidden":{"type":"boolean"}},"required":["fullSizeUrl","thumbnailUrl","type","streamId","isHidden"]},"minItems":1},"productAttributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"productName":{"type":"string"},"order":{"type":"object","properties":{"orderId":{"type":"string"},"orderNumber":{"type":"string"}}},"rating":{"type":"integer","format":"int32","minimum":1,"maximum":5,"description":"The number of stars a review has received."},"reply":{"type":"object","properties":{"body":{"type":"string","format":"html","description":"The html representation of the review reply."},"dateCreated":{"type":"string","format":"date-time"},"rawBody":{"type":"string","description":"The reply entered by the user. (Note: can include markdown syntax)."},"isPrivate":{"type":"boolean","description":"true if the reply is unpublished otherwise false."}},"required":["body"]},"reviewer":{"type":"object","properties":{"attributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"avatarUrl":{"type":"string","format":"uri"},"displayName":{"type":"string","description":"The full name entered by the reviewer with the last name truncated."},"email":{"type":"string","format":"email"},"isVerified":{"type":"boolean"},"location":{"type":"object","properties":{"country":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"zoneCode":{"type":"string"}}},"name":{"type":"string","description":"The full name entered by the reviewer."},"socialConnection":{"type":"string","enum":["facebook","google"]},"verifiedStatus":{"type":"string","enum":["Verified Buyer","Verified Reviewer"],"description":"'Verified Buyer' if the reviewer could be connected to a valid order. 'Verified Reviewer' if the reviewer could not be connected to a valid order but verified their email address."}},"required":["displayName","name"]},"reward":{"type":"object","properties":{"description":{"type":"string"},"integration":{"type":"string"},"type":{"type":"string","enum":["coupon","points","event"]},"value":{"type":"string"},"isCouponUpgrade":{"type":"boolean"}},"required":["type","value"]},"sentiment":{"type":"string","enum":["positive","negative","neutral","mixed"],"description":"The natural language sentiment of the review title and body."},"status":{"type":"string","enum":["approved","pending","rejected"],"description":"The moderation status of the review."},"tags":{"type":"array","items":{"type":"string"},"description":"The names of any tags added to the review."},"title":{"type":"string","description":"The title of the review."},"unhelpfulCount":{"type":"integer","format":"int32","description":"The number of downvotes a review has received."},"variantId":{"type":"string","description":"The id of the reviewed Shopify product variant."},"variantName":{"type":"string","description":"The name of the reviewed Shopify product variant."}},"required":["subscriberId","reviewId","productId","body","dateCreated","rating","reviewer","status","title","unhelpfulCount"]}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## POST /reviews/{reviewId}/reply

> Reply to a Review

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"reviews"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/reviews/{reviewId}/reply":{"post":{"tags":["reviews"],"summary":"Reply to a Review","parameters":[{"name":"reviewId","description":"The ID of the Review to reply to.","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"reply":{"type":"object","properties":{"body":{"type":"string","description":"The message to reply with."},"isPrivate":{"type":"boolean","description":"Whether the reply should be visible to the public."}},"required":["body"]},"shouldEmailReply":{"type":"boolean","description":"Whether the Customer should be notified of the reply via email."}},"required":["reply"]}}},"required":true},"responses":{"200":{"description":"The updated Review with the reply included.","content":{"application/json":{"schema":{"type":"object","properties":{"review":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user id within Okendo.","format":"uuid"},"reviewId":{"type":"string","format":"uuid"},"productId":{"type":"string","description":"The product ID prefixed by a platform identifier."},"attributesWithRating":{"type":"array","items":{"type":"object","properties":{"minLabel":{"type":"string","description":"The label for the leading edge of an attribute bar."},"midLabel":{"type":"string","description":"The label for the midpoint of a centered-range attribute bar."},"maxLabel":{"type":"string","description":"The label for the trailing edge of an attribute bar."},"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["centered-range","range"]},"value":{"type":"number","description":"The value selected on the attribute scale. For attribute of type 'range' this is between 1 and 5. For 'centered-range', between -1 and 1."}},"required":["title","type","value"]}},"body":{"type":"string","description":"The content of the review."},"containsProfanity":{"type":"boolean","description":"true if the title or body contain words on the profanity list, otherwise false."},"dateCreated":{"type":"string","format":"date-time"},"helpfulCount":{"type":"integer","format":"int32","description":"The number of upvotes a review has received."},"isIncentivized":{"type":"boolean"},"isRecommended":{"type":"boolean"},"media":{"type":"array","items":{"type":"object","properties":{"streamId":{"type":"string","format":"uuid"},"fullSizeUrl":{"type":"string","format":"uri"},"largeUrl":{"type":"string","format":"uri"},"thumbnailUrl":{"type":"string","format":"uri"},"type":{"type":"string","enum":["image","video"]},"isHidden":{"type":"boolean"}},"required":["fullSizeUrl","thumbnailUrl","type","streamId","isHidden"]},"minItems":1},"productAttributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"productName":{"type":"string"},"order":{"type":"object","properties":{"orderId":{"type":"string"},"orderNumber":{"type":"string"}}},"rating":{"type":"integer","format":"int32","minimum":1,"maximum":5,"description":"The number of stars a review has received."},"reply":{"type":"object","properties":{"body":{"type":"string","format":"html","description":"The html representation of the review reply."},"dateCreated":{"type":"string","format":"date-time"},"rawBody":{"type":"string","description":"The reply entered by the user. (Note: can include markdown syntax)."},"isPrivate":{"type":"boolean","description":"true if the reply is unpublished otherwise false."}},"required":["body"]},"reviewer":{"type":"object","properties":{"attributes":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","description":"The title of the attribute."},"type":{"type":"string","enum":["drop-down","multi-value","single-value"]},"value":{"oneOf":[{"type":"string"},{"type":"array","items":{"type":"string"}}],"description":"The selected value(s) for the attribute. For types 'drop-down' and 'single-select' this is a single value. For type 'multi-select' it is an array."}},"required":["title","type","value"]}},"avatarUrl":{"type":"string","format":"uri"},"displayName":{"type":"string","description":"The full name entered by the reviewer with the last name truncated."},"email":{"type":"string","format":"email"},"isVerified":{"type":"boolean"},"location":{"type":"object","properties":{"country":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"}}},"zoneCode":{"type":"string"}}},"name":{"type":"string","description":"The full name entered by the reviewer."},"socialConnection":{"type":"string","enum":["facebook","google"]},"verifiedStatus":{"type":"string","enum":["Verified Buyer","Verified Reviewer"],"description":"'Verified Buyer' if the reviewer could be connected to a valid order. 'Verified Reviewer' if the reviewer could not be connected to a valid order but verified their email address."}},"required":["displayName","name"]},"reward":{"type":"object","properties":{"description":{"type":"string"},"integration":{"type":"string"},"type":{"type":"string","enum":["coupon","points","event"]},"value":{"type":"string"},"isCouponUpgrade":{"type":"boolean"}},"required":["type","value"]},"sentiment":{"type":"string","enum":["positive","negative","neutral","mixed"],"description":"The natural language sentiment of the review title and body."},"status":{"type":"string","enum":["approved","pending","rejected"],"description":"The moderation status of the review."},"tags":{"type":"array","items":{"type":"string"},"description":"The names of any tags added to the review."},"title":{"type":"string","description":"The title of the review."},"unhelpfulCount":{"type":"integer","format":"int32","description":"The number of downvotes a review has received."},"variantId":{"type":"string","description":"The id of the reviewed Shopify product variant."},"variantName":{"type":"string","description":"The name of the reviewed Shopify product variant."}},"required":["subscriberId","reviewId","productId","body","dateCreated","rating","reviewer","status","title","unhelpfulCount"]}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## Groups

## POST /groups

> Create a Shopify backed group and return the group created

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/groups":{"post":{"tags":["groups"],"summary":"Create a Shopify backed group and return the group created","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"description":"The name of the group.","type":"string"},"isAutoAssignProductsEnabled":{"description":"Indicates if the products in the group are automatically assigned to show reviews from other products within the same group.","type":"boolean"},"shopifyCollectionId":{"type":"string","description":"The ID of Shopify collection that will be used to create the group."}},"required":["name","isAutoAssignProductsEnabled","shopifyCollectionId"]}}},"required":true},"responses":{"200":{"description":"An object containing the group that was just created.","content":{"application/json":{"schema":{"type":"object","properties":{"group":{"type":"object","allOf":[{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user id within Okendo.","format":"uuid"},"groupId":{"type":"string","description":"The unique group id.","format":"uuid"},"dateCreated":{"description":"The date when the group was created.","format":"date-time","type":"string"},"isAutoAssignProductsEnabled":{"description":"Indicates if the products in the group are automatically assigned to show reviews from other products within the same group.","type":"boolean"},"name":{"description":"The name of the group.","type":"string"}},"required":["subscriberId","groupId","dateCreated","name","type"]}],"properties":{"shopifyCollectionId":{"type":"string","description":"The ID of Shopify collection that will be used to create the group."}},"required":["shopifyCollectionId"]}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"409":{"description":"This response is sent when a request conflicts with the current state of the server.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```


# Loyalty

Merchant REST API endpoints related to Okendo Loyalty

## Loyalty

## GET /loyalty/customers

> Retrieve basic details about a Loyalty Customer

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"loyalty"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/loyalty/customers":{"get":{"tags":["loyalty"],"summary":"Retrieve basic details about a Loyalty Customer","parameters":[{"name":"loyaltyCustomerId","description":"The ID of the Loyalty Customer. Note: May not be used in combination with the `email` parameter","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"email","description":"The email address of the Loyalty Customer. Note: May not be used in combination with the `loyaltyCustomerId` parameter","in":"query","schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"An object containing basic details about a Loyalty Customer.","content":{"application/json":{"schema":{"type":"object","properties":{"loyaltyCustomer":{"type":"object","properties":{"loyaltyCustomerId":{"type":"string","format":"uuid"},"minimumVipTierName":{"type":"string"},"points":{"type":"object","properties":{"balance":{"type":"number"}},"required":["balance"]},"status":{"type":"string","enum":["pending","enrolled","blocked"]},"vipTierName":{"type":"string"}},"required":["loyaltyCustomerId","points","status"]}},"required":["loyaltyCustomer"]}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## List ways to earn loyalty points

> Lists the available ways to earn loyalty points. If a Loyalty Customer is specified, this returns ways of earning and amounts tailored to that customer.

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"loyalty"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/loyalty/earning_rules":{"get":{"tags":["loyalty"],"summary":"List ways to earn loyalty points","description":"Lists the available ways to earn loyalty points. If a Loyalty Customer is specified, this returns ways of earning and amounts tailored to that customer.","parameters":[{"name":"loyaltyCustomerId","description":"The ID of the Loyalty Customer. Note: May not be used in combination with the `email` parameter","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"email","description":"The email address of the Loyalty Customer. Note: May not be used in combination with the `loyaltyCustomerId` parameter","in":"query","schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"An object containing a list of earning rules.","content":{"application/json":{"schema":{"type":"object","properties":{"rules":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["fixed-amount"]},"amount":{"type":"number"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["points-per"]},"amount":{"type":"number"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["points-per-spend"]},"amount":{"type":"number"},"waitTimeDays":{"type":"number"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["submit-review"]},"amountForReview":{"type":"number"},"amountForSocialLogin":{"type":"number"},"amountForImage":{"type":"number"},"amountForVideo":{"type":"number"},"capPerOrder":{"type":"number"},"earnEachAmountOncePer":{"type":"string","enum":["order","review"]}},"required":["type","amountForReview","amountForSocialLogin","amountForImage","amountForVideo","earnEachAmountOncePer"]}]}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## List ways to redeem loyalty points for rewards

> Lists the available ways to redeem loyalty points for rewards. If a Loyalty Customer is specified, this returns ways of earning and amounts tailored to that customer.

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"loyalty"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/loyalty/redemption_rules":{"get":{"tags":["loyalty"],"summary":"List ways to redeem loyalty points for rewards","description":"Lists the available ways to redeem loyalty points for rewards. If a Loyalty Customer is specified, this returns ways of earning and amounts tailored to that customer.","parameters":[{"name":"loyaltyCustomerId","description":"The ID of the Loyalty Customer. Note: May not be used in combination with the `email` parameter","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"email","description":"The email address of the Loyalty Customer. Note: May not be used in combination with the `loyaltyCustomerId` parameter","in":"query","schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"An object containing a list of redemption rules.","content":{"application/json":{"schema":{"type":"object","properties":{"rules":{"type":"array","items":{"anyOf":[{"allOf":[{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"The unique identifier for the redemption rule."},"appliesToCollections":{"type":"object","description":"Collections that the redeemed reward will be restricted too when applying.","properties":{"collectionId":{"type":"string","description":"The ID of the Shopify collection."},"title":{"type":"string","description":"The title of the Shopify collection."},"url":{"type":"string","description":"The URL of the Shopify collection."}},"required":["collectionId","title"]},"expiresAfterDays":{"type":"number","description":"The number of days until the redeemed reward expires."},"minimumPurchase":{"type":"number","description":"The minimum purchase amount that the reward will be restricted to."},"purchaseType":{"type":"string","enum":["single","subscription","both"],"description":"The purchase type that the reward will be restricted to. Either `single`, `subscription` or `both`."},"recurringCycleLimit":{"type":"number","description":"The number of subscription payments that the reward will be restricted to."}},"required":["redemptionRuleId"],"description":"An object containing the base parameters for a redemption rule."},{"type":"object","properties":{"type":{"type":"string","enum":["fixed-value"]},"reward":{"type":"object","properties":{"awardVia":{"type":"string","enum":["coupon","store-credit"],"description":"The way the customer is being rewarded. Either `coupon` or `store-credit`."},"points":{"type":"number","description":"The points required to redeem the reward."},"value":{"type":"number","description":"The value of the reward."}},"required":["points","value"]}},"required":["type","reward"]}]},{"allOf":[{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"The unique identifier for the redemption rule."},"appliesToCollections":{"type":"object","description":"Collections that the redeemed reward will be restricted too when applying.","properties":{"collectionId":{"type":"string","description":"The ID of the Shopify collection."},"title":{"type":"string","description":"The title of the Shopify collection."},"url":{"type":"string","description":"The URL of the Shopify collection."}},"required":["collectionId","title"]},"expiresAfterDays":{"type":"number","description":"The number of days until the redeemed reward expires."},"minimumPurchase":{"type":"number","description":"The minimum purchase amount that the reward will be restricted to."},"purchaseType":{"type":"string","enum":["single","subscription","both"],"description":"The purchase type that the reward will be restricted to. Either `single`, `subscription` or `both`."},"recurringCycleLimit":{"type":"number","description":"The number of subscription payments that the reward will be restricted to."}},"required":["redemptionRuleId"],"description":"An object containing the base parameters for a redemption rule."},{"type":"object","properties":{"type":{"type":"string","enum":["percentage-coupon"]},"reward":{"type":"object","properties":{"points":{"type":"number","description":"The points required to redeem the reward."},"value":{"type":"number","description":"The value of the reward."}},"required":["points","value"]}},"required":["type","reward"]}]},{"allOf":[{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"The unique identifier for the redemption rule."},"appliesToCollections":{"type":"object","description":"Collections that the redeemed reward will be restricted too when applying.","properties":{"collectionId":{"type":"string","description":"The ID of the Shopify collection."},"title":{"type":"string","description":"The title of the Shopify collection."},"url":{"type":"string","description":"The URL of the Shopify collection."}},"required":["collectionId","title"]},"expiresAfterDays":{"type":"number","description":"The number of days until the redeemed reward expires."},"minimumPurchase":{"type":"number","description":"The minimum purchase amount that the reward will be restricted to."},"purchaseType":{"type":"string","enum":["single","subscription","both"],"description":"The purchase type that the reward will be restricted to. Either `single`, `subscription` or `both`."},"recurringCycleLimit":{"type":"number","description":"The number of subscription payments that the reward will be restricted to."}},"required":["redemptionRuleId"],"description":"An object containing the base parameters for a redemption rule."},{"type":"object","properties":{"type":{"type":"string","enum":["variable-value"]},"reward":{"type":"object","properties":{"awardVia":{"type":"string","enum":["coupon","store-credit"],"description":"The way the customer is being rewarded. Either `coupon` or `store-credit`."},"points":{"type":"number","description":"The points required to redeem the reward."},"value":{"type":"number","description":"The value of the reward."},"minimumPoints":{"type":"number","description":"The minimum points that can be spent for this reward."},"maximumPoints":{"type":"number","description":"The maximum points that can be spent for this reward."}},"required":["points","value"]}},"required":["type","reward"]}]},{"allOf":[{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"The unique identifier for the redemption rule."},"appliesToCollections":{"type":"object","description":"Collections that the redeemed reward will be restricted too when applying.","properties":{"collectionId":{"type":"string","description":"The ID of the Shopify collection."},"title":{"type":"string","description":"The title of the Shopify collection."},"url":{"type":"string","description":"The URL of the Shopify collection."}},"required":["collectionId","title"]},"expiresAfterDays":{"type":"number","description":"The number of days until the redeemed reward expires."},"minimumPurchase":{"type":"number","description":"The minimum purchase amount that the reward will be restricted to."},"purchaseType":{"type":"string","enum":["single","subscription","both"],"description":"The purchase type that the reward will be restricted to. Either `single`, `subscription` or `both`."},"recurringCycleLimit":{"type":"number","description":"The number of subscription payments that the reward will be restricted to."}},"required":["redemptionRuleId"],"description":"An object containing the base parameters for a redemption rule."},{"type":"object","properties":{"type":{"type":"string","enum":["free-shipping"]},"reward":{"type":"object","properties":{"points":{"type":"number","description":"The points required to redeem the reward."},"maximumShipping":{"type":"number","description":"The maximum shipping value that the reward can apply to."}},"required":["points"]}},"required":["type","reward"]}]},{"allOf":[{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"The unique identifier for the redemption rule."},"appliesToCollections":{"type":"object","description":"Collections that the redeemed reward will be restricted too when applying.","properties":{"collectionId":{"type":"string","description":"The ID of the Shopify collection."},"title":{"type":"string","description":"The title of the Shopify collection."},"url":{"type":"string","description":"The URL of the Shopify collection."}},"required":["collectionId","title"]},"expiresAfterDays":{"type":"number","description":"The number of days until the redeemed reward expires."},"minimumPurchase":{"type":"number","description":"The minimum purchase amount that the reward will be restricted to."},"purchaseType":{"type":"string","enum":["single","subscription","both"],"description":"The purchase type that the reward will be restricted to. Either `single`, `subscription` or `both`."},"recurringCycleLimit":{"type":"number","description":"The number of subscription payments that the reward will be restricted to."}},"required":["redemptionRuleId"],"description":"An object containing the base parameters for a redemption rule."},{"type":"object","properties":{"type":{"type":"string","enum":["free-product"]},"reward":{"type":"object","properties":{"points":{"type":"number","description":"The points required to redeem the reward."},"productAndVariants":{"type":"object","properties":{"product":{"type":"object","properties":{"id":{"type":"string","description":"The Shopify ID of the product."},"name":{"type":"string","description":"The name of the product."},"imageUrl":{"type":"string","description":"The URL of the image of the product."},"url":{"type":"string","description":"The URL of the product."}},"required":["id","name"]},"variants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"The Shopify ID of the variant."},"title":{"type":"string","description":"The title of the product variant."}},"required":["id","title"]}}},"required":["product"]}},"required":["points","productAndVariants"]}},"required":["type","reward"]}]}]}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## List active coupons for a loyalty customer

> Lists the active coupons for a customer. If a Loyalty Customer is specified, this returns the most recent coupons that have not been used for that customer.

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"loyalty"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/loyalty/coupons":{"get":{"tags":["loyalty"],"summary":"List active coupons for a loyalty customer","description":"Lists the active coupons for a customer. If a Loyalty Customer is specified, this returns the most recent coupons that have not been used for that customer.","parameters":[{"description":"A limit on the number of items returned. Between 1 and 100. Default 25.","in":"query","name":"limit","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"lastEvaluated","description":"The URL-encoded JSON object representing the cursor for the next page of results.","in":"query","required":false,"schema":{"type":"string"}},{"name":"loyaltyCustomerId","description":"The ID of the Loyalty Customer. Note: May not be used in combination with the `email` parameter","in":"query","schema":{"type":"string","format":"uuid"}},{"name":"email","description":"The email address of the Loyalty Customer. Note: May not be used in combination with the `loyaltyCustomerId` parameter","in":"query","schema":{"type":"string","format":"email"}}],"responses":{"200":{"description":"An object containing a list of coupons.","content":{"application/json":{"schema":{"type":"object","properties":{"coupons":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"description":{"type":"string"},"appliesToCollectionIds":{"type":"array","items":{"type":"string"}},"appliesToProductIds":{"type":"array","items":{"type":"string"}},"displayType":{"type":"string"},"expiryDate":{"type":"string","format":"date-time"},"maximumShipping":{"type":"number"},"minimumPurchase":{"type":"number"},"purchaseType":{"type":"string"},"recurringCycleLimit":{"type":"number"},"value":{"type":"number"},"valueType":{"type":"string"}},"required":["code","description"]}},"nextUrl":{"type":"string","format":"uri"}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## POST /loyalty/adjustment\_transactions

> Adjust the points balance of a Loyalty Customer

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"loyalty"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/loyalty/adjustment_transactions":{"post":{"tags":["loyalty"],"summary":"Adjust the points balance of a Loyalty Customer","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"customerIdentifier":{"type":"object","oneOf":[{"properties":{"loyaltyCustomerId":{"type":"string","format":"uuid"}},"required":["loyaltyCustomerId"]},{"properties":{"email":{"type":"string","format":"email"}},"required":["email"]}],"description":"An object identifying the Loyalty Customer by `email` or `loyaltyCustomerId`."},"amount":{"description":"The number of points by which the customer's points balance is to be adjusted. Specify either a positive number to add points or a negative number to remove points.","type":"integer","format":"int32"},"internalReason":{"type":"string","description":"Description of the transaction which is displayed to the store owner."},"notificationText":{"type":"string","description":"Description of the transaction which is displayed to the Customer."}},"required":["customerIdentifier","amount"]}}},"required":true},"responses":{"200":{"description":"The transaction was successfully created and the Loyalty Customer's points balance was updated.","content":{"application/json":{"schema":{"type":"object","properties":{"loyaltyCustomer":{"type":"object","properties":{"points":{"type":"object","properties":{"balance":{"type":"number"}}}}}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## POST /loyalty/earning\_transactions

> Trigger a custom earning rule for a Loyalty Customer

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"loyalty"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/loyalty/earning_transactions":{"post":{"tags":["loyalty"],"summary":"Trigger a custom earning rule for a Loyalty Customer","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"actionId":{"type":"string","description":"The action ID of the custom earning rule."},"customerIdentifier":{"type":"object","oneOf":[{"properties":{"loyaltyCustomerId":{"type":"string","format":"uuid"}},"required":["loyaltyCustomerId"]},{"properties":{"email":{"type":"string","format":"email"}},"required":["email"]}],"description":"An object identifying the Loyalty Customer by `email` or `loyaltyCustomerId`."},"value":{"type":"number","description":"The value to be multiplied with the 'points per' value. Required for Custom Points Per Value Rules."}},"required":["actionId","customerIdentifier"]}}},"required":true},"responses":{"200":{"description":"The transaction was successfully created and the Customer was awarded points based on the configured earning rule.","content":{"application/json":{"schema":{"type":"object","properties":{"pointsEarned":{"format":"int64","type":"integer"},"loyaltyCustomer":{"type":"object","properties":{"loyaltyCustomerId":{"format":"uuid","type":"string"},"points":{"type":"object","properties":{"balance":{"type":"number"}}}}}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## POST /loyalty/redemption\_transactions

> Redeem a redemption reward for a Loyalty Customer

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"loyalty"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/loyalty/redemption_transactions":{"post":{"tags":["loyalty"],"summary":"Redeem a redemption reward for a Loyalty Customer","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"customerIdentifier":{"type":"object","oneOf":[{"properties":{"loyaltyCustomerId":{"type":"string","format":"uuid"}},"required":["loyaltyCustomerId"]},{"properties":{"email":{"type":"string","format":"email"}},"required":["email"]}],"description":"An object identifying the Loyalty Customer by `email` or `loyaltyCustomerId`."},"redemptionRuleId":{"type":"string","format":"uuid","description":"The unique identifier for the redemption rule."},"variableValue":{"type":"object","properties":{"points":{"type":"number","description":"The number of points the customer is redeeming for a variable reward. Must be a positive integer."},"value":{"type":"number","description":"The value of the variable reward being redeemed. Must be a positive number."}},"required":["points","value"]}},"required":["customerIdentifier","redemptionRuleId"]}}},"required":true},"responses":{"200":{"description":"The redemption transaction was successfully created and the Loyalty Customer's points balance was updated.","content":{"application/json":{"schema":{"type":"object","properties":{"loyaltyCustomer":{"type":"object","properties":{"points":{"type":"object","properties":{"balance":{"type":"number","description":"The current points balance of the loyalty customer."}},"required":["balance"]}}},"transactionDetails":{"type":"object","properties":{"amount":{"type":"number","description":"The number of points spent to redeem the reward."}},"required":["amount"]},"reward":{"oneOf":[{"type":"object","properties":{"status":{"type":"string","enum":["completed","pending"],"description":"The status of the reward."},"storeCredit":{"type":"object","properties":{"balanceAmount":{"type":"string","description":"The value of the customer's store credit balance."},"transactionAmount":{"type":"string","description":"The value of the store credit that the customer is being rewarded with."}},"required":["balanceAmount","transactionAmount"]},"type":{"type":"string","enum":["store-credit"],"description":"The reward type."}},"required":["status","type"]},{"type":"object","properties":{"code":{"type":"string","description":"The Shopify coupon code."},"status":{"type":"string","enum":["completed","pending"],"description":"The status of the reward."},"type":{"type":"string","enum":["coupon"],"description":"The reward type."}},"required":["status","type"]}]}},"required":["loyaltyCustomer","transactionDetails"]}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"500":{"description":"Failed to redeem points.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## POST /loyalty/customer\_minimum\_vip\_tiers

> Set a Loyalty Customer's minimum VIP Tier

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"loyalty"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/loyalty/customer_minimum_vip_tiers":{"post":{"tags":["loyalty"],"summary":"Set a Loyalty Customer's minimum VIP Tier","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"customerIdentifier":{"type":"object","oneOf":[{"properties":{"loyaltyCustomerId":{"type":"string","format":"uuid"}},"required":["loyaltyCustomerId"]},{"properties":{"email":{"type":"string","format":"email"}},"required":["email"]}],"description":"An object identifying the Loyalty Customer by `email` or `loyaltyCustomerId`."},"minimumVipTierName":{"type":"string","nullable":true,"description":"The name of the VIP Tier, or null to remove a previously configured minimum VIP Tier."}},"required":["customerIdentifier","minimumVipTierName"]}}},"required":true},"responses":{"200":{"description":"The Loyalty Customer's minimum VIP Tier was updated, in addition to any resultant change to the current VIP Tier.","content":{"application/json":{"schema":{"type":"object","properties":{"minimumVipTierName":{"type":"string"},"vipTierName":{"type":"string"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```


# Surveys

Merchant REST API endpoints related to Okendo Surveys

## List Survey Responses

> Returns a list of Survey Responses for the requested survey

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"surveys"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/surveys/{surveyId}/responses":{"get":{"tags":["surveys"],"summary":"List Survey Responses","description":"Returns a list of Survey Responses for the requested survey","parameters":[{"name":"surveyId","description":"The ID of the survey to retrieve responses for","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"description":"A limit on the number of items returned. Between 1 and 100. Default 25.","in":"query","name":"limit","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"lastEvaluated","description":"The URL-encoded JSON object representing the cursor for the next page of results.","in":"query","required":false,"schema":{"type":"string"}},{"name":"orderBy","description":"The sort order of the survey responses. Format: '(date) (asc|desc)'. Default 'date desc'","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"An object containing a list of Survey Responses and a relative link to the next page of results if available.","content":{"application/json":{"schema":{"type":"object","properties":{"surveyResponses":{"type":"array","items":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user ID within Okendo.","format":"uuid"},"surveyResponseId":{"type":"string","format":"uuid"},"surveyId":{"type":"string","format":"uuid"},"surveyName":{"type":"string","description":"The name of the survey."},"channelSurveyId":{"type":"string","format":"uuid"},"channelSurveyDescription":{"type":"string","description":"The description of the channel survey."},"channel":{"type":"string","description":"The channel through which the survey was submitted.","enum":["on-site","post-checkout","post-review","shareable-link"]},"answeredQuestions":{"type":"array","items":{"oneOf":[{"allOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."}},"required":["id","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["text"]},"answer":{"type":"string"}},"required":["type"]}]},{"allOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."}},"required":["id","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["single-select"]},"answer":{"type":"string"},"customAnswer":{"type":"string","description":"Custom answer text provided by the respondent."},"customAnswerOptionText":{"type":"string","description":"Text for the custom answer option."}},"required":["type","answer"]}]},{"allOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."}},"required":["id","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["multi-select"]},"answer":{"type":"array","items":{"type":"string"}},"customAnswer":{"type":"string","description":"Custom answer text provided by the respondent."},"customAnswerOptionText":{"type":"string","description":"Text for the custom answer option."}},"required":["type","answer"]}]},{"allOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."}},"required":["id","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["five-point","star"]},"answer":{"type":"number"}},"required":["type","answer"]}]},{"allOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."}},"required":["id","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["nps"]},"answer":{"type":"number"},"answerNpsCategory":{"type":"string","enum":["promoter","detractor","passive"]}},"required":["type","answer","answerNpsCategory"]}]},{"allOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."}},"required":["id","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["profile"]},"answer":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["date-components"]},"value":{"type":"object","properties":{"day":{"type":"integer","minimum":1,"maximum":31},"month":{"type":"integer","minimum":1,"maximum":12},"year":{"type":"integer","minimum":1900,"maximum":2100}},"description":"Date components value."}},"required":["type","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["location"]},"value":{"type":"object","properties":{"countryCode":{"type":"string","description":"Country code."},"countryName":{"type":"string","description":"Country name."},"zoneCode":{"type":"string","description":"State, province, or zone code."}},"required":["countryCode"],"description":"Location value."}},"required":["type","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["multi-value"]},"value":{"type":"array","items":{"type":"string"},"description":"The selected values."}},"required":["type","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["single-value"]},"value":{"type":"string","description":"The selected value."}},"required":["type","value"]}],"discriminator":{"propertyName":"type","mapping":{"date-components":"#/ProfileDateComponents","location":"#/ProfileLocation","multi-value":"#/ProfileMultiValue","single-value":"#/ProfileSingleValue"}},"description":"The profile answer data provided."},"profileQuestionId":{"type":"string","format":"uuid"}},"required":["type","answer","profileQuestionId"]}]},{"allOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."}},"required":["id","text"]},{"type":"object","properties":{"type":{"type":"string","enum":["email"]},"answer":{"type":"string","format":"email"},"marketingOptIn":{"type":"boolean"}},"required":["type","answer"]}]}],"discriminator":{"propertyName":"type","mapping":{"text":"#/TextAnswer","single-select":"#/SingleSelectAnswer","multi-select":"#/MultiSelectAnswer","five-point":"#/NumberAnswer","star":"#/NumberAnswer","nps":"#/NpsAnswer","profile":"#/ProfileAnswer","email":"#/EmailAnswer"}}}},"customer":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"}}},"dateCreated":{"type":"string","format":"date-time"},"emailMarketingOptIn":{"type":"boolean","description":"Whether the customer opted in to email marketing."},"isArchived":{"type":"boolean","description":"Whether the survey response has been archived."},"order":{"type":"object","properties":{"remoteOrderId":{"type":"string","description":"The numeric order ID from Shopify."}}},"reward":{"type":"object","properties":{"type":{"type":"string","enum":["coupon"]},"description":{"type":"string","description":"Description of the reward."},"value":{"type":"string","description":"The coupon code or reward value."}},"required":["type","description","value"]}},"required":["subscriberId","surveyResponseId","surveyId","surveyName","channelSurveyId","channel","answeredQuestions","dateCreated"]}},"nextUrl":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```


# Quizzes

Merchant REST API endpoints related to Okendo Quizzes

## List Quiz Responses

> Returns a list of Quiz Responses for the requested quiz

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[{"name":"quizzes"}],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/quizzes/{quizId}/responses":{"get":{"tags":["quizzes"],"summary":"List Quiz Responses","description":"Returns a list of Quiz Responses for the requested quiz","parameters":[{"name":"quizId","description":"The ID of the quiz to retrieve responses for","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"description":"A limit on the number of items returned. Between 1 and 100. Default 25.","in":"query","name":"limit","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"lastEvaluated","description":"The URL-encoded JSON object representing the cursor for the next page of results.","in":"query","required":false,"schema":{"type":"string"}},{"name":"orderBy","description":"The sort order of the quiz responses. Format: '(date) (asc|desc)'. Default 'date desc'","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"An object containing a list of Quiz Responses and a relative link to the next page of results if available.","content":{"application/json":{"schema":{"type":"object","properties":{"quizResponses":{"type":"array","items":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user ID within Okendo.","format":"uuid"},"quizResponseId":{"type":"string","format":"uuid"},"quizId":{"type":"string","format":"uuid"},"quizName":{"type":"string","description":"The name of the quiz."},"channel":{"type":"string","description":"The channel through which the quiz was submitted.","enum":["on-site","on-site-embed"]},"answeredQuestions":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."},"type":{"type":"string","enum":["multiple-select"]},"answer":{"type":"array","items":{"type":"string"},"description":"The selected answer options."},"customAnswer":{"type":"string","description":"Custom answer text provided by the respondent."},"customAnswerOptionText":{"type":"string","description":"Text for the custom answer option."}},"required":["id","text","type","answer"]},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."},"type":{"type":"string","enum":["five-point","star"]},"answer":{"type":"number","description":"The numeric answer provided."}},"required":["id","text","type","answer"]},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."},"type":{"type":"string","enum":["profile"]},"answer":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["date-components"]},"value":{"type":"object","properties":{"day":{"type":"integer","minimum":1,"maximum":31},"month":{"type":"integer","minimum":1,"maximum":12},"year":{"type":"integer","minimum":1900,"maximum":2100}},"description":"Date components value."}},"required":["type","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["location"]},"value":{"type":"object","properties":{"countryCode":{"type":"string","description":"Country code."},"countryName":{"type":"string","description":"Country name."},"zoneCode":{"type":"string","description":"State, province, or zone code."}},"required":["countryCode"],"description":"Location value."}},"required":["type","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["multi-value"]},"value":{"type":"array","items":{"type":"string"},"description":"The selected values."}},"required":["type","value"]},{"type":"object","properties":{"type":{"type":"string","enum":["single-value"]},"value":{"type":"string","description":"The selected value."}},"required":["type","value"]}],"discriminator":{"propertyName":"type","mapping":{"date-components":"#/ProfileDateComponents","location":"#/ProfileLocation","multi-value":"#/ProfileMultiValue","single-value":"#/ProfileSingleValue"}},"description":"The profile answer data provided."},"profileQuestionId":{"type":"string","format":"uuid"}},"required":["id","text","type","answer","profileQuestionId"]},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","description":"The question text."},"type":{"type":"string","enum":["single-select"]},"answer":{"type":"string","description":"The selected answer option."},"customAnswer":{"type":"string","description":"Custom answer text provided by the respondent."},"customAnswerOptionText":{"type":"string","description":"Text for the custom answer option."}},"required":["id","text","type","answer"]}],"discriminator":{"propertyName":"type","mapping":{"multiple-select":"#/QuizMultiSelectAnswer","five-point":"#/QuizNumberAnswer","star":"#/QuizNumberAnswer","profile":"#/QuizProfileAnswer","single-select":"#/QuizSingleSelectAnswer"}}}},"customer":{"type":"object","properties":{"customerId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"}}},"dateCreated":{"type":"string","format":"date-time"},"emailMarketingOptIn":{"type":"boolean","description":"Whether the customer opted in to email marketing."},"order":{"type":"object","properties":{"remoteOrderId":{"type":"string","description":"The numeric order ID from Shopify."}}},"recommendation":{"oneOf":[{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["conditional-outcomes"]},"outcomeId":{"type":"string","format":"uuid","description":"The unique identifier for the outcome."},"outcomeType":{"type":"string","enum":["redirect"]},"outcomeInternalName":{"type":"string","description":"Internal name of the outcome."},"outcomeTitle":{"type":"string","description":"Title of the outcome."},"redirectUrl":{"type":"string","format":"uri","description":"URL to redirect to."}},"required":["type","outcomeId","outcomeType","outcomeTitle","redirectUrl"]},{"type":"object","properties":{"type":{"type":"string","enum":["conditional-outcomes"]},"outcomeId":{"type":"string","format":"uuid","description":"The unique identifier for the outcome."},"outcomeType":{"type":"string","enum":["products"]},"outcomeInternalName":{"type":"string","description":"Internal name of the outcome."},"outcomeTitle":{"type":"string","description":"Title of the outcome."},"recommendedProducts":{"type":"array","items":{"type":"object","properties":{"remoteProductId":{"type":"string","description":"The numeric product ID from Shopify."},"defaultRemoteVariantId":{"type":"string","description":"The default numeric variant ID from Shopify."},"remoteVariantIds":{"type":"array","items":{"type":"string"},"description":"The numeric variant IDs from Shopify."}},"required":["remoteProductId"]},"description":"List of recommended products."}},"required":["type","outcomeId","outcomeType","outcomeTitle","recommendedProducts"]}],"discriminator":{"propertyName":"outcomeType","mapping":{"redirect":"#/QuizOutcomeRedirect","products":"#/QuizOutcomeResult"}}},{"type":"object","properties":{"type":{"type":"string","enum":["weighted-products"]},"recommendedProducts":{"type":"array","items":{"type":"object","properties":{"product":{"type":"object","properties":{"remoteProductId":{"type":"string","description":"The numeric product ID from Shopify."},"defaultRemoteVariantId":{"type":"string","description":"The default numeric variant ID from Shopify."},"remoteVariantIds":{"type":"array","items":{"type":"string"},"description":"The numeric variant IDs from Shopify."}},"required":["remoteProductId"]},"points":{"type":"number","description":"Points assigned to this product."}},"required":["product","points"]},"description":"List of recommended products with points."},"runnerUpProducts":{"type":"array","items":{"type":"object","properties":{"product":{"type":"object","properties":{"remoteProductId":{"type":"string","description":"The numeric product ID from Shopify."},"defaultRemoteVariantId":{"type":"string","description":"The default numeric variant ID from Shopify."},"remoteVariantIds":{"type":"array","items":{"type":"string"},"description":"The numeric variant IDs from Shopify."}},"required":["remoteProductId"]},"points":{"type":"number","description":"Points assigned to this product."}},"required":["product","points"]},"description":"List of runner-up products with points."}},"required":["type","recommendedProducts","runnerUpProducts"]},{"type":"object","properties":{"type":{"type":"string","enum":["weighted-tags"]},"recommendedProducts":{"type":"array","items":{"type":"object","properties":{"product":{"type":"object","properties":{"remoteProductId":{"type":"string","description":"The numeric product ID from Shopify."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags associated with the product."}},"required":["remoteProductId","tags"]},"points":{"type":"number","description":"Points assigned to this product."}},"required":["product","points"]},"description":"List of recommended products with tags and points."},"runnerUpProducts":{"type":"array","items":{"type":"object","properties":{"product":{"type":"object","properties":{"remoteProductId":{"type":"string","description":"The numeric product ID from Shopify."},"tags":{"type":"array","items":{"type":"string"},"description":"Tags associated with the product."}},"required":["remoteProductId","tags"]},"points":{"type":"number","description":"Points assigned to this product."}},"required":["product","points"]},"description":"List of runner-up products with tags and points."}},"required":["type","recommendedProducts","runnerUpProducts"]}],"discriminator":{"propertyName":"type","mapping":{"conditional-outcomes":"#/QuizConditionalOutcomeRecommendation","weighted-products":"#/QuizWeightedProductsRecommendation","weighted-tags":"#/QuizWeightedTagsRecommendation"}}},"reward":{"type":"object","properties":{"type":{"type":"string","enum":["coupon"],"description":"The type of reward."},"description":{"type":"string","description":"Description of the reward."},"value":{"type":"string","description":"The coupon code."}},"required":["type","description","value"]}},"required":["subscriberId","quizResponseId","quizId","quizName","channel","answeredQuestions","dateCreated","recommendation"]}},"nextUrl":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```


# Customers

Endpoints related to customer profiles in Okendo

## Customers

## POST /customer\_lookup

> Look up a Customer's ID by email address

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/customer_lookup":{"post":{"tags":["customers"],"summary":"Look up a Customer's ID by email address","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"description":"The email address of the Customer to look up.","format":"email","type":"string"}},"required":["email"]}}},"required":true},"responses":{"200":{"description":"A Customer was found matching the provided email address.","content":{"application/json":{"schema":{"type":"object","properties":{"customerId":{"format":"uuid","type":"string"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## GET /customers/{customerId}

> Retrieve basic details about a Customer

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/customers/{customerId}":{"get":{"tags":["customers"],"summary":"Retrieve basic details about a Customer","parameters":[{"name":"customerId","description":"The ID of the Customer to retrieve. Use the /customer_lookup endpoint to get the Customer's ID.","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"An object containing basic details about a Customer.","content":{"application/json":{"schema":{"type":"object","properties":{"dateFirstActive":{"description":"The date of the Customer's first action.","format":"date-time","type":"string"},"dateLastActive":{"description":"The date of the Customer's most recent action.","format":"date-time","type":"string"},"email":{"description":"The email address of the customer.","format":"email","type":"string"},"givenName":{"description":"The given name of the customer. Often also known as the first name.","type":"string"},"familyName":{"description":"The family name of the customer. Often also known as the last name.","type":"string"},"avatarUrl":{"description":"The URL of the Customer's current avatar / profile picture.","format":"uri","type":"string"},"location":{"type":"object","properties":{"country":{"description":"The name of the Customer's country."},"zoneCode":{"description":"The code identifying the Customer's state or province."}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## List Customer Profiles and their included properties

> A Customer Profile is a collection of data points (grouped by namespace) about a specific Customer.

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/customers/{customerId}/profiles":{"get":{"tags":["customers"],"summary":"List Customer Profiles and their included properties","description":"A Customer Profile is a collection of data points (grouped by namespace) about a specific Customer.","parameters":[{"description":"A limit on the number of items returned. Between 1 and 100. Default 25.","in":"query","name":"limit","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"lastEvaluated","description":"The URL-encoded JSON object representing the cursor for the next page of results.","in":"query","required":false,"schema":{"type":"string"}},{"name":"customerId","description":"The ID of the Customer to retrieve. Use the /customer_lookup endpoint to get the Customer's ID.","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"namespace","description":"The identifier used to group Customer data. Specify this property to filter the Customer's profile data to a specific namespace.","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"An object containing a list of Customer Profiles and a relative link to the next page of results if available.","content":{"application/json":{"schema":{"type":"object","properties":{"profiles":{"type":"array","items":{"type":"object","properties":{"namespace":{"description":"An identifier used to group Customer data.","type":"string"},"properties":{"description":"The date of the customer's most recent action.","type":"array","items":{"type":"object","properties":{"name":{"description":"The name of the property.","type":"string"},"value":{"description":"The value of the property.","type":"string"},"valueType":{"description":"The type of the property value. One of 'boolean', 'number', 'string', 'string-list', 'date', 'date-components', 'location' or 'image'.","type":"string"},"date":{"description":"The date that the property value was current.","type":"string","format":"date-time"}}}}}}},"nextUrl":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."}}}}}}
```

## List Customer Activities

> A Customer Activity is an action that the Customer has taken or an action that relates to the Customer.

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/customers/{customerId}/activities":{"get":{"tags":["customers"],"summary":"List Customer Activities","description":"A Customer Activity is an action that the Customer has taken or an action that relates to the Customer.","parameters":[{"description":"A limit on the number of items returned. Between 1 and 100. Default 25.","in":"query","name":"limit","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"lastEvaluated","description":"The URL-encoded JSON object representing the cursor for the next page of results.","in":"query","required":false,"schema":{"type":"string"}},{"name":"customerId","description":"The ID of the Customer to retrieve. Use the /customer_lookup endpoint to get the Customer's ID.","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"namespace","description":"The identifier used to group Customer data. Specify this property to filter the Customer's activities to a specific namespace.","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"An object containing a list of Customer Activities and a relative link to the next page of results if available.","content":{"application/json":{"schema":{"type":"object","properties":{"activities":{"type":"array","items":{"type":"object","properties":{"activityId":{"description":"The ID of the Activity.","type":"string","format":"uuid"},"namespace":{"description":"An identifier used to group Customer data.","type":"string"},"date":{"description":"The date that the Activity occurred.","type":"string","format":"date-time"},"title":{"description":"The title of the Activity.","type":"string"}}}},"nextUrl":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."}}}}}}
```


# Webhooks

Endpoints to manage Okendo webhooks

## Webhooks

## List Webhook Subscriptions

> Returns a list of Webhook Subscriptions

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/webhook_subscriptions":{"get":{"tags":["webhook subscriptions"],"summary":"List Webhook Subscriptions","description":"Returns a list of Webhook Subscriptions","parameters":[{"description":"A limit on the number of items returned. Between 1 and 100. Default 25.","in":"query","name":"limit","required":false,"schema":{"type":"integer","format":"int32"}},{"name":"lastEvaluated","description":"The URL-encoded JSON object representing the cursor for the next page of results.","in":"query","required":false,"schema":{"type":"string"}},{"name":"orderBy","description":"The sort order of the webhook subscriptions. Format: 'asc|desc'. Default 'desc'","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"An object containing a list of Webhook Subscriptions and a relative link to the next page of results if available.","content":{"application/json":{"schema":{"type":"object","properties":{"webhookSubscriptions":{"type":"array","items":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user ID within Okendo.","format":"uuid"},"webhookSubscriptionId":{"type":"string","format":"uuid"},"endpointUrl":{"type":"string","format":"uri","description":"The URL that the webhook event will be sent to"},"version":{"type":"string","description":"Webhook event version","enum":["2025-02-01"]},"subscriptions":{"type":"array","items":{"type":"object","properties":{"resourceType":{"type":"string","description":"The webhook resource type","enum":["review","loyalty_adjustment_transaction","loyalty_customer","loyalty_earning_transaction","loyalty_redemption_transaction"]},"topic":{"type":"string","description":"The topic of the webhook","enum":["create","update","delete"]}}}},"isEnabled":{"type":"boolean"},"dateCreated":{"type":"string","format":"date-time"},"dateModified":{"type":"string","format":"date-time"}}}},"nextUrl":{"type":"string","format":"uri"}}}}}},"400":{"description":"Invalid request parameters.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## POST /webhook\_subscriptions

> Create a Webhook Subscription

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/webhook_subscriptions":{"post":{"tags":["webhook subscriptions"],"summary":"Create a Webhook Subscription","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"endpointUrl":{"type":"string","format":"uri","description":"The URL that the webhook event will be sent to"},"isEnabled":{"type":"boolean"},"subscriptions":{"type":"array","items":{"type":"object","properties":{"resourceType":{"type":"string","description":"The webhook resource type","enum":["review","loyalty_adjustment_transaction","loyalty_customer","loyalty_earning_transaction","loyalty_redemption_transaction"]},"topic":{"type":"string","description":"The topic of the webhook","enum":["create","update","delete"]}}}},"version":{"type":"string","description":"Webhook event version","enum":["2025-02-01"]}},"required":["endpointUrl","isEnabled","version","subscriptions"]}}}},"responses":{"200":{"description":"A new Webhook Subscription object which also contains the Webhook Secret","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user ID within Okendo.","format":"uuid"},"webhookSubscriptionId":{"type":"string","format":"uuid"},"endpointUrl":{"type":"string","format":"uri","description":"The URL that the webhook event will be sent to"},"version":{"type":"string","description":"Webhook event version","enum":["2025-02-01"]},"subscriptions":{"type":"array","items":{"type":"object","properties":{"resourceType":{"type":"string","description":"The webhook resource type","enum":["review","loyalty_adjustment_transaction","loyalty_customer","loyalty_earning_transaction","loyalty_redemption_transaction"]},"topic":{"type":"string","description":"The topic of the webhook","enum":["create","update","delete"]}}}},"isEnabled":{"type":"boolean"},"dateCreated":{"type":"string","format":"date-time"},"dateModified":{"type":"string","format":"date-time"}}},{"type":"object","properties":{"webhookSecret":{"type":"string","description":"Webhook Subscription Secret used to verify the Webhook Event"}}}]}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## GET /webhook\_subscriptions/{webhookSubscriptionId}

> Retrieve a Webhook Subscription

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/webhook_subscriptions/{webhookSubscriptionId}":{"get":{"tags":["webhook subscriptions"],"summary":"Retrieve a Webhook Subscription","parameters":[{"name":"webhookSubscriptionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"A Webhook Subscription Object","content":{"application/json":{"schema":{"type":"object","properties":{"webhookSubscription":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user ID within Okendo.","format":"uuid"},"webhookSubscriptionId":{"type":"string","format":"uuid"},"endpointUrl":{"type":"string","format":"uri","description":"The URL that the webhook event will be sent to"},"version":{"type":"string","description":"Webhook event version","enum":["2025-02-01"]},"subscriptions":{"type":"array","items":{"type":"object","properties":{"resourceType":{"type":"string","description":"The webhook resource type","enum":["review","loyalty_adjustment_transaction","loyalty_customer","loyalty_earning_transaction","loyalty_redemption_transaction"]},"topic":{"type":"string","description":"The topic of the webhook","enum":["create","update","delete"]}}}},"isEnabled":{"type":"boolean"},"dateCreated":{"type":"string","format":"date-time"},"dateModified":{"type":"string","format":"date-time"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## PUT /webhook\_subscriptions/{webhookSubscriptionId}

> Update a Webhook Subscription

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/webhook_subscriptions/{webhookSubscriptionId}":{"put":{"tags":["webhook subscriptions"],"summary":"Update a Webhook Subscription","parameters":[{"name":"webhookSubscriptionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"endpointUrl":{"type":"string","format":"uri","description":"The URL that the webhook event will be sent to"},"subscriptions":{"type":"array","items":{"type":"object","properties":{"resourceType":{"type":"string","description":"The webhook resource type","enum":["review","loyalty_adjustment_transaction","loyalty_customer","loyalty_earning_transaction","loyalty_redemption_transaction"]},"topic":{"type":"string","description":"The topic of the webhook","enum":["create","update","delete"]}}}},"version":{"type":"string","description":"Webhook event version","enum":["2025-02-01"]},"isEnabled":{"type":"boolean"}}}}}},"responses":{"200":{"description":"An updated Webhook Subscription Object","content":{"application/json":{"schema":{"type":"object","properties":{"webhookSubscription":{"type":"object","properties":{"subscriberId":{"type":"string","description":"Your user ID within Okendo.","format":"uuid"},"webhookSubscriptionId":{"type":"string","format":"uuid"},"endpointUrl":{"type":"string","format":"uri","description":"The URL that the webhook event will be sent to"},"version":{"type":"string","description":"Webhook event version","enum":["2025-02-01"]},"subscriptions":{"type":"array","items":{"type":"object","properties":{"resourceType":{"type":"string","description":"The webhook resource type","enum":["review","loyalty_adjustment_transaction","loyalty_customer","loyalty_earning_transaction","loyalty_redemption_transaction"]},"topic":{"type":"string","description":"The topic of the webhook","enum":["create","update","delete"]}}}},"isEnabled":{"type":"boolean"},"dateCreated":{"type":"string","format":"date-time"},"dateModified":{"type":"string","format":"date-time"}}}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## DELETE /webhook\_subscriptions/{webhookSubscriptionId}

> Delete a Webhook subscription

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/webhook_subscriptions/{webhookSubscriptionId}":{"delete":{"tags":["webhook subscriptions"],"summary":"Delete a Webhook subscription","parameters":[{"name":"webhookSubscriptionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"204":{"description":"The resource was deleted successfully."},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## POST /webhook\_subscriptions/{webhookSubscriptionId}/rotate\_secret

> Rotate a Webhook Subscription Secret

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/webhook_subscriptions/{webhookSubscriptionId}/rotate_secret":{"post":{"tags":["webhook subscriptions"],"summary":"Rotate a Webhook Subscription Secret","parameters":[{"name":"webhookSubscriptionId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"An object containing a Webhook Subscription Secret","content":{"application/json":{"schema":{"type":"object","properties":{"webhookSubscriptionSecret":{"type":"string","description":"Webhook Subscription Secret used to verify a Webhook Event"}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```


# Settings

Endpoints related to managing Okendo settings

## Review Translation Settings

## POST /review\_translation\_settings

> Update Subscriber Review Translation Settings

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/review_translation_settings":{"post":{"tags":["Subscriber Review Translation Settings"],"summary":"Update Subscriber Review Translation Settings","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"isGlobalTermsBlocklistEnabled":{"type":"boolean","description":"A flag which is used to determine whether the Subscriber Review Translation Blocklist will be used when translating Reviews"},"isProductTermsBlocklistEnabled":{"type":"boolean","description":"A flag which is used to determine whether Product Review Translation Blocklist will be used when translating Reviews"}},"required":["isGlobalTermsBlocklistEnabled","isProductTermsBlocklistEnabled"]}}}},"responses":{"200":{"description":"Updated Subscriber Review Translation Settings Object","content":{"application/json":{"schema":{"type":"object","properties":{"isGlobalTermsBlocklistEnabled":{"type":"boolean","description":"A flag which is used to determine whether the Subscriber Review Translation Blocklist will be used when translating Reviews"},"isProductTermsBlocklistEnabled":{"type":"boolean","description":"A flag which is used to determine whether Product Review Translation Blocklist will be used when translating Reviews"}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## GET /review\_translation\_blocklist

> Retrieve a Subscriber Review Translation Blocklist

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/review_translation_blocklist":{"get":{"tags":["Subscriber Review Translation Blocklist"],"summary":"Retrieve a Subscriber Review Translation Blocklist","responses":{"200":{"description":"A Translation Blocklist Object","content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## PUT /review\_translation\_blocklist

> Create/Update a Subscriber Review Translation Blocklist with provided terms

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/review_translation_blocklist":{"put":{"tags":["Subscriber Review Translation Blocklist"],"summary":"Create/Update a Subscriber Review Translation Blocklist with provided terms","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"responses":{"200":{"description":"A Translation Blocklist Object","content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## PATCH /review\_translation\_blocklist

> Append a list of terms to the Subscriber Review Translation Blocklist

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/review_translation_blocklist":{"patch":{"tags":["Subscriber Review Translation Blocklist"],"summary":"Append a list of terms to the Subscriber Review Translation Blocklist","requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"responses":{"200":{"description":"A Translation Blocklist Object","content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## DELETE /review\_translation\_blocklist

> Delete the Subscriber Review Translation Blocklist

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/review_translation_blocklist":{"delete":{"tags":["Subscriber Review Translation Blocklist"],"summary":"Delete the Subscriber Review Translation Blocklist","responses":{"204":{"description":"The resource was deleted successfully."},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## GET /products/{productId}/review\_translation\_blocklist

> Retrieve a Product Review Translation Blocklist

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/products/{productId}/review_translation_blocklist":{"get":{"tags":["Product Review Translation Blocklist"],"summary":"Retrieve a Product Review Translation Blocklist","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string","description":"The product ID prefixed by a platform identifier."}}],"responses":{"200":{"description":"A Translation Blocklist Object","content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## PUT /products/{productId}/review\_translation\_blocklist

> Create/Update a Product Review Translation Blocklist with provided terms

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/products/{productId}/review_translation_blocklist":{"put":{"tags":["Product Review Translation Blocklist"],"summary":"Create/Update a Product Review Translation Blocklist with provided terms","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string","description":"The product ID prefixed by a platform identifier."}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"responses":{"200":{"description":"A Translation Blocklist Object","content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## PATCH /products/{productId}/review\_translation\_blocklist

> Append a list of terms to the Product Review Translation Blocklist

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/products/{productId}/review_translation_blocklist":{"patch":{"tags":["Product Review Translation Blocklist"],"summary":"Append a list of terms to the Product Review Translation Blocklist","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string","description":"The product ID prefixed by a platform identifier."}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"responses":{"200":{"description":"A Translation Blocklist Object","content":{"application/json":{"schema":{"type":"object","properties":{"blocklistedTerms":{"type":"array","items":{"type":"string","maxLength":2048},"description":"Array of blocklisted terms.","maxItems":100}}}}}},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"422":{"description":"The request was well-formed but was unable to be followed due to semantic errors.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```

## DELETE /products/{productId}/review\_translation\_blocklist

> Delete the Product Review Translation Blocklist

```json
{"openapi":"3.0.1","info":{"title":"Okendo Enterprise API","version":"1.2.1"},"tags":[],"servers":[{"url":"https://api.okendo.io/enterprise"}],"security":[{"basic":[]}],"components":{"securitySchemes":{"basic":{"type":"http","scheme":"basic"}}},"paths":{"/products/{productId}/review_translation_blocklist":{"delete":{"tags":["Product Review Translation Blocklist"],"summary":"Delete the Product Review Translation Blocklist","parameters":[{"name":"productId","in":"path","required":true,"schema":{"type":"string","description":"The product ID prefixed by a platform identifier."}}],"responses":{"204":{"description":"The resource was deleted successfully."},"401":{"description":"Authentication credentials are missing or incorrect."},"403":{"description":"The requested resource is forbidden.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}},"404":{"description":"The requested resource could not be found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string"}}}}}}}}}}}}}
```


# On Site Widgets


# Reviews Widget

## Overview

A high-impact, visually stunning review display widget that is proven to engage shoppers and increase conversions. Extensively customizable and optimized for page-load speed.

<figure><img src="/files/YoI9R6fm7Wm2U1MkBw3O" alt=""><figcaption></figcaption></figure>

## Installation

{% tabs %}
{% tab title="Shopify Online Store 2.0" %}
Instructions for a Shopify Online Store 2.0 installation can be found [here](https://support.okendo.io/en/articles/5537298-installing-okendo-on-shopify-online-store-2-0).
{% endtab %}

{% tab title="Shopify Vintage Theme" %}

1. Create a new liquid snippet in the snippets folder with the following name: `snippets/okendo-reviews-widget.liquid`
2. Inside your newly created liquid file, add the following HTML snippet:

   ```tsx
   <div data-oke-widget></div>
   ```
3. Customize your snippet with the data attributes listed [here](#reviews-widget-data-attributes).
4. Copy the following snippet and place it in your Theme Code where you would like the widget to appear: `{% render 'okendo-reviews-widget', product: product %}`

For more detailed instructions, read our [help centre article](https://support.okendo.io/en/articles/1770332-setting-up-okendo-reviews-on-shopify-vintage-themes).
{% endtab %}
{% endtabs %}

## Styling

The preferred method of configuring the Reviews Widget is via the Okendo Admin which can be accessed in the Okendo app via Reviews -> On-Site Displays:

<figure><img src="/files/0WflgytBkmWDhOcfaZgf" alt=""><figcaption></figcaption></figure>

## Data Attributes

Use these data attributes on the widget markup to customize its configuration. None of these attributes are required.

<table><thead><tr><th width="220">Data Attribute</th><th width="206">Description</th><th width="119">Value Type</th><th>Supported Values</th></tr></thead><tbody><tr><td><code>data-oke-reviews-product-id</code></td><td>Used to specify a Shopify Product ID with the word <code>shopify-</code> in front of it. The reviews widget will only show reviews for the specified product.</td><td><code>string</code></td><td>Any valid product ID in the format <code>shopify-</code> e.g. <code>shopify-1234567</code>.</td></tr><tr><td><code>data-oke-reviews-group-id</code></td><td>Used to specify an Okendo Group ID so that the reviews widget only shows reviews for the specified group of products.</td><td><code>string</code></td><td>Any valid product group ID in a GUID format e.g. <code>69d2e67d-b980-4333-97b7-30411807a7b1</code></td></tr><tr><td><code>data-oke-reviews-ask-question-product-id</code></td><td>Used to show the “Ask a Question” in the reviews widget to leave a question for the specified product.</td><td><code>string</code></td><td>Any valid product ID in the format <code>shopify-</code> e.g. <code>shopify-1234567</code>.</td></tr><tr><td><code>data-oke-reviews-write-review-product-id</code></td><td>Used to show the “Write a Review” in the reviews widget to write a review for the specified product.</td><td><code>string</code></td><td>Any valid product ID in the format <code>shopify-</code> e.g. <code>shopify-1234567</code>.</td></tr><tr><td><code>data-oke-order-by-tag-id</code></td><td>Used to sort the widget by a given featured tag id that has been exposed as a public tag</td><td><code>string</code></td><td>A tag ID copied from the On Site Displays -> Reviews Widget -> Reviews List tag picker.<br><br><a href="#creating-curated-review-widgets-using-feature-tags">See the section below for more details.</a></td></tr></tbody></table>

## Examples

### **Giving The Widget A Data Source**

Without specifying a data source for the reviews, the widget will show **all** reviews for your store. You can provide either a Product ID or a Group ID to use that as the data source for the reviews.

#### **Product Widget**

```html
<div data-oke-widget data-oke-reviews-product-id="shopify-<PRODUCT_ID>"></div>
```

The product widget also has some pre-rendered content stored in Shopify Metafields that we recommend including for increased performance on-site:

If you are using **liquid** use the following snippet:

```
<div data-oke-widget data-oke-reviews-product-id="shopify-{{ product.id }}">
    {{ product.metafields.okendo.ReviewsWidgetSnippet }}
</div>
```

The general format for other frameworks is:

```html
<div data-oke-widget data-oke-reviews-product-id="shopify-<PRODUCT_ID>">
    <!-- 
    Retrieve the product.metafields.okendo.ReviewsWidgetSnippet via Shopify's GraphQL/REST API
    and put the contents here
    -->
</div>
```

#### Grouped **Widget**

Learn more about Okendo Groups here:

{% embed url="<https://support.okendo.io/en/articles/3086139-understanding-okendo-groups>" %}

If you are using **liquid or general frameworks** use the following snippet:

```
<div data-oke-widget data-oke-reviews-group-id="<GROUP_ID>"></div>
```

Group ID is found in the Okendo Admin URL for a given group as descibed in the table above.

### Specifying a Product To Ask About

When the widget is in all-reviews or grouped mode an explicit Product ID is needed to show the "Write a Review" or "Ask a Question" buttons.

#### Write A Review Product **ID**

If you are using **liquid** use the following snippet:

```markup
<div data-oke-widget data-oke-reviews-write-review-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```html
<div data-oke-widget data-oke-reviews-write-review-product-id="<PRODUCT_ID>"></div>
```

#### Ask A Question Product ID

If you are using **liquid** use the following snippet:

```markup
<div data-oke-widget data-oke-reviews-ask-question-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```html
<div data-oke-widget data-oke-reviews-ask-question-product-id="<PRODUCT_ID>"></div>
```

### Creating Curated Review Widgets Using Feature Tags

You can create multiple review widgets that display reviews curated by specific feature tags (for example, "Winter 2026", "Great for Layering", etc.).

#### 1. Create and Assign a Review Tag

1. Navigate to **Reviews** or **Moderation**.
2. Open the review you want to feature.
3. Create a new tag (for example, `Winter 2026`).
4. Assign the tag to the review.

> Tags created in Reviews/Moderation are private by default and cannot be used by storefront widgets until they are exposed publicly.

***

#### 2. Make the Tag Public

1. Navigate to **On-Site Displays**.
2. Open the Reviews Widget you want to configure.
3. Locate the **Featured Reviews / Feature Tags** configuration.
4. Add the tag name (`Winter 2026`) to the list.
5. Save the widget configuration.

This action exposes the tag publicly and generates a **Tag ID**.

6. Copy the generated **Tag ID**.

***

#### 3. Add a Curated Reviews Widget

Add a Reviews Widget to your storefront (for example, using a Shopify Custom Liquid section).

Example:

```
<div
  data-oke-widget
  data-oke-reviews-product-id="{{ product.id }}"
  data-oke-order-by-tag-id="PLWTGAF">
</div>
```

Replace:

* `{{ product.id }}` with the target product ID (or your existing product widget configuration).
* `PLWTGAF` with the public Tag ID copied from the Reviews Widget settings.

***

#### 4. Publish and Verify

1. Save and publish your theme changes.
2. Load the storefront page containing the widget.
3. Confirm that reviews tagged with the specified feature tag appear first in the widget.

> Newly exposed tags may take a short period of time to propagate through the system before all tag-related UI elements appear.

If you are using **liquid** use the following snippet:

```markup
<div data-oke-widget data-oke-reviews-product-id="shopify-{{ product.id }}" data-oke-order-by-tag-id="<THE TAG ID COPIED FROM OKENDO ADMIN>">
    {{ product.metafields.okendo.ReviewsWidgetSnippet }}
</div>
```

<figure><img src="/files/l1FYToNnBe1oN3rlmgZS" alt=""><figcaption></figcaption></figure>


# Star Rating

## Overview

Star Ratings build shopper trust on collection and product pages with subtle yet powerful displays of customer feedback. Star Ratings show the average aggregated rating of published customer reviews as well as the total number of published reviews.

<figure><img src="/files/NhVQAXfuJUMqjwR9d8uT" alt=""><figcaption></figcaption></figure>

## Installation

{% tabs %}
{% tab title="Shopify Online Store 2.0" %}
Instructions for a Shopify Online Store 2.0 installation can be found [here](https://support.okendo.io/en/articles/5537298-installing-okendo-on-shopify-online-store-2-0).
{% endtab %}

{% tab title="Shopify Vintage Theme" %}

1. Create a new liquid snippet in the snippets folder with the following name: `snippets/okendo-reviews-product-rating-summary.liquid`
2. Inside your newly created liquid file, add the following HTML snippet:

   ```html
   <div data-oke-star-rating></div>
   ```
3. Customize your snippet with the data attributes listed [here](/on-site/on-site-widgets/star-rating#star-rating-data-attributes).
4. Copy the following snippet and place it in your Theme Code where you would like the widget to appear: `{% render 'okendo-reviews-product-rating-summary', product: product %}`

For more detailed instructions, read our [help centre article](https://support.okendo.io/en/articles/1770332-setting-up-okendo-reviews-on-shopify-vintage-themes).
{% endtab %}
{% endtabs %}

## Styling

The preferred method of configuring the Star Rating is via the Okendo Admin which can be accessed in the Okendo app via Reviews -> On-Site Displays:

<figure><img src="/files/0WflgytBkmWDhOcfaZgf" alt=""><figcaption></figcaption></figure>

## Data Attributes

Use these data attributes on the widget markup to customise its configuration. None of these attributes are required.

<table><thead><tr><th width="235">Data Attribute</th><th width="249">Description</th><th>Value Type</th><th>Supported Values</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>data-oke-star-rating</code></td><td>This tells Widget Plus to show a star rating when the element is initialised.</td><td></td><td></td><td align="center"><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>data-oke-reviews-product-id</code></td><td>Used to specify a Shopify Product ID with the word <code>shopify-</code> in front of it. The star snippet will only show aggregate data for a particular product.</td><td><code>string</code></td><td></td><td align="center"></td></tr><tr><td><code>data-oke-reviews-group-id</code></td><td>Used to specify an Okendo Group ID so that the star snippet only shows aggregate data for that particular group of products.</td><td><code>string</code></td><td>Any valid product group ID in a <code>GUID</code> format e.g. <code>69d2e67d-b980-4333-97b7-30411807a7b1</code></td><td align="center"></td></tr><tr><td><code>data-oke-all-reviews</code></td><td>Determines whether or not to show the star snippet with the aggregate data from all reviews.</td><td><code>boolean</code></td><td><code>true</code>, <code>false</code></td><td align="center"></td></tr><tr><td><code>data-oke-scroll-disabled</code></td><td>Determines whether or not clicking the star snippet will scroll to the reviews widget.</td><td><code>boolean</code></td><td><code>true</code>, <code>false</code></td><td align="center"></td></tr></tbody></table>

{% hint style="info" %}
One of the following data attributes must be used in conjunction with the `data-oke-star-rating` attribute:

1. `data-oke-reviews-product-id`
2. `data-oke-reviews-group-id`
3. `data-oke-all-reviews`
   {% endhint %}

## Examples

### **Giving The Widget A Data Source**

Without specifying a data source for the reviews, the widget will show **all** reviews for your store. You can provide either a Product ID or a Group ID to use that as the data source for the reviews.

#### **Product Widget**

If you are using **liquid** use the following snippet:

```markup
<div data-oke-star-rating data-oke-reviews-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```html
<div data-oke-star-rating data-oke-reviews-product-id="shopify-<PRODUCT_ID>"></div>
```

The product widget also has some pre-rendered content stored in Shopify Metafields that we recommend including for increased performance on-site:

If you are using **liquid** use the following snippet:

```markup
<div data-oke-star-rating data-oke-reviews-product-id="shopify-{{ product.id }}">
    {{ product.metafields.okendo.StarRatingSnippet }}
</div>
```

The general format for other frameworks is:

```html
<div data-oke-star-rating data-oke-reviews-product-id="shopify-<PRODUCT_ID>">
    <!-- 
    Retrieve the product.metafields.okendo.StarRatingSnippet via Shopify's GraphQL/REST API
    and put the contents here
    -->
</div>
```

#### **Grouped Widget**

Learn more about Okendo Groups here:

{% embed url="<https://support.okendo.io/en/articles/3086139-understanding-okendo-groups>" %}

If you are using **liquid or general frameworks** use the following snippet:

```markup
<div data-oke-star-rating data-oke-reviews-group-id="<GROUP_ID>">
    {{ product.metafields.okendo.StarRatingSnippet }}
</div>
```

Group ID is found in the Okendo Admin URL for a given group as described in the table above.

#### **All Reviews Widget**

If you are using **liquid or general frameworks** use the following snippet:

```html
<div data-oke-star-rating data-oke-all-reviews="true"></div>
```

### Okendo Legacy Widget Backwards Compatibility

During a migration from our Legacy Widget to Widget Plus it is useful to keep showing the Legacy Widget until Widget Plus is enabled. This snippet shows how this can be achieved:

```jsx
{% if shop.metafields.okendo.settings.isWidgetPlusEnabled == true %}
    {% assign renderWidgetPlusContent = true %}
{% elsif shop.metafields.okendo.settings.isWidgetPlusAdminEnabled == true %}
    {% if request.design_mode or theme.role == "unpublished" %}
	{% assign renderWidgetPlusContent = true %}
    {% endif %}
{% endif %}

{% if renderWidgetPlusContent == true %}
    <div data-oke-star-rating data-oke-reviews-product-id="shopify-{{ product.id }}">
        {{ product.metafields.okendo.StarRatingSnippet }}
    </div>
{% else %}
    <div data-oke-reviews-product-listing-rating>
        {{ product.metafields.okendo.ProductListingSnippet }}
    </div>
{% endif %}
```


# Questions Widget

## Overview

{% hint style="info" %}
The [Reviews Widget](/on-site/on-site-widgets/reviews-widget) can be configured to show a Questions tab as part of a combined widget. This article describes how to include a standalone Questions Widget without reviews.
{% endhint %}

The Questions Widget lists questions that customers have asked and answers you've provided to them.&#x20;

<figure><img src="/files/acwKn9t6dVRoP2DGVHCW" alt=""><figcaption></figcaption></figure>

## Installation

{% tabs %}
{% tab title="Shopify Online Store 2.0" %}
Instructions for a Shopify Online Store 2.0 installation can be found [here](https://support.okendo.io/en/articles/5537298-installing-okendo-on-shopify-online-store-2-0).
{% endtab %}

{% tab title="Shopify Vintage Theme" %}

1. Create a new liquid snippet in the snippets folder with the following name: `snippets/okendo-reviews-widget.liquid`
2. Inside your newly created liquid file, add the following HTML snippet:

   ```tsx
   <div data-oke-questions-widget></div>
   ```
3. Customize your snippet with the data attributes listed [here](#questions-widget-data-attributes).
4. Copy the following snippet and place it in your Theme Code where you would like the widget to appear: `{% render 'okendo-reviews-widget', product: product %}`

For more detailed instructions, read our [help centre article](https://support.okendo.io/en/articles/1770332-setting-up-okendo-reviews-on-shopify-vintage-themes).
{% endtab %}
{% endtabs %}

## Styling

The preferred method of configuring the Questions Widget is via the Okendo Admin which can be accessed in the Okendo app via Reviews -> On-Site Displays:

<figure><img src="/files/0WflgytBkmWDhOcfaZgf" alt=""><figcaption></figcaption></figure>

## Data Attributes

Use these data attributes on the widget markup to customize its configuration. None of these attributes are required.

| Data Attribute                             | Description                                                                                                                                            | Value Type | Supported Values                                                                        |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | --------------------------------------------------------------------------------------- |
| `data-oke-reviews-product-id`              | Used to specify a Shopify Product ID with the word `shopify-` in front of it. The star snippet will only show aggregate data for a particular product. | `string`   | Any valid product ID in the format `shopify-` e.g. `shopify-1234567`.                   |
| `data-oke-reviews-group-id`                | Used to specify an Okendo Group ID so that the reviews widget only shows reviews for the specified group of products.                                  | `string`   | Any valid product group ID in a GUID format e.g. `69d2e67d-b980-4333-97b7-30411807a7b1` |
| `data-oke-reviews-ask-question-product-id` | Used to show the “Ask a Question” in the reviews widget to leave a question for the specified product.                                                 | `string`   | Any valid product ID in the format `shopify-` e.g. `shopify-1234567`.                   |

## Examples

### **Giving The Widget A Data Source**

Without specifying a data source for the questions, the widget will show **all** questions for your store. You can provide either a Product ID or a Group ID to use that as the data source for the questions.

#### **Product Widget**

If you are using **liquid** use the following snippet:

```markup
<div data-oke-questions-widget data-oke-reviews-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```html
<div data-oke-questions-widget data-oke-reviews-product-id="shopify-<PRODUCT_ID>"></div>
```

#### **Group Widget**

Learn more about Okendo Groups here:

{% embed url="<https://support.okendo.io/en/articles/3086139-understanding-okendo-groups>" %}

If you are using **liquid or general frameworks** use the following snippet:

```html
<div data-oke-questions-widget data-oke-reviews-group-id="<GROUP_ID>"></div>
```

Group ID is found in the Okendo Admin URL for a given group as described in the table above.

### Specifying a Product To Ask About

When the widget is in all-reviews or grouped mode an explicit Product ID is needed to show the "Ask a Question" button.

If you are using **liquid** use the following snippet:

```html
<div data-oke-questions-widget data-oke-reviews-ask-question-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```
<div data-oke-questions-widget data-oke-reviews-ask-question-product-id="shopify-<PRODUCT_ID>"></div>
```


# Reviews Carousel Widget

## Overview

Surface customer reviews at key conversion points throughout the buying journey such as the homepage, collection page, product page or even landing pages with the Reviews Carousel. The Reviews Carousel will scroll through the highest rated, most recent published reviews across all products and can be styled in a variety of ways.

<figure><img src="/files/xfn07F1YIGAs3iAOAkzY" alt=""><figcaption></figcaption></figure>

## Installation

{% tabs %}
{% tab title="Shopify Online Store 2.0" %}
Instructions for a Shopify Online Store 2.0 installation can be found [here](https://support.okendo.io/en/articles/5537298-installing-okendo-on-shopify-online-store-2-0).
{% endtab %}

{% tab title="Shopify Vintage Theme" %}

1. Create a new liquid snippet in the snippets folder with the following name: `snippets/okendo-reviews-carousel.liquid`
2. Inside your newly created liquid file, add the following HTML snippet:

   ```tsx
   <div data-oke-carousel></div>
   ```
3. Customize your snippet with the data attributes listed [here](#reviews-carousel-data-attributes).
4. Copy the following snippet and place it in your Theme Code where you would like the widget to appear: `{% render 'okendo-reviews-carousel' %}`

For more detailed instructions, read our [help centre article](https://support.okendo.io/en/articles/1770332-setting-up-okendo-reviews-on-shopify-vintage-themes).
{% endtab %}
{% endtabs %}

## Styling

The preferred method of configuring the Reviews Carousel is via the Okendo Admin which can be accessed in the Okendo app via Reviews -> On-Site Displays:

<figure><img src="/files/0WflgytBkmWDhOcfaZgf" alt=""><figcaption></figcaption></figure>

## Data Attributes

| Data Attribute                | Description                                                                                                                                            | Value Type | Supported Values                                                                        | Required |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------- | --------------------------------------------------------------------------------------- | :------: |
| `data-oke-reviews-product-id` | Used to specify a Shopify Product ID with the word `shopify-` in front of it. The star snippet will only show aggregate data for a particular product. | `string`   | Any valid product ID in the format `shopify-` e.g. `shopify-1234567`.                   |          |
| `data-oke-reviews-group-id`   | Used to specify an Okendo Group ID so that the reviews widget only shows reviews for the specified group of products.                                  | `string`   | Any valid product group ID in a GUID format e.g. `69d2e67d-b980-4333-97b7-30411807a7b1` |          |
| `data-oke-header-badge-url`   | Used to hyperlink the reviews badge above the carousel with a link relative to current URL.                                                            | `string`   |                                                                                         |          |

## Examples

### **Giving The Widget A Data Source**

Without specifying a data source for the reviews, the widget will show **all** reviews for your store. You can provide either a Product ID or a Group ID to use that as the data source for the reviews.

#### **Product Widget**

If you are using **liquid** use the following snippet:

```html
<div data-oke-carousel data-oke-reviews-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```html
<div data-oke-carousel data-oke-reviews-product-id="shopify-<PRODUCT_ID>"></div>
```

#### **Group Widget**

Learn more about Okendo Groups here:

{% embed url="<https://support.okendo.io/en/articles/3086139-understanding-okendo-groups>" %}

If you are using **liquid or general frameworks** use the following snippet:

```html
<div data-oke-carousel data-oke-reviews-group-id="<GROUP_ID>"></div>
```

Group ID is found in the Okendo Admin URL for a given group as described in the table above.

### **Customizing The Widget Header**

#### **Badge URL**

```html
<div data-oke-carousel data-oke-header-badge-url="<RELATIVE_URL>"></div>
```


# Media Grid Widget

## Overview

Promote a sense of brand community with a media gallery widget that displays customer-generated photos and videos in a large, high-impact media grid. Available in a variety of different styles, the Media Grid can also show approved UGC from [Foursixty](https://foursixty.com).

<figure><img src="/files/WXCcqymEA9zLHr2R3wVj" alt=""><figcaption></figcaption></figure>

## Installation

{% tabs %}
{% tab title="Shopify Online Store 2.0" %}
Instructions for a Shopify Online Store 2.0 installation can be found [here](https://support.okendo.io/en/articles/5537298-installing-okendo-on-shopify-online-store-2-0).
{% endtab %}

{% tab title="Shopify Vintage Theme" %}

1. Create a new liquid snippet in the snippets folder with the following name: `snippets/okendo-reviews-media-grid.liquid`
2. Inside your newly created liquid file, add the following HTML snippet:

   ```tsx
   <div data-oke-media-grid></div>
   ```
3. Customize your snippet with the data attributes listed [here](#media-grid-widget-data-attributes).
4. Copy the following snippet and place it in your Theme Code where you would like the widget to appear: `{% render 'okendo-reviews-media-grid' %}`
   {% endtab %}
   {% endtabs %}

## Styling

The preferred method of configuring the Media Grid is via the Okendo Admin which can be accessed in the Okendo app via Reviews -> On-Site Displays:

<figure><img src="/files/0WflgytBkmWDhOcfaZgf" alt=""><figcaption></figcaption></figure>

## Data Attributes

| Data Attribute                | Description                                                                                                                                        | Value Type | Supported Values                                                                        | Required |
| ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | --------------------------------------------------------------------------------------- | :------: |
| `data-oke-reviews-product-id` | Used to specify a Shopify Product ID with the word `shopify-` in front of it. The reviews widget will only show reviews for the specified product. | `string`   | Any valid product ID in the format `shopify-` e.g. `shopify-1234567`.                   |          |
| `data-oke-reviews-group-id`   | Used to specify an Okendo Group ID so that the reviews widget only shows reviews for the specified group of products.                              | `string`   | Any valid product group ID in a GUID format e.g. `69d2e67d-b980-4333-97b7-30411807a7b1` |          |

## Examples

### **Giving The Widget A Data Source**

Without specifying a data source for the media, the widget will show **all** media for your store. You can provide either a Product ID or a Group ID to use that as the data source for the media.

#### **Product Widget**

If you are using **liquid** use the following snippet:

```markup
<div data-oke-carousel data-oke-reviews-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```html
<div data-oke-carousel data-oke-reviews-product-id="shopify-<PRODUCT_ID>"></div>
```

#### **Group Widget**

Learn more about Okendo Groups here:

{% embed url="<https://support.okendo.io/en/articles/3086139-understanding-okendo-groups>" %}

If you are using **liquid or general frameworks** use the following snippet:

```html
<div data-oke-carousel data-oke-reviews-group-id="<GROUP_ID>"></div>
```

Group ID is found in the Okendo Admin URL for a given group as described in the table above.


# Media Carousel Widget

## Overview

Bring reviews to life with a stand-alone media carousel that displays customer-generated photos and videos submitted in published product reviews. Shoppers can hover over photos/videos to quickly see the review star rating and click to bring up a modal with the full review. An excellent addition to the product page to increase shopper engagement.

<figure><img src="/files/8RDgC7Uo8vdaxTseZ6oK" alt=""><figcaption></figcaption></figure>

## Installation

{% tabs %}
{% tab title="Shopify Online Store 2.0" %}
Instructions for a Shopify Online Store 2.0 installation can be found [here](https://support.okendo.io/en/articles/5537298-installing-okendo-on-shopify-online-store-2-0).
{% endtab %}

{% tab title="Shopify Vintage Theme" %}

1. Create a new liquid snippet in the snippets folder with the following name: `snippets/okendo-reviews-media-carousel.liquid`
2. Inside your newly created liquid file, add the following HTML snippet:

   ```tsx
   <div data-oke-media-carousel></div>
   ```
3. Customize your snippet with the data attributes listed [here](#media-carousel-widget-data-attributes).
4. Copy the following snippet and place it in your Theme Code where you would like the widget to appear: `{% render 'okendo-reviews-media-carousel' %}`
   {% endtab %}
   {% endtabs %}

## Styling

The preferred method of configuring the Media Carousel is via the Okendo Admin which can be accessed in the Okendo app via Reviews -> On-Site Displays:

<figure><img src="/files/0WflgytBkmWDhOcfaZgf" alt=""><figcaption></figcaption></figure>

## Data Attributes

| Data Attribute                | Description                                                                                                                                             | Value Type | Supported Values                                                                        | Required |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | --------------------------------------------------------------------------------------- | :------: |
| `data-oke-reviews-product-id` | Used to specify a Shopify Product ID with the word `shopify-` in front of it. The media carousel widget will only show media for the specified product. | `string`   | Any valid product ID in the format `shopify-` e.g. `shopify-1234567`.                   |          |
| `data-oke-reviews-group-id`   | Used to specify an Okendo Group ID so that the media carousel widget only shows media for the specified group of products.                              | `string`   | Any valid product group ID in a GUID format e.g. `69d2e67d-b980-4333-97b7-30411807a7b1` |          |
|                               |                                                                                                                                                         |            |                                                                                         |          |

## Examples

### **Giving The Widget A Data Source**

Without specifying a data source for the media, the widget will show **all** media for your store. You can provide either a Product ID or a Group ID to use that as the data source for the media.

#### **Product Widget**

If you are using **liquid** use the following snippet:

```markup
<div data-oke-carousel data-oke-reviews-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```html
<div data-oke-carousel data-oke-reviews-product-id="shopify-<PRODUCT_ID>"></div>
```

#### **Group Widget**

Learn more about Okendo Groups here:

{% embed url="<https://support.okendo.io/en/articles/3086139-understanding-okendo-groups>" %}

If you are using **liquid or general frameworks** use the following snippet:

```html
<div data-oke-carousel data-oke-reviews-group-id="<GROUP_ID>"></div>
```

Group ID is found in the Okendo Admin URL for a given group as described in the table above.


# Reviews Badge Widget

## Overview

An authoritative trust-mark that builds social proof and establishes credibility in the minds of prospective shoppers, the Reviews Badge shows the total number of published reviews and the aggregated average of all star ratings.

<div><figure><img src="/files/GOIQGv3nTtx30dmIOWeH" alt=""><figcaption></figcaption></figure> <figure><img src="/files/evbGFsFUAg0te21mZimh" alt=""><figcaption></figcaption></figure> <figure><img src="/files/gRt7VmsJ0ocK7AuZtpHa" alt=""><figcaption></figcaption></figure></div>

## Installation

{% tabs %}
{% tab title="Shopify Online Store 2.0" %}
Instructions for a Shopify Online Store 2.0 installation can be found [here](https://support.okendo.io/en/articles/5537298-installing-okendo-on-shopify-online-store-2-0).
{% endtab %}

{% tab title="Shopify Vintage Theme" %}

1. Create a new liquid snippet in the snippets folder with the following name: `snippets/okendo-reviews-badge.liquid`
2. Inside your newly created liquid file, add the following HTML snippet:

   ```tsx
   <div data-oke-badge></div>
   ```
3. Customize your snippet with the data attributes listed [here](#reviews-badge-widget-data-attributes).
4. Copy the following snippet and place it in your Theme Code where you would like the widget to appear: `{% render 'okendo-reviews-badge' %}`
   {% endtab %}
   {% endtabs %}

## Styling

The preferred method of configuring the Reviews Badge is via the Okendo Admin which can be accessed in the Okendo app via Reviews -> On-Site Displays:

<figure><img src="/files/0WflgytBkmWDhOcfaZgf" alt=""><figcaption></figcaption></figure>

## Data Attributes

| Data Attribute                | Description                                                                                                                                                            | Value Type | Supported Values                                                                        | Required |
| ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | --------------------------------------------------------------------------------------- | :------: |
| `data-oke-reviews-product-id` | Used to specify a Shopify Product ID with the word `shopify-` in front of it. The reviews badge widget will only show aggregate review data for the specified product. | `string`   | Any valid product ID in the format `shopify-` e.g. `shopify-1234567`.                   |          |
| `data-oke-reviews-group-id`   | Used to specify an Okendo Group ID so that the reviews badge widget will only show aggregate review data for the specified group of products.                          | `string`   | Any valid product group ID in a GUID format e.g. `69d2e67d-b980-4333-97b7-30411807a7b1` |          |
| `data-oke-url`                | Used to hyperlink the badge on click so that it directs the user to a custom absolute URL.                                                                             | `string`   |                                                                                         |          |

## Examples

### **Giving The Widget A Data Source**

Without specifying a data source for the media, the widget will show **all** media for your store. You can provide either a Product ID or a Group ID to use that as the data source for the media.

#### **Product Widget**

If you are using **liquid** use the following snippet:

```html
<div data-oke-carousel data-oke-reviews-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```markup
<div data-oke-carousel data-oke-reviews-product-id="shopify-<PRODUCT_ID>"></div>
```

#### **Group Widget**

Learn more about Okendo Groups here:

{% embed url="<https://support.okendo.io/en/articles/3086139-understanding-okendo-groups>" %}

If you are using **liquid or general frameworks** use the following snippet:

```html
<div data-oke-carousel data-oke-reviews-group-id="<GROUP_ID>"></div>
```

Group ID is found in the Okendo Admin URL for a given group as descibed in the table above.


# Reviews Modal Trigger

## Overview

Trigger a reviews widget to appear in a modal (pop-up) when the user clicks on an element on your online store.

<figure><img src="/files/Gk3XHf2DxoSuWewescGB" alt=""><figcaption></figcaption></figure>

## Installation

Place the `data-oke-reviews-modal-trigger` data attribute on any HTML element e.g. `<div>` `<button>` `<span>`. When Widget Plus initializes it will find any tags with that data element and add click behavior to them.

## Data Attributes

| Data Attribute                   | Description                                                                                                                                       | Value Type | Supported Values                                                                        |       Required       |
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- | --------------------------------------------------------------------------------------- | :------------------: |
| `data-oke-reviews-modal-trigger` | This tells Widget Plus to show a modal/pop up when the customer clicks the element.                                                               | `string`   |                                                                                         | :white\_check\_mark: |
| `data-oke-reviews-product-id`    | Used to specify a Shopify Product ID with the word `shopify-` in front of it. The reviews modal will only show reviews for the specified product. | `string`   | Any valid product ID in the format `shopify-` e.g. `shopify-1234567`.                   |                      |
| `data-oke-reviews-group-id`      | Used to specify an Okendo Group ID so that the reviews badge widget will only show aggregate review data for the specified group of products.     | `string`   | Any valid product group ID in a GUID format e.g. `69d2e67d-b980-4333-97b7-30411807a7b1` |                      |

## Examples

### **Giving The Widget A Data Source**

Without specifying a data source for the reviews, the widget will show **all** reviews for your store. You can provide either a Product ID or a Group ID to use that as the data source for the reviews.

#### **Product Widget**

If you are using **liquid** use the following snippet:

```html
<div data-oke-reviews-modal-trigger data-oke-reviews-product-id="shopify-{{ product.id }}"></div>
```

The general format for other frameworks is:

```markup
<div data-oke-reviews-modal-trigger data-oke-reviews-product-id="shopify-<PRODUCT_ID>"></div>
```

#### **Group Widget**

**Grouped Widget**

Learn more about Okendo Groups here:

{% embed url="<https://support.okendo.io/en/articles/3086139-understanding-okendo-groups>" %}

If you are using **liquid or general frameworks** use the following snippet:

```html
<div data-oke-reviews-modal-trigger data-oke-reviews-group-id="<GROUP_ID>"></div>
```

Group ID is found in the Okendo Admin URL for a given group as described in the table above.


# Storefront Javascript API

The Okendo Storefront Javascript API exposes various ways of interacting with Okendo Widgets through code. The main way to do so is via the Widget Plus Window API:

{% content-ref url="/pages/xjhxdBkzB0hnuCQ3kGuF" %}
[Widget Plus Window API](/on-site/storefront-javascript-api/widget-plus-window-api)
{% endcontent-ref %}

{% content-ref url="/pages/WrrvjrZURZ49atPx5uvK" %}
[Surveys - Connect Window API](/on-site/storefront-javascript-api/surveys-connect-window-api)
{% endcontent-ref %}

{% content-ref url="/pages/Jr01CtSXCqteUHpNJwtk" %}
[Quizzes - Connect Window API](/on-site/storefront-javascript-api/quizzes-connect-window-api)
{% endcontent-ref %}

{% content-ref url="/pages/FWL3BqZ0YIDipm5RhS2T" %}
[Referrals Window API](/on-site/storefront-javascript-api/referrals-window-api)
{% endcontent-ref %}

{% content-ref url="/pages/RIGSinxTS6qfSW0XY9xE" %}
[Inspiration](/on-site/storefront-javascript-api/inspiration)
{% endcontent-ref %}


# Widget Plus Window API

The Widget Plus Window API exposes public functions that can be called to setup or make configuration changes to the widgets on the page.

## Functions

### initAllWidgets

Initializes all widgets on the current page.

#### Example Usage

```jsx
window.okeWidgetApi.initAllWidgets();
```

### initWidget

Initializes or reinitializes a particular widget.

#### Example Usage

```jsx
const widgetElement = document.querySelector('[data-oke-widget]');
window.okeWidgetApi.initWidget(widgetElement);
```

#### Parameters

<table><thead><tr><th width="262">Parameter</th><th width="215">Description</th><th width="166">Value Type</th><th width="114">Supported Values</th><th width="102" align="center">Required</th></tr></thead><tbody><tr><td><code>widgetElement</code></td><td>The widget <code>HTMLElement</code> which will be initialized.</td><td><code>HTMLElement</code></td><td></td><td align="center"><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>forceReinitialization</code></td><td>Determines whether or not to force the widget to reinitialize if it has already been initialized.</td><td><code>boolean</code></td><td><code>true</code>, <code>false</code></td><td align="center"></td></tr></tbody></table>

### setProduct

Sets a widget to 'product' mode and to only show review data for the specified product.

#### Example Usage

```jsx
const widgetElement = document.querySelector('[data-oke-widget]');
window.okeWidgetApi.setProduct(widgetElement, 'shopify-7551554945263');
```

#### Parameters

| Parameter       | Description                                                                         | Value Type    | Supported Values                                                                  |       Required       |
| --------------- | ----------------------------------------------------------------------------------- | ------------- | --------------------------------------------------------------------------------- | :------------------: |
| `widgetElement` | The widget `HTMLElement` which will be set with a particular product’s data.        | `HTMLElement` |                                                                                   | :white\_check\_mark: |
| `productId`     | Sets the widget in 'product' mode with only reviews data for the specified product. | `string`      | Any valid Product ID in the format `shopify-{product_id}` e.g. `shopify-1234567`. | :white\_check\_mark: |

### setGroup

Sets a widget to 'group' mode and to only show review data for the specified group.

#### Example Usage

```jsx
const widgetElement = document.querySelector('[data-oke-widget]');
window.okeWidgetApi.setGroup(widgetElement, 'd06b2294-7f17-48fe-9fd6-155e8cb07a54');
```

#### Parameters

| Parameter       | Description                                                                             | Value Type    | Supported Values                                                            |       Required       |
| --------------- | --------------------------------------------------------------------------------------- | ------------- | --------------------------------------------------------------------------- | :------------------: |
| `widgetElement` | The widget/target `HTMLElement` which will be set with a particular product’s data.     | `HTMLElement` |                                                                             | :white\_check\_mark: |
| `groupId`       | Sets the widget in 'group' mode with only reviews data for the specified product group. | `string`      | Any valid Group ID. [Where can I find a Group ID?](#how-to-find-a-group-id) | :white\_check\_mark: |

#### How to Find a Group ID <a href="#how-to-find-a-group-id" id="how-to-find-a-group-id"></a>

1. Open **Okendo Admin.**
2. Navigate to **Groups** (Reviews > Groups).
3. Select the Group you would like to use for your widget.
4. Look in the URL for the group page and you will see a [GUID](https://www.techtarget.com/searchwindowsserver/definition/GUID-global-unique-identifier) at the end of the URL. This is the Group ID.

<figure><img src="/files/9sj5LtU6YD5sPg8gdpgK" alt=""><figcaption><p>Group ID is located in the browser address bar at the end of the URL.</p></figcaption></figure>

### setWidgetLocale

Sets the widget locale and/or locale variant for the widgets to use for translation purposes.

#### Example Usage

```jsx
window.okeWidgetApi.setWidgetLocale('fr');
```

#### Parameters

<table><thead><tr><th width="129">Parameter</th><th>Description</th><th width="127">Value Type</th><th>Supported Values</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>locale</code></td><td>The locale code for the language you want the set the widgets to use.</td><td><code>string</code></td><td><code>da</code> | <code>de</code> | <code>el</code> | <code>en</code> | <code>es</code> | <code>fr</code> | <code>id</code> | <code>it</code> | <code>ja</code> | <code>ko</code> | <code>nl</code> | <code>no</code> | <code>pl</code> | <code>pt</code> | <code>ru</code> | <code>sv</code> | <code>th</code> | <code>vi</code> | <code>zh-TW</code></td><td align="center"><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>variant</code></td><td>The variant code for the language you want to set the widget to use.<br><br>Currently only support formal/informal for the German locale <code>de</code><br></td><td><code>string</code></td><td><code>formal</code> | <code>informal</code></td><td align="center"></td></tr></tbody></table>

## Custom Initialization

If our standard widget initialization pattern doesn't work correctly for your application, you may need to manually re-initialize the widget(s).

### Manually Initialize a Widget

A common practice is to initialize the widget via the Window API by placing a `script` block or file at the base of your HTML document.\
\
You are then able to watch the `document.readyState` lifecycle and initialise widgets using the `window.okeWidgetApi`.

```javascript
<script type="text/javascript">
((document, window) => {  
    const reviewsWidgetHolder = document.querySelector('[data-oke-widget]');
    if (reviewsWidgetHolder) {
        const handleDocumentLoaded = function (e) {
            if (window.okeWidgetApi) {
                window.okeWidgetApi.initWidget(reviewsWidgetHolder, true);
            }
        }
    
        if (document.readyState !== 'interactive' && document.readyState !== 'complete') {
            document.addEventListener('readystatechange', () => {
                handleDocumentLoaded();
            }, { once: true });
        }
        else {
            handleDocumentLoaded();
        }
    }
})(document, window);
</script>
```

### Overriding The Product Details URL - Stores With Shopify Markets / Custom Domains / Headless

We give merchants the ability to override the way their product detail URLs are generated by the Reviews Widget.

A common use-case for this functionality would be in the event a store is using Shopify Markets, Custom Domains, a Headless implementation.

In your theme or a custom html/liquid block you can supply a product URL formatter function on the `window` object which the reviews widget will use when generating links to products.

**It is recommended to place this snippet in the \<head> of your site above the {{ content\_for\_header }}**:

**Example Markets Usage When Using Shopify Translate and Adapt Style Sub-Folders for \<market>-\<locale> e.g. <https://www.store-domain.com/ja-ja/>**

```
<script type="text/javascript">
window.okeProductUrlFormatter = (product) => {
    if (product && window?.Shopify?.routes?.root?.length && window?.Shopify?.routes?.root !== '/') {
        return window.Shopify.routes.root + 'products/' + product.productHandle + '/?id=' + product.productId + (product.variantId ? ('&variantId=' + product.variantId) : '');
    }
};
</script>
```

**Example Markets Usage**

```
<script type="text/javascript">
  window.okeProductUrlFormatter = (product) => {
    // Retrieve current Shopify locale
    const locale = window.Shopify.locale || 'en';

    // Base URL for each locale
    // You could use window.Shopify.routes.root
    let baseUrl;

    // Switch statement to handle different locales
    switch (locale) {
      case 'en': // Default English market
        baseUrl = 'https://www.my-store.com';
        break;
      case 'ja': // Japanese market
        baseUrl = 'https://www.my-store.co.jp';
        break;
      case 'au': // Australian market
        baseUrl = 'https://www.my-store.com.au';
        break;
      case 'zh': // Chinese market
        baseUrl = 'https://www.my-store.cn';
        break;
      case 'de': // German market
        baseUrl = 'https://www.my-store.de';
        break;
      // Add more cases for other locales as needed
      default: // Fallback for unsupported locales
        baseUrl = 'https://www.my-store.com';
        break;
    }

    // Construct the product URL
    const productUrl = `${baseUrl}/products/${product.productHandle}/?id=${product.productId}`;

    // Include variantId if available
    if (product.variantId) {
      return `${productUrl}&variantId=${product.variantId}`;
    }

    return productUrl;
  };
</script>

```

#### Parameters

<table><thead><tr><th width="129">Parameter</th><th>Description</th><th width="127">Value Type</th><th>Object Values</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>product</code></td><td>This is a Javascript object which is passed to your function to provide product information you may use when constructing a product details URL.</td><td><code>object</code></td><td><code>{ productHandle: string;</code><br><code>productId: string;</code><br><code>variantId: string }</code></td><td align="center"><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr></tbody></table>

## Events

For merchants not using Google Analytics, an `oke-analytics-event` is raised in conjunction with any of our standard Google Analytics interaction and view events.\
\
You can subscribe to the event and forward it on to other analytics providers like so:

```
document.addEventListener('oke-analytics-event', (event) => {
  // event.detail contains analytics information properties
  console.log(JSON.stringify(event.detail));
});
```

#### event.detail Properties

| Property         | Description                                                                                                                                                                                  |                                                                                                                                                                                                                                                                                                                                                                  |   |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - |
| `event`          | The name of the event in snake case                                                                                                                                                          |                                                                                                                                                                                                                                                                                                                                                                  |   |
| `event_category` | `'Okendo'`                                                                                                                                                                                   |                                                                                                                                                                                                                                                                                                                                                                  |   |
| `event_label`    | A custom label based on the event or falls back to the product name if not supplied                                                                                                          |                                                                                                                                                                                                                                                                                                                                                                  |   |
| `event_type`     | <p><code>'interaction'</code>                                                                                                                                                                | <code>'view'</code><br><br><code>interaction</code> : When a user directly interacted with the widget<br><br><code>view</code> : When widget based time tracking is enabled (see: <a href="https://support.okendo.io/en/articles/6787536-tracking-widget-on-screen-time"><https://support.okendo.io/en/articles/6787536-tracking-widget-on-screen-time></a>)</p> |   |
| `okendo_product` | `'reviews'`                                                                                                                                                                                  |                                                                                                                                                                                                                                                                                                                                                                  |   |
| `product_label`  | <p>The product name/label if the reviews widget is displaying a specific product.<br><br>This will be empty when the widget displays "All Reviews", "Grouped" , or "Collection" reviews.</p> |                                                                                                                                                                                                                                                                                                                                                                  |   |


# Surveys - Connect Window API

The Connect Window API exposes public functions that can be called to setup or make configuration changes to surveys to be displayed on the page.

## Properties

This is a list of all properties that can be set on the window API.

| Name                                          | Description                                                                        | Sample                                 |
| --------------------------------------------- | ---------------------------------------------------------------------------------- | -------------------------------------- |
| `window.okeConnectApi.subscriberId`           | Okendo subscriber id for connecting to your store.                                 | `00000000-0000-0000-0000-000000000000` |
| `window.okeConnectApi.apiDomain`              | Shopify domain for connecting to your store.                                       | `{your-shopify-domain}`                |
| `window.okeConnectApi.channel`                | The survey channel being implemented. `on-site` or `post-checkout`                 | `on-site`                              |
| `window.okeConnectApi.targetElementId`        | Optional target element id in which to display an embedded survey.                 | `okendo-survey`                        |
| `window.okeConnectApi.checkout.orderId`       | Order id to associate with the customer and survey response.                       | `5179739177206`                        |
| `window.okeConnectApi.checkout.subtotalPrice` | Price of the order used for order value conditions as well as revenue attribution. | `100`                                  |
| `window.okeConnectApi.checkout.email`         | Used to attribute orders to survey responses.                                      | `user@example.com`                     |
| `window.okeConnectApi.checkout.lineItems`     | An array of product ids being purchased. Used for cart content conditions.         | `112233, 112244`                       |

## Functions

### <mark style="color:blue;">setup</mark>

Initialises the surveys scripts on the page.

#### Example Usage

```javascript
window.okeConnectApi.setup();
```

#### Properties

Before calling `setup`, you should set the properties below.

<table><thead><tr><th width="402">Name</th><th>Description</th></tr></thead><tbody><tr><td><code>window.okeConnectApi.subscriberId</code></td><td>Either subscriberId or apiDomain is required.</td></tr><tr><td><code>window.okeConnectApi.apiDomain</code></td><td>Either subscriberId or apiDomain is required.</td></tr><tr><td><code>window.okeConnectApi.channel</code></td><td><code>on-site</code> or <code>post-checkout</code></td></tr><tr><td><code>window.okeConnectApi.targetElementId</code></td><td>An optional target element id to place an embedded survey in.</td></tr></tbody></table>

#### Parameters

<table><thead><tr><th width="223">Parameter</th><th width="208">Description</th><th width="116">Value Type</th><th>Supported Values</th><th>Required</th></tr></thead><tbody><tr><td><code>customEventsOnly</code></td><td>Supress all page event triggers to allow manually triggering custom event surveys after initialisation.</td><td><code>boolean</code></td><td><code>true</code>, <code>false</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr></tbody></table>

### <mark style="color:blue;">raiseCustomEvent</mark>

Raise a custom event to potentially trigger a given survey. Display frequency rules are followed by default which can prevent a survey from being displayed to a given user for example if they have already answered the survey in their session.

#### Example Usage

```javascript
window.okeConnectApi.raiseCustomEvent('product-survey');
```

#### Properties

You should set one of these properties before you can raise a custom event.

| Name                                | Description                                   |
| ----------------------------------- | --------------------------------------------- |
| `window.okeConnectApi.subscriberId` | Either subscriberId or apiDomain is required. |
| `window.okeConnectApi.apiDomain`    | Either subscriberId or apiDomain is required. |

#### Parameters

<table><thead><tr><th width="150">Parameter</th><th width="230">Description</th><th width="116">Value Type</th><th>Supported Values</th><th>Required</th></tr></thead><tbody><tr><td><code>eventName</code></td><td>The name of the event on the survey to show.</td><td><code>string</code></td><td></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>forceShow</code></td><td>Flag to ignore all display rules and show the survey. Defaults to <code>false</code></td><td><code>boolean</code></td><td><code>true</code>, <code>false</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr></tbody></table>

<figure><img src="/files/BkfnRX5FLG9f1p1gscIh" alt=""><figcaption><p>Setting a custom eventName on the on-site channel survey.</p></figcaption></figure>

### <mark style="color:blue;">addToCart</mark>

Raise an add to cart event to trigger any add to cart surveys or to support a remove from cart trigger later. Add and remove from cart events rely on a cached list of products to store state between events.

#### Example Usage

```javascript
window.okeConnectApi.addToCart('11223344');
```

#### Parameters

| Parameter   | Description                         | Value Type | Required             |
| ----------- | ----------------------------------- | ---------- | -------------------- |
| `productId` | The product id being added to cart. | `string`   | :white\_check\_mark: |

### <mark style="color:blue;">removeFromCart</mark>

Raise a remove from cart event to trigger any remove from cart surveys.

#### Example Usage

```javascript
window.okeConnectApi.removeFromCart('11223344');
```

#### Parameters

| Parameter   | Description                             | Value Type | Required             |
| ----------- | --------------------------------------- | ---------- | -------------------- |
| `productId` | The product id being removed from cart. | `string`   | :white\_check\_mark: |


# Quizzes - Connect Window API

The Connect Window API exposes public functions that can be called to show or configure custom events for quizzes to be displayed on the page.

## Functions

### `showQuiz`&#x20;

The `showQuiz` event can optionally be used to trigger display of Okendo Quizzes on your storefront in a modal.&#x20;

#### Example Usage

```markup
<script>
	window.okeConnectApi.showQuiz(channelQuizId, subscriberId);
</script>
```

#### Custom Liquid Usage

```html
<a  
  href="#" 
  onclick="okeConnectApi.showQuiz('your-channel-quiz-id', 'your-subscriber-id')" 
  class="button button--full-width">Take our quiz
</a>
```

#### Parameters

<table><thead><tr><th width="223">Parameter</th><th width="284">Description</th><th width="116">Value Type</th><th>Required</th></tr></thead><tbody><tr><td><code>channelQuizId</code></td><td>Can be found in the install dialog of your quiz</td><td><code>string</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>subscriberId</code></td><td>Your Okendo customer identifier.</td><td><code>string</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr></tbody></table>

### `recommendedProductMounted`&#x20;

The `recommendedProductMounted` event is triggered when an individual product recommendation is mounted in the application. It provides an opportunity for merchants to insert custom HTML or other custom product display functionality, allowing them to further customize the presentation of recommended products.

#### Example Usage

```javascript
window.okeConnectApi.recommendedProductMounted = (sectionContent, product) => {
	const addButton = sectionContent.querySelector('button.c-addToCart');
	if (addButton && !sectionContent.loaded) {
		sectionContent.loaded = true;
		let selectorHtml = `
		<div class="c-resultLearnMore">
			<a class="c-resultButton-primary c-button c-resultButton" style="width: 100%;" href="https://sample.myshopify.com/collections/product1" target="_blank">Learn More</a>
		</div>`;
		addButton.insertAdjacentHTML('beforeBegin', selectorHtml);
	}
};
```

#### Parameters

<table><thead><tr><th width="198">Parameter</th><th width="338">Description</th><th width="116">Value Type</th><th>Required</th></tr></thead><tbody><tr><td><code>sectionContent</code></td><td>HTML of the recommended product to be rendered.</td><td><code>html</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>product</code></td><td>A payload representing the product to be recommended.</td><td><code>JSON</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr></tbody></table>

### `recommendedProductsMounted`&#x20;

The `recommendedProductsMounted` event is triggered when all product recommendations are mounted in the application. It provides an opportunity for merchants to insert custom HTML or other custom product display functionality for the entire recommendation page. This allows merchants to have full control over the presentation of the entire recommendation section.&#x20;

#### Example Usage

```javascript
window.okeConnectApi.recommendedProductsMounted = (recommendationSection, products) => {
	// Insert custom HTML or other custom product display functionality for the entire recommendation page
	// Example:
	recommendationSection.insertAdjacentHTML('beforeend', '<div class="custom-recommendation-section">...</div>');
};
```

#### Parameters

<table><thead><tr><th width="258">Parameter</th><th width="227">Description</th><th>Value Type</th><th>Required</th></tr></thead><tbody><tr><td><code>recommendationSection</code> </td><td>The html element representing the entire recommendation section.</td><td><code>html</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>products</code> </td><td>A JSON object representing all recommended products to be displayed on the recommendation page.</td><td>JSON</td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr></tbody></table>

### `generateCartLineItemProperties`&#x20;

The `generateCartLineItemProperties` event is triggered when a product is added to the cart from the recommendation page. It provides an opportunity for merchants to insert custom data into the cart line items, allowing them to enhance the cart experience with personalized information.&#x20;

#### Example Usage

```javascript
window.okeConnectApi.generateCartLineItemProperties = (addToCartButtonId, product) => {
	// Insert custom data into the cart line items
	// Example:
		const customProperties = {};
	customProperties['Customer option'] = 'Some custom option';
	customProperties['_has_custom'] = true;
	return customProperties;
};
```

#### Parameters

<table><thead><tr><th width="228">Parameter</th><th width="263">Description</th><th>Value Type</th><th>Required</th></tr></thead><tbody><tr><td><code>addToCartButtonId</code></td><td>id of the add to cart button element that was clicked</td><td><code>string</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>product</code> </td><td>A JSON object representing the product that was added to the cart from the recommendation page.</td><td>JSON</td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr></tbody></table>

## Events

### `oke_quizCapture_addToCart`&#x20;

The `oke_quizCapture_addToCart` event is used by Okendo Quizzes to notify the store that a customer intends to “Add to Cart” one or more recommended products.

#### Example Usage

```typescript
// Listen to the oke_quizCapture_addToCart event
document.addEventListener('oke_quizCapture_addToCart', async event => {

	// Process each product variant to be added to the custom cart.
	for (const productVariant of event.detail.items) {

		try {
			// Attempt to add the variant.
			await customCart.addProductVariant({
				productId: productVariant.productId,
				variantId: productVariant.variantId,
				quantity: productVariant.quantity
			});

			// Tell Okendo Quizzes to visually show the customer
			// that the product variant was added successfully.
			document.dispatchEvent(new CustomEvent(
				'oke_quizCapture_addToCartSuccess',
				{	detail: { message: 'Yay! Added to cart successfully!' } }
			);
		}
		catch {
			// The variant was not able to be added to the custom cart.
			document.dispatchEvent(new CustomEvent(
				'oke_quizCapture_addToCartFailure',
				{	detail: { message: 'Oh no, something went wrong.' } }
			);
		}
	}

});
```

## Headless Events

Typically used in headless implementations. See the below guide for an explanation and examples of how to setup quizzes on headless instances:

{% content-ref url="/pages/gcl0ncDa4bOBR38UBmQg" %}
[Installing Quizzes on Headless Instances](/on-site/advanced-widget-installs/installing-quizzes-on-headless-instances)
{% endcontent-ref %}

### oke\_quizCapture\_addToCartSuccess

### oke\_quizCapture\_addToCartFailure

### oke\_connect\_cart\_itemVariantAdded

### oke\_connect\_checkout\_orderSubmitted


# Referrals Window API

The Referrals Window API exposes public functions that can be called to setup or make configuration changes to referral to be displayed on the page.

## Properties

This is a list of all properties that can be set on the window API.

<table><thead><tr><th>Name</th><th width="249">Description</th><th>Sample</th></tr></thead><tbody><tr><td><code>window.okeReferralsApi.appStatus</code></td><td>The current load state of the Referrals widget on site.<br><br><code>'notRequested'</code> - no load for the referrals app has been attempted.<br><br><code>'requested'</code> - The referrals app initialisation has commenced.<br><br><code>'loaded'</code> - The app has been loaded and is ready to interact with whether the widget is visible or not.</td><td><code>'notRequested' | 'requested' | 'loaded'</code></td></tr><tr><td><code>window.okeReferralsApi.isEmbedded</code></td><td>A <code>boolean</code> value to indicate whether there is a Referrals Widget in the page markup as opposite to one that would be invoked as a pop-over/modal component.</td><td><code>true</code> | <code>false</code></td></tr><tr><td><code>window.okeReferralsApi.isModalOpen</code></td><td>A <code>boolean</code> value to indicate whether there is an open Referrals Widget in pop-over/modal component.</td><td><code>true</code> | <code>false</code></td></tr></tbody></table>

## Functions

### <mark style="color:blue;">openModal</mark>

Opens the Referrals Widget as a modal/pop-over on a given page. If a Referrals Widget is already embedded on the current page, the page will scroll down to the embedded Referrals Widget.

#### Example Usage

```javascript
window.okeReferralsApi.openModal();
```

#### Properties

Before calling `openModal`, you should check that `window.okeReferralsApi.appStatus` is `loaded`

### <mark style="color:blue;">closeModal</mark>

Closes an open Referrals Widget modal/pop-over on a given page. If a Referrals Widget is already embedded on the current page this action won't do anything as there is no modal/pop-over to close.

#### Example Usage

```javascript
window.okeReferralsApi.closeModal();
```

## Binding A Referrals Modal Open Action To An Element

We give merchants/engineers the ability to add a `data` attribute to elements within the DOM.

When the Okendo App Embed is enabled and the `data` attribute is present, any click on that given element will open a Referrals modal/pop-over.

#### Example Usage

```html
<button data-oke-open-referrals="">Open Referrals Widget In Modal/Pop-Over</button>
```


# Inspiration

Here are some common ways that the Storefront Javascript API can be used to build custom on-site features.

### Create a Reviews Page With a Product/Group Review Switcher

This recipe will guide you through setting up a dedicated page which can switch between showing reviews for different products or groups.

<figure><img src="/files/WVs4daabsS5Sb8JpveyT" alt=""><figcaption></figcaption></figure>

1\. Navigate to the store's theme: Sales Channels -> Online Store -> Themes and press the menu item with the three vertical dots. Press "Edit Code" from the menu which appears:![](/files/EoWrbpbZUtnixAeW6893)

2\. Create a new file in the `page` folder of your theme called `page.okendo-reviews-switcher` (This will be the template name for your dedicated reviews page template).

3\. Copy/paste the markup below:

```
<style type="text/css">
.reviews-page-wrapper {
  padding-top: 2em;
}

.orc-allReviewsCollections .orc-collectionControlsLabel {
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px
}

.orc-allReviewsCollections .orc-collectionControls {
    -ms-flex-align: stretch;
    align-items: stretch;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-wrap: wrap;
    flex-wrap: wrap;
    margin: -3px -9px
}

.orc-allReviewsCollections .orc-collectionControls .orc-collectionControls-item-label {
    -ms-flex-align: center;
    align-items: center;
    border: 1px solid #c2c2c2;
    border-radius: 4px;
    cursor: pointer;
    display: -ms-flexbox;
    display: flex;
    -ms-flex-direction: row;
    flex-direction: row;
    -ms-flex-pack: justify;
    justify-content: space-between;
    margin-top: 0;
    padding: 8px 16px;
    text-align: center
}

.orc-allReviewsCollections .orc-collectionControls-item-input--checked+.orc-collectionControls-item-label,.orc-allReviewsCollections .orc-collectionControls-item-input:checked+.orc-collectionControls-item-label {
    border: 1px solid #535565;
    box-shadow: 0 0 0 1px #535565
}

.orc-allReviewsCollections .orc-collectionControls-item {
    box-sizing: border-box;
    -ms-flex: 1 1 100%;
    flex: 1 1 100%;
    padding: 3px 9px
}

.orc-allReviewsCollections .orc-collectionControls-item-label-heading {
    display: block;
    -ms-flex-preferred-size: 66.66%;
    flex-basis: 66.66%;
    font-size: 18px;
    font-weight: 400;
    text-align: left
}

.orc-allReviewsCollections .orc-collectionControls-item-input {
    border: 0;
    clip: rect(0 0 0 0);
    height: 1px;
    margin: -1px;
    overflow: hidden;
    padding: 0;
    position: absolute;
    width: 1px
}

.orc-allReviewsCollections .orc-collectionControls-item-label-background {
    background-position: 100%;
    background-repeat: no-repeat;
    background-size: contain;
    display: block;
    -ms-flex-preferred-size: 33.33%;
    flex-basis: 33.33%;
    height: 50px;
    margin: 0
}

@media only screen and (min-width: 800px) {
    .orc-allReviewsCollections .orc-collectionControls {
        margin:-9px
    }

    .orc-allReviewsCollections .orc-collectionControls-item {
        -ms-flex: 1 1 50%;
        flex: 1 1 50%;
        padding: 9px
    }

    .orc-allReviewsCollections .orc-collectionControls .orc-collectionControls-item-label {
        -ms-flex-align: stretch;
        align-items: stretch;
        -ms-flex-direction: column;
        flex-direction: column;
        height: auto;
        padding: 16px
    }

    .orc-allReviewsCollections .orc-collectionControls-item-label-heading {
        -ms-flex-preferred-size: auto;
        flex-basis: auto;
        margin-bottom: 16px;
        text-align: center
    }

    .orc-allReviewsCollections .orc-collectionControls-item-label-background {
        background-position: 50%;
        -ms-flex-preferred-size: auto;
        flex-basis: auto;
        height: 150px;
        margin-top: auto;
        width: auto
    }
}

@media only screen and (min-width: 1200px) {
    .orc-allReviewsCollections .orc-collectionControls-item {
        -ms-flex:1 1 25%;
        flex: 1 1 25%
    }
}

@media all and (min-width: 1200px) {
    .orc-allReviewsCollections .orc-collectionControls-item {
        -ms-flex: 1 1 25%;
        flex: 1 1 15%;
    }

    .orc-allReviewsCollections .orc-collectionControls-item-label-heading {
        font-size: 16px;
    }
}

.orc-allReviewsCollections .orc-collectionControls .orc-collectionControls-item-label {
    border: 0;
}

#orc-collection-control {
  margin-bottom: 4em;
}
</style>
<div class="reviews-page-wrapper">
  <div class="orc-allReviewsCollections">
      <div id="orc-collection-control" style="display: none">
          <div id="orc-collection-controls-label" class="orc-collectionControlsLabel">Select a product range</div>
          <div class="orc-collectionControls" role="radiogroup" aria-labelledby="orc-collection-controls-label">
              <div class="orc-collectionControls-item">
                  <input
                      id="orc-reviews-control-0"
                      class="orc-collectionControls-item-input orc-collectionControls-item-input--checked js-orc-collectionRadio"
                      type="radio"
                      checked
                      value="<YOUR GROUP ID OR PRODUCT ID GOES HERE>"
                      name="orc-reviews-collection-control"
                  />
                  <label for="orc-reviews-control-0" class="orc-collectionControls-item-label">
                      <span class="orc-collectionControls-item-label-heading"> **<!-- YOUR GROUP NAME OR PRODUCT NAME GOES HERE .e.g Rings -->** </span>
														***<!-- OPTIONAL ADD AN IMAGE FOR THE GROUP/PRODUCT - IF NOT NEEDED, DELETE THE SPAN TAG BELOW -->***
                      <span
                          class="orc-collectionControls-item-label-background"
                          style="background-image: url('{{ 'ADD AN ASSET IMAGE URL.jpg' | asset_img_url: '150x' }}')"
                      ></span>
                  </label>
              </div>
              <div class="orc-collectionControls-item">
                  <input
                      id="orc-reviews-control-1"
                      class="orc-collectionControls-item-input js-orc-collectionRadio"
                      type="radio"
                      value="<YOUR GROUP ID OR PRODUCT ID GOES HERE>"
                      name="orc-reviews-collection-control"
                  />
                  <label for="orc-reviews-control-1" class="orc-collectionControls-item-label">
                      <span class="orc-collectionControls-item-label-heading"> **<!-- YOUR GROUP NAME OR PRODUCT NAME GOES HERE .e.g Rings -->** </span>
													***<!-- OPTIONAL ADD AN IMAGE FOR THE GROUP/PRODUCT - IF NOT NEEDED, DELETE THE SPAN TAG BELOW -->***
                      <span
                          class="orc-collectionControls-item-label-background"
                          style="background-image: url('{{ 'ADD AN ASSET IMAGE URL.jpg' | asset_img_url: '150x' }}')"
                      ></span>
                  </label>
              </div>
              <!-- Add More orc-collectionControls-item elements if you want to switch between more items -->
          </div>
      </div>
      **<!-- SET THE data-oke-reviews-product-id attribute to shopify-<YOUR PRODUCT ID> OR data-oke-reivews-group-id to the GUID you wish to default the widget to when the page loads (usually the first radio value in the list above -->**
      <div id="orc-widget-snippet" class="drp-okendo-reviews" data-oke-widget data-oke-reviews-group-id="<**YOUR DEFAULT GROUP ID GOES HERE>**"></div>
  </div>
  <script type="text/javascript">
  ((document, window) => {
    const okeRenderedHandler = function(e) {
        if (e.detail.widget === 'reviews-widget') {
         setupCollectionControls();
       }
    }
  
    document.addEventListener('oke-rendered', okeRenderedHandler);
  
    if (!String.prototype.startsWith) {
        Object.defineProperty(String.prototype, 'startsWith', {
            value: function(search, rawPos) {
                var pos = rawPos > 0 ? rawPos|0 : 0;
                return this.substring(pos, pos + search.length) === search;
            }
        });
    }
  
    function setupCollectionControls() {
        const snippetEl = document.querySelector('#orc-widget-snippet');
        const controlEl = document.querySelector('#orc-collection-control');
        const collectionRadioElements = Array.prototype.slice.call(document.querySelectorAll('.js-orc-collectionRadio'));
        controlEl.style.display = 'block';
        collectionRadioElements.forEach(function (radioElement) {
            radioElement.addEventListener('change', function () {
            if (radioElement.value) {
              if(radioElement.value.toLowerCase().startsWith('shopify-')) {
                snippetEl.removeAttribute('data-oke-reviews-group-id');
                window.okeWidgetApi.setProduct(snippetEl, radioElement.value);
              }
              else {
                snippetEl.removeAttribute('data-oke-reviews-product-id');
                window.okeWidgetApi.setGroup(snippetEl, radioElement.value);
              }
            } else {
              snippetEl.removeAttribute('data-oke-reviews-group-id');
              snippetEl.removeAttribute('data-oke-reviews-product-id');
              snippetEl.innerHTML = '';
              window.okeWidgetApi.initWidget(snippetEl, true);
            }

            collectionRadioElements.forEach(function (element) {
                element.classList.remove('orc-collectionControls-item-input--checked');
            });
            radioElement.classList.add('orc-collectionControls-item-input--checked');
          });
        });
  
      document.removeEventListener('oke-rendered', okeRenderedHandler);
    }
  })(document, window);
  </script>
```

4\. Modify the product/group IDs in the markup. For each group or product you wish to filter the reviews down by you will create a new `orc-collectionControls-item`. The value of the radio button will be either the Group ID (a group ID is in the form of a GUID) or the Product ID (a product ID is in the format `shopify-<YOUR PRODUCT ID>`:

```html
<div class="reviews-page-wrapper">
  <div class="orc-allReviewsCollections">
      <div id="orc-collection-control" style="display: none">
          <div id="orc-collection-controls-label" class="orc-collectionControlsLabel">Select a product range</div>
          <div class="orc-collectionControls" role="radiogroup" aria-labelledby="orc-collection-controls-label">
              <div class="orc-collectionControls-item">
                  <input
                      id="orc-reviews-control-0"
                      class="orc-collectionControls-item-input orc-collectionControls-item-input--checked js-orc-collectionRadio"
                      type="radio"
                      checked
                      value="<YOUR GROUP ID OR PRODUCT ID GOES HERE>"
                      name="orc-reviews-collection-control"
                  />
                  <label for="orc-reviews-control-0" class="orc-collectionControls-item-label">
                      <span class="orc-collectionControls-item-label-heading"> **<!-- YOUR GROUP NAME OR PRODUCT NAME GOES HERE .e.g Rings -->** </span>
														***<!-- OPTIONAL ADD AN IMAGE FOR THE GROUP/PRODUCT - IF NOT NEEDED, DELETE THE SPAN TAG BELOW -->***
                      <span
                          class="orc-collectionControls-item-label-background"
                          style="background-image: url('{{ 'ADD AN ASSET IMAGE URL.jpg' | asset_img_url: '150x' }}')"
                      ></span>
                  </label>
              </div>
              <div class="orc-collectionControls-item">
                  <input
                      id="orc-reviews-control-1"
                      class="orc-collectionControls-item-input js-orc-collectionRadio"
                      type="radio"
                      value="<YOUR GROUP ID OR PRODUCT ID GOES HERE>"
                      name="orc-reviews-collection-control"
                  />
                  <label for="orc-reviews-control-1" class="orc-collectionControls-item-label">
                      <span class="orc-collectionControls-item-label-heading"> **<!-- YOUR GROUP NAME OR PRODUCT NAME GOES HERE .e.g Rings -->** </span>
													***<!-- OPTIONAL ADD AN IMAGE FOR THE GROUP/PRODUCT - IF NOT NEEDED, DELETE THE SPAN TAG BELOW -->***
                      <span
                          class="orc-collectionControls-item-label-background"
                          style="background-image: url('{{ 'ADD AN ASSET IMAGE URL.jpg' | asset_img_url: '150x' }}')"
                      ></span>
                  </label>
              </div>
              <!-- Add More orc-collectionControls-item elements if you want to switch between more items -->
          </div>
      </div>
      **<!-- SET THE data-oke-reviews-product-id attribute to shopify-<YOUR PRODUCT ID> OR data-oke-reivews-group-id to the GUID you wish to default the widget to when the page loads (usually the first radio value in the list above -->**
      <div id="orc-widget-snippet" class="drp-okendo-reviews" data-oke-widget data-oke-reviews-group-id="<**YOUR DEFAULT GROUP ID GOES HERE>**"></div>
  </div>
```

<figure><img src="/files/z4XbtVntJi462IuwS8zM" alt=""><figcaption></figcaption></figure>

5\. Save the page template and exit the theme code editor.

6\. Navigate to Online Store -> Pages and assign the page template to a given page in the Shopify: Admin:

<figure><img src="/files/FS9pE9Stts2Q0C6FWVXX" alt=""><figcaption></figcaption></figure>

7\. View the page and confirm the switching is correct:

<figure><img src="/files/6N6Mgm6VzoGC6e5QzOjV" alt=""><figcaption></figcaption></figure>


# Storefront REST API

Use our public REST API from your storefront to build custom displays with your data.

## Usage

This is a public API that is intended to be used on a storefront or other public client to retrieve data from Okendo.

## Basics

This API is organised around REST with resource-based CRUD operations. Parameters for GET requests should be provided in the query string whereas POST/PUT request parameters should be provided as JSON in the body. JSON is also used for responses, including errors.

## Paths

All endpoints are relative to our base URL:

```
https://api.okendo.io/v1/stores/{okendo_user_id}
```

### Substitutions Reference

Throughout these docs you will see substitutions enclosed in `{}` (eg. `{okendo_user_id}`). Replace these (including the curly brackets) with the corresponding value:

`okendo_user_id`: Your Okendo User ID. This identifies your Okendo account. You can get this information from the Okendo section in the integration settings of the Okendo app.

`product_id`: A numerical Shopify Product ID.

`group_id`: An Okendo Group ID or a numerical Shopify Collection ID.

## Authentication

No authentication is required.

## Pagination

When listing large amounts of data, not all of it can be returned in a single request. We use pagination to break data up into reasonably sized chunks. When listing a resource, the response may include a `nextUrl` property to indicate that another page of results is available:

```json
{
    "reviews": [],
    "nextUrl": "/reviews..."
}
```

Append the `nextUrl` to the base path and make a GET request to that URL to retrieve the next page of results. Repeat this process until you have all the results you need or there are no more pages of results (there will be no `nextUrl`).

## Caching

When making repeated, identical calls to this API your response may be served from a cache. When this occurs any changes to the data since the response was cached may not be included. Making the request again after a short delay will refresh the results with any new changes.

## Versioning

Versioning is done via an HTTP header containing the required version. New versions of the API are released periodically. Provide the `okendo-api-version` header with a valid value in all requests. Valid versions:

* 2025-02-01


# Quick Start

Make your first request to the Storefront REST API in minutes

{% hint style="info" %}
This API is intended for client-side use. See [Storefront REST API](/on-site/storefront-rest-api) for usage details.
{% endhint %}

## Get Your Okendo User ID

Your Okendo User ID identifies your Okendo account. You can get this information from the Okendo section in the integration settings of the Okendo app.

## Make Your First Request

To make your first request, we'll send a request to the `/reviews` endpoint. This will retrieve some of your published `reviews`.

To make the request, first replace `{okendo_user_id}` in the path with the value you got from [#get-your-okendo-user-id](#get-your-okendo-user-id "mention"). Then use a networking client of your choice to make the request. Some example networking options are provided below:

{% tabs %}
{% tab title="Node.js Fetch" %}

```javascript
const response = await fetch('https://api.okendo.io/v1/stores/{okendo_user_id}/reviews', {
  headers: {
    'okendo-api-version': '2025-02-01'
  }
});

const data = await response.json();
```

{% endtab %}

{% tab title="cURL" %}

```bash
curl -X GET "https://api.okendo.io/v1/stores/{okendo_user_id}/reviews" \
  -H "okendo-api-version: 2025-02-01"
```

{% endtab %}
{% endtabs %}


# Endpoints

Full specifications of each API endpoint available in Okendo's Storefront REST API

## Getting Started

Before diving into the details, check out the usage guidelines ([Storefront REST API](/on-site/storefront-rest-api)) and the [Quick Start](/on-site/storefront-rest-api/quick-start) guide.

## Table of Contents

{% content-ref url="/pages/csD0mTo1w72X0yed5E8W" %}
[Reviews](/on-site/storefront-rest-api/endpoints/reviews)
{% endcontent-ref %}

{% content-ref url="/pages/VFSX1tTqpLHgbKHZj3AZ" %}
[Loyalty](/on-site/storefront-rest-api/endpoints/loyalty)
{% endcontent-ref %}

{% content-ref url="/pages/oTJfgDnZBocF13fVqC6J" %}
[Referrals](/on-site/storefront-rest-api/endpoints/referrals)
{% endcontent-ref %}


# Reviews

Storefront REST API endpoints related to Okendo Reviews

## List Reviews

Retrieve a list of published reviews relating to a specific resource.

#### By Product

```
GET /products/shopify-{product_id}/reviews
```

#### By Store

```
GET /reviews
```

#### By Group

```
GET /collections/{group_id}/reviews
```

#### Query Params

`limit`: Integer between 1 and 25. Default 25.

`orderBy`: One of: `date desc`, `date asc`, `rating desc`, `rating asc`, `helpful desc`, `helpful asc`, `has_media desc`. Default: `date desc`.

`locale`: One of the **locale query param** values below (e.g. `locale=es`):

{% hint style="info" %}
**Using the locale param requires translation settings to be configured in Okendo Admin.**

Review Translations are currently ONLY supported for reviews who's languages were automatically detected and the time of creation/import.

See: <https://support.okendo.io/en/articles/9684374-enabling-review-translation-for-multiple-languages>

for configuration before use. The translations settings for your review widgets should be configured to "On Load" in your Okendo settings.
{% endhint %}

| locale query param | Language              |
| ------------------ | --------------------- |
| `zh-TW`            | Chinese (Traditional) |
| `da`               | Danish                |
| `nl`               | Dutch                 |
| `en`               | English               |
| `fr`               | French                |
| `de-formal`        | German - Formal       |
| `de-informal`      | German - Informal     |
| `id`               | Indonesian            |
| `it`               | Italian               |
| `ja`               | Japanese              |
| `ko`               | Korean                |
| `pl`               | Polish                |
| `pt-PT`            | Portuguese            |
| `ru`               | Russian               |
| `es`               | Spanish               |
| `sv`               | Swedish               |
| `th`               | Thai                  |
| `vi`               | Vietnamese            |

#### Example

List the most recent 10 reviews the store has received:

```
GET https://api.okendo.io/v1/stores/{okendo_user_id}/reviews?limit=10&orderBy=date%20desc
```

## Get Review Aggregate

Get an aggregate of all the data related to published reviews for a specific resource.

#### By Product

```
GET /products/shopify-{product_id}/review_aggregate
```

#### By Store

```
GET /review_aggregate
```

#### By Group

```
GET /collections/{group_id}/review_aggregate
```

## List Review Media

Retrieve a list of published media attached to reviews relating to a specific resource. Ordered by most recent first.

#### By Product

```
GET /products/shopify-{product_id}/review_media
```

#### By Store

```
GET /review_media
```

#### By Group

```
GET /collections/{group_id}/review_media
```

#### Query Params

`limit`: Integer between 1 and 25. Default 25.

### Get Reviews Summary

Retrieve the AI-generated reviews summary for a specific product. If the product is part of a review group and configured to use a group summary, the summary for the group will be returned.

**By Product**

```
GET /products/shopify-{product_id}/reviews_summary
```

**Example**

Retrieve the reviews summary for a specific product:

```
GET https://api.okendo.io/v1/stores/{okendo_user_id}/products/shopify-{product_id}/reviews_summary
```

**Response Body Considerations**

The response typically includes a `reviewsSummary` object with the following fields if a summary is available:

* `body`: (string) The AI-generated text content of the reviews summary.
* `contributingReviewCount`: (number) The number of reviews that contributed to this summary.
* `dateGenerated`: (string, ISO 8601) The UTC date and time when the summary content was generated.
* `datePublished`: (string, ISO 8601) The UTC date and time when this summary version was published.

Example JSON Response (Success with data):

```json
{
  "reviewsSummary": {
    "body": "Customers generally find this product to be well-made and comfortable. Many highlight its stylish design and ease of use. While a few reviewers mention the sizing can be tricky, the overall sentiment is positive, with users appreciating the value and quality offered.",
    "contributingReviewCount": 88,
    "dateGenerated": "2024-03-15T10:30:00.123Z",
    "datePublished": "2024-03-16T11:00:00.456Z"
  }
}
```

**Important Notes:**

* A product/group generally needs a sufficient number of reviews (e.g., around 30 or more) for a summary to be eligible to be generated.
* Summaries need to be published (either by manual approval or by the auto-publish setting being toggled on) in order to be available.
* The API returns either a product-specific summary or a group-level summary based on the product's configuration in Okendo (i.e., whether it's set to display its own product reviews or shared group reviews for its summary).
* If no summary is available (e.g., insufficient reviews, not yet published/approved), the JSON response will be an empty object `{}`.

### Get Reviews Keywords

Retrieve the AI-generated keywords and topics for a specific product. If the product is part of a review group and configured to use group-level keywords, the keywords for the group will be returned.

**By Product**

```
GET /products/shopify-{product_id}/reviews_keywords
```

**Example**

Retrieve the reviews keywords for a specific product:

```
GET https://api.okendo.io/v1/stores/{okendo_user_id}/products/shopify-{product_id}/reviews_keywords
```

**Response Body Considerations**

The response includes a `reviewsKeywords` object, which contains a `keywordTopics` array if keywords are available.\
Each object within the `keywordTopics` array represents a broader theme and has the following structure:

* `topic`: (string) The name of the general theme (e.g., "Fit", "Comfort", "Quality").
* `keywords`: (array of objects) A list of specific keywords related to this topic.  \
  Each keyword object has:
  * `name`: (string) The specific keyword phrase (e.g., "sizing", "durability", "material quality").
  * `occurrences`: (number) The number of times this specific keyword was identified.

Example structure for the `reviewsKeywords` object:

```json
{
  "reviewsKeywords": {
    "keywordTopics": [
      {
        "topic": "Fit",
        "keywords": [
          { "name": "fit", "occurrences": 295 },
          { "name": "sizing", "occurrences": 138 },
          { "name": "size chart", "occurrences": 5 }
        ]
      },
      {
        "topic": "Comfort",
        "keywords": [
          { "name": "comfort", "occurrences": 79 },
          { "name": "stays put", "occurrences": 5 }
        ]
      }
      // ... other topics
    ]
  }
}
```

**Important Notes:**

* A product/group generally needs a sufficient number of reviews for keywords to be generated and available.
* The API returns either a product-specific keywords or a group-level keywords based on the product's configuration in Okendo (i.e., whether it's set to display its own product reviews or shared group reviews for its keywords).
* If no keywords are available (e.g., insufficient reviews, not yet processed), the JSON response will be an empty object `{}`.

## List Questions & Answers

Retrieve a list of published questions (and corresponding answers) relating to a specific resource. Ordered by most recent first.

#### By Product

```
GET /products/shopify-{product_id}/questions
```

#### By Group

```
GET /collections/{group_id}/questions
```

#### Query Params

`limit`: Integer between 1 and 25. Default 25.


# Loyalty

Storefront REST API endpoints related to Okendo Loyalty. Both unauthenticated and after customer authentication.

## Pre-Requisites

### Okendo Partner ID

If you're integrating with Okendo Loyalty using these APIs, send an email to <solutions@okendo.io> to retrieve the value of your `okendo-partner-id` header.

### Terminology

* **Earning Rule**: a way for a customer to earn points.
* **Redemption Rule**: a way for a customer to redeem points for a reward.
* **Transaction**: an instance of points being awarded or removed from a customer.

### Recommended Usage

For anonymous customers, use the [#unauthenticated](#unauthenticated "mention") endpoints to display general details about the loyalty program. Once a customer has logged into their Shopify account and you have their user token, you should call [#post-stores-subscriberid-loyalty-login](#post-stores-subscriberid-loyalty-login "mention") to exchange this for an Okendo Loyalty customer token (JWT).

Once you have an Okendo Loyalty customer token, you can call the customer-authenticated endpoints which will tailor the response content for that specific customer. For example some earning or redemption rules may only be available to certain customers or they will earn more points if they're on a certain VIP tier. To call these [#customer-authenticated](#customer-authenticated "mention") endpoints, provide your Okendo Loyalty customer token as Bearer authentication in the request header. *Note*: A customer that hasn’t enrolled in the loyalty program can still be logged in and shown details like their points balance and earning history. However to redeem points for rewards, be placed in a tier, and more they will need to enrol in the program.

#### Program Enrolment

Okendo requires each customer to explicitly enrol in the loyalty program. By using these APIs you agree to follow the following steps in compliance with our enrolment flow:

1. After the [#post-stores-subscriberid-loyalty-login](#post-stores-subscriberid-loyalty-login "mention") call, if the customer's `status` is `pending`, continue to step 2. If the customer's `status` is `blocked`, they should not have access to participate in the program. If the customer's `status` is `enrolled`, the following steps can be skipped as the customer has already agreed to the terms during previous enrolment.
2. Call the [#get-stores-subscriberid-loyalty-legal\_policies](#get-stores-subscriberid-loyalty-legal_policies "mention") endpoint to retrieve the policies and legal texts of the loyalty program (both by Okendo and by the merchant).
3. These terms **must** be shown to the customer before they agree to enrol in the loyalty program. The `acceptTermsAndJoinProgramButtonText` is to be used as the button text and the `policySentence.html` (or equivalent using `policySentence.template`, `privacyPolicyUrl` and `termsAndConditionsUrl`) is to be displayed below or above the opt-in button. The `version` of the terms is also provided and will be required in the next step. The following is an example of how the enrol button and terms are to be displayed.

   <figure><img src="/files/oYlDGMY0nMTO0XvD1hv9" alt="" width="322"><figcaption></figcaption></figure>
4. When the enrol button is clicked, call the [#post-loyalty-customer\_activation](#post-loyalty-customer_activation "mention") endpoint with the following body: `{ enrollmentChannel: <your_okendo_partner_id>, legalPoliciesVersionAccepted: <'version' field value from step 3> }`. *Note*: the `okendo-partner-id` header will need to be set to the same value as the `enrollmentChannel`.
5. The customer is now enrolled in the loyalty program. Their sign-up points will be awarded and their initial VIP tier will be set.

## Unauthenticated

## GET /stores/{subscriberId}/loyalty/earning\_rules

> Get Earning Rules

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"paths":{"/stores/{subscriberId}/loyalty/earning_rules":{"get":{"summary":"Get Earning Rules","tags":["loyalty"],"parameters":[{"name":"subscriberId","in":"path","required":true,"schema":{"type":"string"},"description":"The unique identifier for the store. Available on the Okendo integration settings page."},{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A list of earning rules","content":{"application/json":{"schema":{"type":"object","properties":{"earningRules":{"type":"array","items":{"type":"object","properties":{"earningRuleId":{"type":"string","format":"uuid","description":"Unique identifier for the earning rule"},"action":{"type":"string","enum":["sign-up","anniversary","birthday","custom-fixed","custom-points-per","purchase","answer-question","referral-invite","submit-review","facebook-like","facebook-share","instagram-follow","tiktok-follow","twitter-follow","twitter-post","submit-survey"],"description":"The specific action that triggers this earning rule"},"actionCategory":{"type":"string","enum":["account","custom","order","profile-question","referral","review","social","survey"],"description":"The category of action for this earning rule"},"actionLink":{"type":"string","format":"uri","description":"URL link for custom actions"},"dateComponentsToCapture":{"type":"string","enum":["day-month","day-month-year"],"description":"The parts of the date to capture in order to complete this rule (valid on birthday action only)"},"icon":{"description":"Icon for the earning rule - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"imageUrl":{"type":"string","format":"uri","description":"Image URL for the earning rule"},"pointsPerText":{"type":"string","description":"Text description for points-per rewards. In the format 'x points per {pointsPerText}'"},"promotion":{"description":"Associated promotion details if applicable","type":"object","properties":{"promotionId":{"type":"string","format":"uuid","description":"Unique identifier for the promotion"},"title":{"type":"string","description":"Display title for the promotion"},"description":{"type":"string","description":"Description of the promotion"},"type":{"type":"string","enum":["fixed-point","point-multiplier"],"description":"Type of promotion - fixed-point adds a fixed number of points, point-multiplier multiplies earned points"},"value":{"type":"number","description":"The promotion value - either fixed points to add or multiplier factor"},"icon":{"description":"Icon for the promotion - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"dateStart":{"type":"string","format":"date-time","description":"ISO date-time string when the promotion starts"},"dateEnd":{"type":"string","format":"date-time","description":"ISO date-time string when the promotion ends (optional for ongoing promotions)"},"appliesToEarningRules":{"type":"array","items":{"type":"string"},"description":"Array of earning rule IDs that this promotion applies to","minItems":1},"eligibleVipTiers":{"type":"array","items":{"type":"string"},"description":"Array of VIP tier IDs that are eligible for this promotion (optional - if not specified, applies to all tiers)"}},"required":["promotionId","title","description","type","value","icon","dateStart","appliesToEarningRules"]},"socialPageLink":{"type":"string","format":"uri","description":"Social media page link for social actions"},"title":{"type":"string","description":"Display title for the earning rule"},"reward":{"type":"object","required":["type"],"discriminator":{"propertyName":"type","mapping":{"fixed-amount":"./fixed-amount-reward.yaml","points-per":"./points-per-reward.yaml","points-per-spend":"./points-per-spend-reward.yaml","submit-review":"./submit-review-reward.yaml"}},"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["fixed-amount"]},"amount":{"type":"integer","minimum":1,"description":"Number of points awarded"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["points-per"]},"amount":{"type":"number","minimum":0.01,"description":"Points awarded per unit"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["points-per-spend"]},"amount":{"type":"number","minimum":0.01,"description":"Points awarded per currency unit spent"},"waitTimeDays":{"type":"integer","minimum":0,"description":"Waiting period in days before points are awarded"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["submit-review"]},"amountForReview":{"type":"integer","minimum":0,"description":"Points awarded for submitting a review"},"amountForSocialLogin":{"type":"integer","minimum":0,"description":"Points awarded for social login during review"},"amountForImage":{"type":"integer","minimum":0,"description":"Points awarded for including an image in review"},"amountForVideo":{"type":"integer","minimum":0,"description":"Points awarded for including a video in review"},"capPerOrder":{"type":"integer","minimum":0,"description":"Maximum points that can be earned per order"},"earnEachAmountOncePer":{"type":"string","enum":["order","review"],"description":"Whether each amount can be earned once per order or per review"}},"required":["type","amountForReview","amountForSocialLogin","amountForImage","amountForVideo","capPerOrder","earnEachAmountOncePer"]}],"description":"Reward configuration for this earning rule"}},"required":["earningRuleId","action","actionCategory","icon","title","reward"]}}}}}}}}}}}}
```

## GET /stores/{subscriberId}/loyalty/redemption\_rules

> Get Redemption Rules

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"paths":{"/stores/{subscriberId}/loyalty/redemption_rules":{"get":{"summary":"Get Redemption Rules","tags":["loyalty"],"parameters":[{"name":"subscriberId","in":"path","required":true,"schema":{"type":"string"},"description":"The unique identifier for the store. Available on the Okendo integration settings page."},{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}},{"name":"countryCode","in":"query","required":false,"schema":{"type":"string"},"description":"Country code for localisation"},{"name":"languageCode","in":"query","required":false,"schema":{"type":"string"},"description":"Language code for localisation"},{"name":"currencyCode","in":"query","required":false,"schema":{"type":"string"},"description":"Currency code for localisation"}],"responses":{"200":{"description":"A list of redemption rules","content":{"application/json":{"schema":{"type":"object","properties":{"redemptionRules":{"type":"array","items":{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"Unique identifier for the redemption rule"},"title":{"type":"string","description":"Display title for the redemption rule"},"type":{"type":"string","enum":["free-product","free-shipping","fixed-value","percentage-coupon","variable-value"],"description":"Type of redemption rule"},"icon":{"description":"Icon for the redemption rule - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"imageUrl":{"type":"string","format":"uri","description":"Image URL for the redemption rule"},"reward":{"oneOf":[{"type":"object","description":"Free product reward","properties":{"points":{"type":"integer"},"product":{"type":"object","properties":{"productId":{"type":"string"},"name":{"type":"string"},"imageUrl":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"},"price":{"type":"string"},"currencyCode":{"type":"string"}},"required":["productId","name"]},"variants":{"type":"array","items":{"type":"object","properties":{"variantRemoteId":{"type":"string"},"title":{"type":"string"},"price":{"type":"string"},"currencyCode":{"type":"string"}},"required":["variantRemoteId","title"]}}},"required":["points","product"]},{"type":"object","description":"A redemption for a percentage-off coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"}},"required":["points","value"]},{"type":"object","description":"A fixed-value redemption for store credit or a coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"},"awardVia":{"type":"string","enum":["store-credit","coupon"]},"localised":{"type":"object","properties":{"value":{"type":"number"},"formattedValue":{"type":"string"}},"required":["value","formattedValue"]}},"required":["points","value"]},{"type":"object","description":"A variable-value redemption for store credit or a coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"},"awardVia":{"type":"string","enum":["store-credit","coupon"]},"minimumPoints":{"type":"number"},"maximumPoints":{"type":"number"},"localised":{"type":"object","properties":{"value":{"type":"number"},"formattedValue":{"type":"string"}},"required":["value","formattedValue"]}},"required":["points","value"]},{"type":"object","description":"Free shipping reward","properties":{"points":{"type":"integer"},"maximumShipping":{"type":"number"}},"required":["points"]}]},"appliesToCollections":{"type":"array","items":{"type":"object","properties":{"collectionId":{"type":"string"},"title":{"type":"string"},"url":{"type":"string","format":"uri"}},"required":["collectionId","title"]},"description":"Collections this reward coupon will apply to"},"expiresAfterDays":{"type":"integer","description":"Number of days after which the reward expires"},"minimumPurchase":{"type":"number","description":"Minimum purchase amount required for the reward coupon to be valid in cart"},"purchaseType":{"type":"string","enum":["single","subscription","both"],"description":"Type of purchase that the reward coupon will apply to"},"recurringCycleLimit":{"type":"integer","description":"The number of recurring payments that the reward coupon will apply to for subscription purchases"}},"required":["redemptionRuleId","title","type","icon","reward"]}},"localisation":{"type":"object","description":"Optional localisation information for currency conversion","properties":{"currency":{"type":"object","properties":{"code":{"type":"string","description":"Currency code for localised values"},"exchangeRate":{"type":"number","description":"Exchange rate used for currency conversion"}},"required":["code","exchangeRate"]}},"required":["currency"]}},"required":["redemptionRules"]}}}}}}}}}
```

## GET /stores/{subscriberId}/loyalty/vip\_program

> Get VIP Program

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"paths":{"/stores/{subscriberId}/loyalty/vip_program":{"get":{"summary":"Get VIP Program","tags":["loyalty"],"parameters":[{"name":"subscriberId","in":"path","required":true,"schema":{"type":"string"},"description":"The unique identifier for the store. Available on the Okendo integration settings page."},{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"The VIP program details","content":{"application/json":{"schema":{"type":"object","properties":{"vipProgram":{"type":"object","properties":{"vipTiers":{"type":"array","items":{"type":"object","properties":{"vipTierId":{"type":"string","format":"uuid"},"name":{"type":"string"},"entryRequirement":{"type":"object","properties":{"spend":{"type":"integer"}},"required":["spend"]},"style":{"type":"object","properties":{"badge":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["framed"]},"icon":{"type":"string","description":"FontAwesome icon name"},"color":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$","description":"HexColorCode"},"frame":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["bronze","silver","gold","diamond","platinum"]}},"required":["type"]},{"type":"object","properties":{"type":{"type":"string","enum":["custom"]},"style":{"type":"object","properties":{"backgroundColor":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$","description":"HexColorCode"},"borderColor":{"type":"string","pattern":"^#[0-9A-Fa-f]{6}$","description":"HexColorCode"},"shineEffect":{"type":"boolean"}},"required":["backgroundColor","borderColor","shineEffect"]}},"required":["type","style"]}]},"svgUrl":{"type":"string","format":"uri"}},"required":["type","icon","color","frame","svgUrl"]},{"type":"object","properties":{"type":{"type":"string","enum":["uploaded"]},"url":{"type":"string","format":"uri"},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1}},"required":["type","url","width","height"]}]}},"required":["badge"]},"customPerks":{"type":"array","description":"Legacy custom perks represented as simple strings","items":{"type":"string"}},"structuredCustomPerks":{"type":"array","description":"Structured custom perks with full details including name, value type, value, and icon.","items":{"type":"object","properties":{"name":{"type":"string"},"valueType":{"type":"string","enum":["text","is-included"]},"value":{"oneOf":[{"type":"string"},{"type":"boolean","enum":[true]}]},"icon":{"oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Uploaded image","properties":{"url":{"type":"string","format":"uri"},"width":{"type":"integer","minimum":1},"height":{"type":"integer","minimum":1}},"required":["url","width","height"]}]}},"required":["name","valueType","value","icon"]}},"earningRules":{"type":"array","items":{"type":"object","properties":{"earningRuleId":{"type":"string","format":"uuid","description":"Unique identifier for the earning rule"},"action":{"type":"string","enum":["sign-up","anniversary","birthday","custom-fixed","custom-points-per","purchase","answer-question","referral-invite","submit-review","facebook-like","facebook-share","instagram-follow","tiktok-follow","twitter-follow","twitter-post","submit-survey"],"description":"The specific action that triggers this earning rule"},"actionCategory":{"type":"string","enum":["account","custom","order","profile-question","referral","review","social","survey"],"description":"The category of action for this earning rule"},"actionLink":{"type":"string","format":"uri","description":"URL link for custom actions"},"dateComponentsToCapture":{"type":"string","enum":["day-month","day-month-year"],"description":"The parts of the date to capture in order to complete this rule (valid on birthday action only)"},"icon":{"description":"Icon for the earning rule - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"imageUrl":{"type":"string","format":"uri","description":"Image URL for the earning rule"},"pointsPerText":{"type":"string","description":"Text description for points-per rewards. In the format 'x points per {pointsPerText}'"},"promotion":{"description":"Associated promotion details if applicable","type":"object","properties":{"promotionId":{"type":"string","format":"uuid","description":"Unique identifier for the promotion"},"title":{"type":"string","description":"Display title for the promotion"},"description":{"type":"string","description":"Description of the promotion"},"type":{"type":"string","enum":["fixed-point","point-multiplier"],"description":"Type of promotion - fixed-point adds a fixed number of points, point-multiplier multiplies earned points"},"value":{"type":"number","description":"The promotion value - either fixed points to add or multiplier factor"},"icon":{"description":"Icon for the promotion - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"dateStart":{"type":"string","format":"date-time","description":"ISO date-time string when the promotion starts"},"dateEnd":{"type":"string","format":"date-time","description":"ISO date-time string when the promotion ends (optional for ongoing promotions)"},"appliesToEarningRules":{"type":"array","items":{"type":"string"},"description":"Array of earning rule IDs that this promotion applies to","minItems":1},"eligibleVipTiers":{"type":"array","items":{"type":"string"},"description":"Array of VIP tier IDs that are eligible for this promotion (optional - if not specified, applies to all tiers)"}},"required":["promotionId","title","description","type","value","icon","dateStart","appliesToEarningRules"]},"socialPageLink":{"type":"string","format":"uri","description":"Social media page link for social actions"},"title":{"type":"string","description":"Display title for the earning rule"},"reward":{"type":"object","required":["type"],"discriminator":{"propertyName":"type","mapping":{"fixed-amount":"./fixed-amount-reward.yaml","points-per":"./points-per-reward.yaml","points-per-spend":"./points-per-spend-reward.yaml","submit-review":"./submit-review-reward.yaml"}},"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["fixed-amount"]},"amount":{"type":"integer","minimum":1,"description":"Number of points awarded"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["points-per"]},"amount":{"type":"number","minimum":0.01,"description":"Points awarded per unit"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["points-per-spend"]},"amount":{"type":"number","minimum":0.01,"description":"Points awarded per currency unit spent"},"waitTimeDays":{"type":"integer","minimum":0,"description":"Waiting period in days before points are awarded"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["submit-review"]},"amountForReview":{"type":"integer","minimum":0,"description":"Points awarded for submitting a review"},"amountForSocialLogin":{"type":"integer","minimum":0,"description":"Points awarded for social login during review"},"amountForImage":{"type":"integer","minimum":0,"description":"Points awarded for including an image in review"},"amountForVideo":{"type":"integer","minimum":0,"description":"Points awarded for including a video in review"},"capPerOrder":{"type":"integer","minimum":0,"description":"Maximum points that can be earned per order"},"earnEachAmountOncePer":{"type":"string","enum":["order","review"],"description":"Whether each amount can be earned once per order or per review"}},"required":["type","amountForReview","amountForSocialLogin","amountForImage","amountForVideo","capPerOrder","earnEachAmountOncePer"]}],"description":"Reward configuration for this earning rule"}},"required":["earningRuleId","action","actionCategory","icon","title","reward"]}},"redemptionRules":{"type":"array","items":{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"Unique identifier for the redemption rule"},"title":{"type":"string","description":"Display title for the redemption rule"},"type":{"type":"string","enum":["free-product","free-shipping","fixed-value","percentage-coupon","variable-value"],"description":"Type of redemption rule"},"icon":{"description":"Icon for the redemption rule - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"imageUrl":{"type":"string","format":"uri","description":"Image URL for the redemption rule"},"reward":{"oneOf":[{"type":"object","description":"Free product reward","properties":{"points":{"type":"integer"},"product":{"type":"object","properties":{"productId":{"type":"string"},"name":{"type":"string"},"imageUrl":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"},"price":{"type":"string"},"currencyCode":{"type":"string"}},"required":["productId","name"]},"variants":{"type":"array","items":{"type":"object","properties":{"variantRemoteId":{"type":"string"},"title":{"type":"string"},"price":{"type":"string"},"currencyCode":{"type":"string"}},"required":["variantRemoteId","title"]}}},"required":["points","product"]},{"type":"object","description":"A redemption for a percentage-off coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"}},"required":["points","value"]},{"type":"object","description":"A fixed-value redemption for store credit or a coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"},"awardVia":{"type":"string","enum":["store-credit","coupon"]},"localised":{"type":"object","properties":{"value":{"type":"number"},"formattedValue":{"type":"string"}},"required":["value","formattedValue"]}},"required":["points","value"]},{"type":"object","description":"A variable-value redemption for store credit or a coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"},"awardVia":{"type":"string","enum":["store-credit","coupon"]},"minimumPoints":{"type":"number"},"maximumPoints":{"type":"number"},"localised":{"type":"object","properties":{"value":{"type":"number"},"formattedValue":{"type":"string"}},"required":["value","formattedValue"]}},"required":["points","value"]},{"type":"object","description":"Free shipping reward","properties":{"points":{"type":"integer"},"maximumShipping":{"type":"number"}},"required":["points"]}]},"appliesToCollections":{"type":"array","items":{"type":"object","properties":{"collectionId":{"type":"string"},"title":{"type":"string"},"url":{"type":"string","format":"uri"}},"required":["collectionId","title"]},"description":"Collections this reward coupon will apply to"},"expiresAfterDays":{"type":"integer","description":"Number of days after which the reward expires"},"minimumPurchase":{"type":"number","description":"Minimum purchase amount required for the reward coupon to be valid in cart"},"purchaseType":{"type":"string","enum":["single","subscription","both"],"description":"Type of purchase that the reward coupon will apply to"},"recurringCycleLimit":{"type":"integer","description":"The number of recurring payments that the reward coupon will apply to for subscription purchases"}},"required":["redemptionRuleId","title","type","icon","reward"]}}},"required":["vipTierId","name","entryRequirement","style"]}}}}}}}}}}}}}}
```

## GET /stores/{subscriberId}/loyalty/faq

> Get FAQ

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"paths":{"/stores/{subscriberId}/loyalty/faq":{"get":{"summary":"Get FAQ","tags":["loyalty"],"parameters":[{"name":"subscriberId","in":"path","required":true,"schema":{"type":"string"},"description":"The unique identifier for the store. Available on the Okendo integration settings page."},{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A list of FAQ items","content":{"application/json":{"schema":{"type":"object","properties":{"faqItems":{"type":"array","items":{"type":"object","properties":{"question":{"type":"string"},"answer":{"type":"string"}}}}}}}}}}}}}}
```

## Get Legal Policies

> Retrieve legal policies information including terms and conditions, privacy policy URLs, and policy text templates for the loyalty program

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"paths":{"/stores/{subscriberId}/loyalty/legal_policies":{"get":{"summary":"Get Legal Policies","description":"Retrieve legal policies information including terms and conditions, privacy policy URLs, and policy text templates for the loyalty program","tags":["loyalty"],"parameters":[{"name":"subscriberId","in":"path","required":true,"schema":{"type":"string"},"description":"The unique identifier for the store. Available on the Okendo integration settings page."},{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Legal policies information","content":{"application/json":{"schema":{"type":"object","properties":{"acceptTermsAndJoinProgramButtonText":{"type":"string","description":"Text to display on the button for accepting terms and joining the program"},"policySentence":{"type":"object","description":"Policy sentence with template and HTML versions","properties":{"template":{"type":"string","description":"Template version of the policy sentence with placeholders"},"html":{"type":"string","description":"HTML version of the policy sentence with actual links"}},"required":["template","html"]},"privacyPolicyUrl":{"type":"string","format":"uri","description":"URL to the privacy policy"},"termsAndConditionsUrl":{"type":"string","format":"uri","description":"URL to the terms and conditions"},"version":{"type":"string","description":"Version of the legal policies"}},"required":["acceptTermsAndJoinProgramButtonText","policySentence","privacyPolicyUrl","termsAndConditionsUrl","version"]}}}}}}}}}
```

## POST /stores/{subscriberId}/loyalty/login

> Login

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"paths":{"/stores/{subscriberId}/loyalty/login":{"post":{"summary":"Login","tags":["loyalty"],"parameters":[{"name":"subscriberId","in":"path","required":true,"schema":{"type":"string"},"description":"The unique identifier for the store. Available on the Okendo integration settings page."},{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"customerAccessToken":{"type":"string"}}},{"type":"object","properties":{"storefrontAccessToken":{"type":"string","description":"The Shopify Storefront API access token that was used to generate the `storefrontCustomerAccessToken`. Created via the [storefrontAccessTokenCreate mutation](https://shopify.dev/docs/api/admin-graphql/latest/mutations/storefrontAccessTokenCreate) or another equivalent method."},"storefrontCustomerAccessToken":{"type":"string","description":"A customer access token retrieved via the Shopify Storefront API using the [customerAccessTokenCreate mutation](https://shopify.dev/docs/api/storefront/latest/mutations/customeraccesstokencreate) or another equivalent method."}},"required":["storefrontAccessToken","storefrontCustomerAccessToken"]}]}}}},"responses":{"200":{"description":"Login successful","content":{"application/json":{"schema":{"type":"object","properties":{"jwt":{"type":"string","description":"A session token for this customer. Provide this in calls to our customer-authenticated endpoints to get responses tailored to this customer."},"loyaltyCustomerDetails":{"type":"object","properties":{"balance":{"type":"integer","description":"The customer's points balance"},"status":{"type":"string","enum":["enrolled","pending","blocked"],"description":"The customer's loyalty program status"},"vipTierId":{"type":"string","format":"uuid","description":"The customer's VIP Tier identifier"}},"required":["balance","status"]}}}}}}}}}}}
```

## Customer Authenticated

## Get Customer Details

> Retrieve detailed information about the authenticated loyalty customer

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/customer_details":{"get":{"summary":"Get Customer Details","tags":["loyalty"],"description":"Retrieve detailed information about the authenticated loyalty customer","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Customer details retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"loyaltyCustomer":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"Customer's email address"},"dateEnrolled":{"type":"string","format":"date-time","description":"Date when customer enrolled in loyalty program"},"dateTierExpires":{"type":"string","format":"date-time","description":"Date when current VIP tier expires"},"fullName":{"type":"string","description":"Customer's full name"},"avatarDynamicKey":{"type":"string","description":"Dynamic key for customer avatar image"},"status":{"type":"string","enum":["enrolled","pending","blocked"],"description":"The customer's loyalty program status"},"vipTierId":{"type":"string","format":"uuid","description":"The customer's VIP Tier identifier"},"isTierLocked":{"type":"boolean","description":"Whether the customer's tier is locked"},"minimumVipTierId":{"type":"string","format":"uuid","description":"The customer's minimum VIP Tier identifier. The customer cannot be moved below this tier."},"points":{"type":"object","properties":{"balance":{"type":"integer","description":"The customer's points balance"},"dateUpdated":{"type":"string","format":"date-time","description":"Date when points were last updated"},"pending":{"type":"integer","description":"Points that are pending a cool-off period"},"spent":{"type":"integer","description":"Total points spent by customer"}},"required":["balance","dateUpdated","pending","spent"]},"referralSender":{"type":"object","properties":{"referralSenderId":{"type":"string","format":"uuid","description":"Referral sender identifier"},"shareableLinkUrl":{"type":"string","format":"uri","description":"Shareable referral link URL"}},"required":["referralSenderId","shareableLinkUrl"]},"rewardsClaimed":{"type":"number","description":"Number of rewards claimed by customer"},"birthday":{"type":"object","properties":{"day":{"type":"integer","minimum":1,"maximum":31,"description":"Day of birth"},"month":{"type":"integer","minimum":1,"maximum":12,"description":"Month of birth"},"year":{"type":"integer","minimum":1900,"maximum":2025,"description":"Year of birth"}},"required":["day","month"]}},"required":["points","rewardsClaimed","status"]}},"required":["loyaltyCustomer"]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"404":{"description":"Customer not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"409":{"description":"Conflict - Unable to load customer data","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Activate (Enrol) Loyalty Customer

> Enrol a customer into the loyalty program

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/customer_activation":{"post":{"summary":"Activate (Enrol) Loyalty Customer","tags":["loyalty"],"description":"Enrol a customer into the loyalty program","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enrollmentChannel":{"type":"string","description":"The channel through which the customer is enrolling into the loyalty program"},"legalPoliciesVersionAccepted":{"type":"string","description":"Version of legal policies accepted by the customer. To fetch the legal policies to display and their version, call the `GET /stores/{subscriberId}/loyalty/legal_policies` endpoint."}},"required":["enrollmentChannel","legalPoliciesVersionAccepted"]}}}},"responses":{"200":{"description":"Customer activated successfully","content":{"application/json":{"schema":{"type":"object","properties":{"loyaltyCustomer":{"type":"object","properties":{"dateEnrolled":{"type":"string","format":"date-time","description":"Date when customer enrolled in loyalty program"},"points":{"type":"object","properties":{"balance":{"type":"integer","description":"The customer's points balance"},"dateUpdated":{"type":"string","format":"date-time","description":"Date when points were last updated"},"pending":{"type":"integer","description":"Points that are pending a cool-off period"},"spent":{"type":"integer","description":"Total points spent by customer"}},"required":["balance","dateUpdated","pending","spent"]},"rewardsClaimed":{"type":"number","description":"Number of rewards claimed by customer"},"status":{"type":"string","enum":["enrolled","pending","blocked"],"description":"The customer's loyalty program status"},"vipTierId":{"type":"string","format":"uuid","description":"The customer's VIP Tier identifier"}},"required":["dateEnrolled","points","rewardsClaimed","status","vipTierId"]}},"required":["loyaltyCustomer"]}}}},"400":{"description":"Bad Request - Invalid customer identifier or subscriber ID","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"403":{"description":"Forbidden - Customer blocked, loyalty feature missing, or access denied","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"404":{"description":"Not Found - Loyalty customer not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"500":{"description":"Internal Server Error - Failed to activate customer","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Get Earning Rules For Customer

> Retrieve earning rules for the authenticated customer, including completion status

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/earning_rules":{"get":{"summary":"Get Earning Rules For Customer","tags":["loyalty"],"description":"Retrieve earning rules for the authenticated customer, including completion status","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Earning rules retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"earningRules":{"type":"array","items":{"allOf":[{"type":"object","properties":{"earningRuleId":{"type":"string","format":"uuid","description":"Unique identifier for the earning rule"},"action":{"type":"string","enum":["sign-up","anniversary","birthday","custom-fixed","custom-points-per","purchase","answer-question","referral-invite","submit-review","facebook-like","facebook-share","instagram-follow","tiktok-follow","twitter-follow","twitter-post","submit-survey"],"description":"The specific action that triggers this earning rule"},"actionCategory":{"type":"string","enum":["account","custom","order","profile-question","referral","review","social","survey"],"description":"The category of action for this earning rule"},"actionLink":{"type":"string","format":"uri","description":"URL link for custom actions"},"dateComponentsToCapture":{"type":"string","enum":["day-month","day-month-year"],"description":"The parts of the date to capture in order to complete this rule (valid on birthday action only)"},"icon":{"description":"Icon for the earning rule - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"imageUrl":{"type":"string","format":"uri","description":"Image URL for the earning rule"},"pointsPerText":{"type":"string","description":"Text description for points-per rewards. In the format 'x points per {pointsPerText}'"},"promotion":{"description":"Associated promotion details if applicable","type":"object","properties":{"promotionId":{"type":"string","format":"uuid","description":"Unique identifier for the promotion"},"title":{"type":"string","description":"Display title for the promotion"},"description":{"type":"string","description":"Description of the promotion"},"type":{"type":"string","enum":["fixed-point","point-multiplier"],"description":"Type of promotion - fixed-point adds a fixed number of points, point-multiplier multiplies earned points"},"value":{"type":"number","description":"The promotion value - either fixed points to add or multiplier factor"},"icon":{"description":"Icon for the promotion - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"dateStart":{"type":"string","format":"date-time","description":"ISO date-time string when the promotion starts"},"dateEnd":{"type":"string","format":"date-time","description":"ISO date-time string when the promotion ends (optional for ongoing promotions)"},"appliesToEarningRules":{"type":"array","items":{"type":"string"},"description":"Array of earning rule IDs that this promotion applies to","minItems":1},"eligibleVipTiers":{"type":"array","items":{"type":"string"},"description":"Array of VIP tier IDs that are eligible for this promotion (optional - if not specified, applies to all tiers)"}},"required":["promotionId","title","description","type","value","icon","dateStart","appliesToEarningRules"]},"socialPageLink":{"type":"string","format":"uri","description":"Social media page link for social actions"},"title":{"type":"string","description":"Display title for the earning rule"},"reward":{"type":"object","required":["type"],"discriminator":{"propertyName":"type","mapping":{"fixed-amount":"./fixed-amount-reward.yaml","points-per":"./points-per-reward.yaml","points-per-spend":"./points-per-spend-reward.yaml","submit-review":"./submit-review-reward.yaml"}},"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["fixed-amount"]},"amount":{"type":"integer","minimum":1,"description":"Number of points awarded"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["points-per"]},"amount":{"type":"number","minimum":0.01,"description":"Points awarded per unit"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["points-per-spend"]},"amount":{"type":"number","minimum":0.01,"description":"Points awarded per currency unit spent"},"waitTimeDays":{"type":"integer","minimum":0,"description":"Waiting period in days before points are awarded"}},"required":["type","amount"]},{"type":"object","properties":{"type":{"type":"string","enum":["submit-review"]},"amountForReview":{"type":"integer","minimum":0,"description":"Points awarded for submitting a review"},"amountForSocialLogin":{"type":"integer","minimum":0,"description":"Points awarded for social login during review"},"amountForImage":{"type":"integer","minimum":0,"description":"Points awarded for including an image in review"},"amountForVideo":{"type":"integer","minimum":0,"description":"Points awarded for including a video in review"},"capPerOrder":{"type":"integer","minimum":0,"description":"Maximum points that can be earned per order"},"earnEachAmountOncePer":{"type":"string","enum":["order","review"],"description":"Whether each amount can be earned once per order or per review"}},"required":["type","amountForReview","amountForSocialLogin","amountForImage","amountForVideo","capPerOrder","earnEachAmountOncePer"]}],"description":"Reward configuration for this earning rule"}},"required":["earningRuleId","action","actionCategory","icon","title","reward"]},{"type":"object","properties":{"isCompleted":{"type":"boolean","description":"Whether the customer has completed this earning rule"}},"required":["isCompleted"]}]},"description":"List of earning rules with completion status for the authenticated customer"}},"required":["earningRules"]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"404":{"description":"Customer or subscriber not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Trigger Social Earning Rule

> Trigger a social earning rule to earn points for the authenticated customer

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/earning_rules/{earningRuleId}/trigger":{"post":{"summary":"Trigger Social Earning Rule","tags":["loyalty"],"description":"Trigger a social earning rule to earn points for the authenticated customer","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}},{"name":"earningRuleId","in":"path","required":true,"schema":{"type":"string"},"description":"The unique identifier for the earning rule to trigger"}],"requestBody":{"description":"Empty request body","content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"Earning rule triggered successfully","content":{"application/json":{"schema":{"type":"object","properties":{"pointsEarned":{"type":"integer","description":"Number of points earned by triggering the earning rule"}},"required":["pointsEarned"]}}}},"400":{"description":"Bad request - Invalid earning rule or customer","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"403":{"description":"Forbidden - Customer not enrolled or invalid earning rule type","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"404":{"description":"Earning rule not found or inactive","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Update Customer Birthday

> Updates the birthday for the given customer.

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/customer_birthday":{"put":{"summary":"Update Customer Birthday","tags":["loyalty"],"description":"Updates the birthday for the given customer.","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"day":{"type":"integer","minimum":1,"maximum":31,"description":"The day of the month, from 1 to 31."},"month":{"type":"integer","minimum":1,"maximum":12,"description":"The month of the year, from 1 to 12."}},"required":["day","month"]}}}},"responses":{"204":{"description":"Successfully updated customer birthday."},"400":{"description":"Bad Request - Invalid birthday provided.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"404":{"description":"Not Found - Customer or subscriber not found.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Get Redemption Rules For Customer

> Retrieve redemption rules for the authenticated customer with localization support

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/redemption_rules":{"get":{"summary":"Get Redemption Rules For Customer","tags":["loyalty"],"description":"Retrieve redemption rules for the authenticated customer with localization support","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}},{"name":"languageCode","in":"query","required":false,"schema":{"type":"string"},"description":"Language code for localization"},{"name":"countryCode","in":"query","required":false,"schema":{"type":"string"},"description":"Country code for localization"},{"name":"currencyCode","in":"query","required":false,"schema":{"type":"string"},"description":"Currency code for localization"}],"responses":{"200":{"description":"Redemption rules retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"redemptionRules":{"type":"array","items":{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"Unique identifier for the redemption rule"},"title":{"type":"string","description":"Display title for the redemption rule"},"type":{"type":"string","enum":["free-product","free-shipping","fixed-value","percentage-coupon","variable-value"],"description":"Type of redemption rule"},"icon":{"description":"Icon for the redemption rule - either a FontAwesome icon name or custom image","oneOf":[{"type":"string","description":"FontAwesome icon name"},{"type":"object","description":"Icon object with URL and dimensions","properties":{"url":{"type":"string","format":"uri","description":"URL of the custom icon image"},"width":{"type":"integer","minimum":1,"description":"Width of the icon image in pixels"},"height":{"type":"integer","minimum":1,"description":"Height of the icon image in pixels"}},"required":["url","width","height"]}]},"imageUrl":{"type":"string","format":"uri","description":"Image URL for the redemption rule"},"reward":{"oneOf":[{"type":"object","description":"Free product reward","properties":{"points":{"type":"integer"},"product":{"type":"object","properties":{"productId":{"type":"string"},"name":{"type":"string"},"imageUrl":{"type":"string","format":"uri"},"url":{"type":"string","format":"uri"},"price":{"type":"string"},"currencyCode":{"type":"string"}},"required":["productId","name"]},"variants":{"type":"array","items":{"type":"object","properties":{"variantRemoteId":{"type":"string"},"title":{"type":"string"},"price":{"type":"string"},"currencyCode":{"type":"string"}},"required":["variantRemoteId","title"]}}},"required":["points","product"]},{"type":"object","description":"A redemption for a percentage-off coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"}},"required":["points","value"]},{"type":"object","description":"A fixed-value redemption for store credit or a coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"},"awardVia":{"type":"string","enum":["store-credit","coupon"]},"localised":{"type":"object","properties":{"value":{"type":"number"},"formattedValue":{"type":"string"}},"required":["value","formattedValue"]}},"required":["points","value"]},{"type":"object","description":"A variable-value redemption for store credit or a coupon","properties":{"points":{"type":"integer"},"value":{"type":"number"},"awardVia":{"type":"string","enum":["store-credit","coupon"]},"minimumPoints":{"type":"number"},"maximumPoints":{"type":"number"},"localised":{"type":"object","properties":{"value":{"type":"number"},"formattedValue":{"type":"string"}},"required":["value","formattedValue"]}},"required":["points","value"]},{"type":"object","description":"Free shipping reward","properties":{"points":{"type":"integer"},"maximumShipping":{"type":"number"}},"required":["points"]}]},"appliesToCollections":{"type":"array","items":{"type":"object","properties":{"collectionId":{"type":"string"},"title":{"type":"string"},"url":{"type":"string","format":"uri"}},"required":["collectionId","title"]},"description":"Collections this reward coupon will apply to"},"expiresAfterDays":{"type":"integer","description":"Number of days after which the reward expires"},"minimumPurchase":{"type":"number","description":"Minimum purchase amount required for the reward coupon to be valid in cart"},"purchaseType":{"type":"string","enum":["single","subscription","both"],"description":"Type of purchase that the reward coupon will apply to"},"recurringCycleLimit":{"type":"integer","description":"The number of recurring payments that the reward coupon will apply to for subscription purchases"}},"required":["redemptionRuleId","title","type","icon","reward"]},"description":"List of redemption rules available to the authenticated customer"},"localisation":{"type":"object","description":"Localization information including currency details","properties":{"currency":{"type":"object","properties":{"code":{"type":"string","description":"Three letter currency code"},"exchangeRate":{"type":"number","description":"Exchange rate for currency conversion"}},"required":["code","exchangeRate"]}},"required":["currency"]}},"required":["redemptionRules"]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"404":{"description":"Customer or subscriber not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Redeem Points

> Redeem loyalty points for rewards using a redemption rule

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/redemptions":{"post":{"summary":"Redeem Points","tags":["loyalty"],"description":"Redeem loyalty points for rewards using a redemption rule","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"description":"Redemption request details","content":{"application/json":{"schema":{"type":"object","properties":{"redemptionRuleId":{"type":"string","format":"uuid","description":"The unique identifier of the redemption rule to use"},"variableValue":{"type":"object","description":"Variable value selected by the customer for redemption rules that support variable amounts. Required for variable value redemptions. Ignored for other redemption types.","properties":{"points":{"type":"integer","description":"The number of points to redeem"},"value":{"type":"number","description":"The value of the reward in currency"}}},"localisation":{"type":"object","description":"Localization settings for the redemption","properties":{"currencyCode":{"type":"string","description":"Currency code used to generate the localized client value"},"clientValue":{"type":"number","description":"The value of the reward in the localized currency"},"locale":{"type":"string","description":"Locale for localization"}},"required":["currencyCode","clientValue"]}},"required":["redemptionRuleId"]}}}},"responses":{"200":{"description":"Points redeemed successfully","content":{"application/json":{"schema":{"type":"object","properties":{"reward":{"type":"object","properties":{"rewardType":{"type":"string","enum":["coupon","store-credit"],"description":"Type of reward received"},"result":{"description":"Result of the redemption operation - either success with reward data or failure with error details","oneOf":[{"type":"object","properties":{"success":{"type":"boolean","enum":[true]},"data":{"oneOf":[{"type":"object","properties":{"code":{"type":"string","description":"Coupon code"}},"required":["code"]},{"type":"object","properties":{"currencyCode":{"type":"string","description":"Currency code for the store credit"},"storeCreditTransactionAmount":{"type":"string","description":"Amount of store credit awarded in this transaction"},"balanceAmount":{"type":"string","description":"Total store credit balance after this transaction"}},"required":["currencyCode","storeCreditTransactionAmount","balanceAmount"]}]}},"required":["success","data"]},{"type":"object","properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"object","properties":{"code":{"type":"string","enum":["shopify-error","timeout-error"],"description":"Error code indicating the type of failure"},"message":{"type":"string","description":"Human-readable error message"}},"required":["code"]}},"required":["success","error"]}]}},"required":["rewardType","result"]},"customerPoints":{"type":"object","properties":{"balance":{"type":"number","description":"Customer's updated points balance after redemption"},"dateUpdated":{"type":"string","format":"date-time","description":"Date when points were last updated"},"pending":{"type":"number","description":"Points that are pending approval"},"spent":{"type":"number","description":"Total points spent by customer (including this redemption)"}},"required":["balance","dateUpdated","pending","spent"]}},"required":["reward","customerPoints"]}}}},"400":{"description":"Bad request - Invalid redemption rule or request","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"403":{"description":"Forbidden - Customer not enrolled, insufficient points, or ineligible for rule","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"404":{"description":"Customer not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"422":{"description":"Unprocessable entity - Currency exchange mismatch","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Get Loyalty Transactions

> Retrieve paginated list of loyalty transactions for the authenticated customer

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/transactions":{"get":{"summary":"Get Loyalty Transactions","tags":["loyalty"],"description":"Retrieve paginated list of loyalty transactions for the authenticated customer","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25},"description":"Maximum number of transactions to return"},{"name":"lastEvaluated","in":"query","required":false,"schema":{"type":"string"},"description":"Token for pagination to get the next page of results"},{"name":"orderBy","in":"query","required":false,"schema":{"type":"string","enum":["date desc"],"default":"date desc"},"description":"Field and direction to order results by"}],"responses":{"200":{"description":"Loyalty transactions retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"transactions":{"type":"array","items":{"type":"object","properties":{"loyaltyTransactionId":{"type":"string","format":"uuid","description":"Unique identifier for the loyalty transaction"},"amount":{"type":"integer","description":"Points amount for the transaction (positive for earning, negative for redemption)"},"notificationText":{"type":"string","description":"Human-readable text describing the transaction"},"date":{"type":"string","format":"date-time","description":"Date and time when the transaction occurred"},"status":{"type":"string","enum":["complete","pending","declined"],"description":"Current status of the transaction"},"type":{"type":"string","enum":["earn","redeem","adjustment"],"description":"Type of transaction"},"bonusPoints":{"type":"integer","description":"Additional bonus points earned from promotions (only present for earn transactions)"}},"required":["loyaltyTransactionId","amount","date","status","type"]},"description":"List of loyalty transactions for the customer"},"nextUrl":{"type":"string","format":"uri","description":"URL for the next page of results"}},"required":["transactions"]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Get Customer Spend

> Retrieve the customer's spending amount within the current VIP tier eligibility period

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/customer_spend":{"get":{"summary":"Get Customer Spend","tags":["loyalty"],"description":"Retrieve the customer's spending amount within the current VIP tier eligibility period","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Customer spend retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"customerSpend":{"type":"number","description":"Total amount spent by the customer in the current VIP tier eligibility period"},"dateFrom":{"type":"string","format":"date-time","description":"Start date of the spending period (ISO 8601 format)"}},"required":["customerSpend","dateFrom"]}}}},"401":{"description":"Unauthorized - Invalid or missing authentication token","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"403":{"description":"Forbidden - Loyalty program not launched or customer not enrolled","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}},"404":{"description":"Customer not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

### Loyalty x Referrals

{% hint style="info" %}
Before making a referral, the customer will need to be registered as a "referral sender". See [Referrals](/on-site/storefront-rest-api/endpoints/referrals).
{% endhint %}

## Send Referral Request

> Sends a referral request to the specified email address

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/referrals":{"post":{"summary":"Send Referral Request","tags":["loyalty"],"description":"Sends a referral request to the specified email address","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","description":"The email of the person being referred to the loyalty program"},"referralSenderId":{"type":"string","format":"uuid","description":"The Referral Sender ID of the loyalty member. This can be found in the response from the `Get Customer Details` authenticated endpoint."}},"required":["email","referralSenderId"]}}}},"responses":{"204":{"description":"Successfully sent referral request."},"400":{"description":"Bad Request - Unable to create referral.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```

## Get Referral History

> Retrieves the referral history for the authenticated customer

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/referrals":{"get":{"summary":"Get Referral History","tags":["loyalty"],"description":"Retrieves the referral history for the authenticated customer","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}},{"name":"lastEvaluated","in":"query","required":false,"schema":{"type":"string"},"description":"Token for pagination to get the next page of results"}],"responses":{"200":{"description":"Referral history retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"referrals":{"type":"array","items":{"type":"object","properties":{"dateCreated":{"type":"string","format":"date-time","description":"Date and time when the referral was made"},"recipient":{"type":"object","description":"Details of the person who received the referral invitation","properties":{"email":{"type":"string","format":"email"}}},"status":{"type":"string","enum":["complete","pending","declined"],"description":"Current status of the referral"}},"required":["dateCreated","recipient","status"]},"description":"List of referrals for the customer"},"nextUrl":{"type":"string","format":"uri","description":"URL for the next page of results"}},"required":["referrals","nextUrl"]}}}}}}}}}
```

## Get Referral Count

> Retrieves the number of referrals by an authenticated customer

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API (Customer Authed)","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"security":[{"BearerAuth":[]}],"components":{"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT token for authenticated customer"}}},"paths":{"/loyalty/referral_aggregate":{"get":{"summary":"Get Referral Count","tags":["loyalty"],"description":"Retrieves the number of referrals by an authenticated customer","parameters":[{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"Referral count retrieved successfully","content":{"application/json":{"schema":{"type":"object","properties":{"referralsTotal":{"type":"number"}},"required":["referralsTotal"]}}}}}}}}}
```


# Referrals

Storefront REST API endpoints related to Okendo Referrals

## POST /stores/{subscriberId}/referral\_senders

> Create Referral Sender

```json
{"openapi":"3.0.0","info":{"title":"Okendo Storefront API","version":"1.1.0"},"servers":[{"url":"https://api.okendo.io/v1"}],"paths":{"/stores/{subscriberId}/referral_senders":{"post":{"summary":"Create Referral Sender","tags":["referrals"],"parameters":[{"name":"subscriberId","in":"path","required":true,"schema":{"type":"string"},"description":"The unique identifier for the store. Available on the Okendo integration settings page."},{"name":"okendo-api-version","in":"header","required":true,"schema":{"type":"string","enum":["2025-02-01"]},"description":"API version header"},{"name":"okendo-partner-id","in":"header","required":false,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":["email"]}}}},"responses":{"200":{"description":"Successfully created referral sender","content":{"application/json":{"schema":{"type":"object","properties":{"referralSenderId":{"type":"string","format":"uuid","description":"The Referral Sender ID is required for sending referral requests via authenticated endpoints"},"shareableLinkUrl":{"type":"string","format":"uri","description":"A URL which can be sent as a referral link"}},"required":["referralSenderId","shareableLinkUrl"]}}}},"400":{"description":"Bad Request - Invalid email address","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"description":{"type":"string","description":"Human-readable error message"},"code":{"type":"string","description":"Error code identifier"}},"required":["description"]}},"required":["error"]}}}}}}}}}
```


# Advanced Widget Installs

{% content-ref url="/pages/ia8XUCBmDgCbzJ1unPPA" %}
[Installing Reviews on Headless Instances](/on-site/advanced-widget-installs/installing-widget-plus-on-headless-instances)
{% endcontent-ref %}

{% content-ref url="/pages/hptUCMMv0OekFD30Beuj" %}
[Installing Surveys on Headless Instances](/on-site/advanced-widget-installs/installing-connect-surveys-on-headless-instances)
{% endcontent-ref %}

{% content-ref url="/pages/gcl0ncDa4bOBR38UBmQg" %}
[Installing Quizzes on Headless Instances](/on-site/advanced-widget-installs/installing-quizzes-on-headless-instances)
{% endcontent-ref %}

{% content-ref url="/pages/h2VjIBAgmOC6sP5ftMv2" %}
[Stores Running an Existing Vue App](/on-site/advanced-widget-installs/stores-running-an-existing-vue-app)
{% endcontent-ref %}

{% content-ref url="/pages/g766NslRnwRVl7cQL3eb" %}
[Installing Quizzes with Custom Carts](/on-site/advanced-widget-installs/installing-quizzes-with-custom-carts)
{% endcontent-ref %}


# Installing Reviews on Headless Instances

Headless installs are available for merchants on our Advanced plan or above.

We have a number of resources/examples to help get your started, and our dedicated support team is available to help answer any queries about your specific headless requirements.

### Headless Examples

1. Shopify Hydrogen - <https://github.com/okendo/okendo-shopify-hydrogen-demo>
2. React - <https://github.com/okendo/okendo-reactjs-example>
3. Vue - <https://github.com/okendo/okendo-vuejs-example>


# Installing Loyalty on Headless Instances

### Overview <a href="#overview" id="overview"></a>

For stores specifically running Shopify Hydrogen 2, please [look here](https://docs.okendo.io/okendo-shopify-hydrogen-support) for further support.

This guide explains how to integrate Okendo Loyalty into your headless Shopify store. The implementation requires 2-3 code snippets depending on your needs.

**Prerequisites:**

* Active Okendo Loyalty subscription
* Headless Shopify storefront
* Customer authentication implemented (via Customer Account API or Storefront API)

**Quick Links:**

* [Required: Loyalty Settings](https://untitled+.vscode-resource.vscode-cdn.net/Untitled-1#1-loyalty-settings-metafield)
* [Required: Customer Authentication](https://untitled+.vscode-resource.vscode-cdn.net/Untitled-1#2-customer-access-token-script-tag)
* [Optional: Additional Widgets](https://untitled+.vscode-resource.vscode-cdn.net/Untitled-1#3-loyalty-landing-page--other-widgets-optional)

### Implementation Steps <a href="#implementation-steps" id="implementation-steps"></a>

To implement Okendo Loyalty, you will need to render two or three snippets on your store:

### 1. Loyalty Settings Metafield <a href="#id-1-loyalty-settings-metafield" id="id-1-loyalty-settings-metafield"></a>

Located in your Shop Metafields, under the `okendo` namespace and `LoyaltySettings` key, you will find a snippet containing 2 script tags (one for the loyalty widget settings, and one for the initialisation script).

**Purpose:** Loads the Loyalty App with your customized settings and displays the Floating Widget.

**Implementation:** Render the metafield content in the `<head>` section of your store pages.

```liquid
<!-- Liquid example -->
{{ shop.metafields.okendo.LoyaltySettings }}
```

```javascript
// GraphQL query example (for Hydrogen/Remix)
query metafields {
  shop {
    metafield(namespace: "okendo", key: "LoyaltySettings") {
      value
    }
  }
}
```

The metafield contains 2 script tags:

1. Widget settings configuration
2. Initialization script

**Result:** The Floating Widget will appear automatically (unless disabled in Okendo Admin settings).

> **⚠️ Important:** This must be rendered on every page where you want loyalty features to appear.

### 2. Customer Access Token Script Tag <a href="#id-2-customer-access-token-script-tag" id="id-2-customer-access-token-script-tag"></a>

**Purpose:** Authenticates the customer to display personalized loyalty information.

**Required for:**

* Logged-in customer experience
* Points balance display
* Rewards redemption
* Member-specific content

Choose **one** implementation method based on your authentication approach:

#### Option A: Customer Account API (Recommended for New Hydrogen Stores) <a href="#option-a-customer-account-api-recommended-for-new-hydrogen-stores" id="option-a-customer-account-api-recommended-for-new-hydrogen-stores"></a>

**When to use:** Your store uses the [Customer Account API](https://shopify.dev/docs/api/customer/2025-01#authentication) for authentication (Shopify's newer authentication method).

**Implementation:**

```html
<script type="application/json" id="oke-loyalty-customer-access-token">
{
  "customerAccessToken": "YOUR_ACCESS_TOKEN_HERE"
}
</script>
```

**Example (React/Hydrogen):**

```tsx
// In your root layout or auth context
export function LoyaltyAuth({accessToken}: {accessToken: string}) {
  return (
    <script
      type="application/json"
      id="oke-loyalty-customer-access-token"
      dangerouslySetInnerHTML={{
        __html: JSON.stringify({customerAccessToken: accessToken}),
      }}
    />
  );
}
```

**Where to get the token:**

* The `access_token` is obtained during your login flow from the Customer Account API
* Typically stored in session/cookies after the OAuth redirect
* Usually already available since it's required for Customer Account API requests

**Token Lifecycle:**

* ✅ **Must** implement automatic token refresh when it expires
* ✅ Remove or update the script tag when customer logs out
* ✅ Check token expiry before rendering

> **💡 Tip:** Most Hydrogen projects already manage this token in an auth context or session.

#### Option B: Storefront API (Legacy Authentication) <a href="#option-b-storefront-api-legacy-authentication" id="option-b-storefront-api-legacy-authentication"></a>

**When to use:** Your store uses the [Storefront API](https://shopify.dev/docs/api/storefront/2025-01/mutations/customerAccessTokenCreate) for authentication (older method).

**Implementation:**

```html
<script type="application/json" id="oke-loyalty-storefront-customer-access-token">
{
  "storefrontCustomerAccessToken": "CUSTOMER_ACCESS_TOKEN",
  "storefrontAccessToken": "STOREFRONT_PUBLIC_TOKEN"
}
</script>
```

**Example (React):**

```tsx
export function LoyaltyAuthStorefront({
  customerToken,
  storefrontToken,
}: {
  customerToken: string;
  storefrontToken: string;
}) {
  return (
    <script
      type="application/json"
      id="oke-loyalty-storefront-customer-access-token"
      dangerouslySetInnerHTML={{
        __html: JSON.stringify({
          storefrontCustomerAccessToken: customerToken,
          storefrontAccessToken: storefrontToken,
        }),
      }}
    />
  );
}
```

**Required Token #1: `storefrontCustomerAccessToken`**

**Source:** Returned from the `customerAccessTokenCreate` mutation.

```graphql
mutation {
  customerAccessTokenCreate(input: {
    email: "customer@example.com"
    password: "password"
  }) {
    customerAccessToken {
      accessToken  # ← Use this value
      expiresAt
    }
  }
}
```

**What you need:** The `accessToken` string from the response.

**Required Token #2: `storefrontAccessToken`**

**Source:** Your Storefront API public access token.

**Where to find it:**

1. Go to `Shopify Admin → Sales channels`
2. Click on your headless storefront
3. Navigate to `Storefront API → Public access token`
4. Copy the token value

**Environment variable:** Usually stored as `PUBLIC_STOREFRONT_API_TOKEN` and used for your `X-Shopify-Storefront-Access-Token` header.

> **💡 Tip:** You're likely already using this token for all Storefront API requests in your project.

### 3. Loyalty Landing Page / Other Widgets (Optional) <a href="#id-3-loyalty-landing-page--other-widgets-optional" id="id-3-loyalty-landing-page--other-widgets-optional"></a>

#### Loyalty Page <a href="#loyalty-page" id="loyalty-page"></a>

To display the Loyalty Page Widget on one of your store pages (e.g. a dedicated loyalty page) all you need to do is render the snippet below:

```
<div data-oke-loyalty-embedded-widget=""></div>
```

When the app initialisation script runs, it will detect this `div` and render the Loyalty Page widget there.

Other valid snippets for rendering individual modules from the Loyalty Page Widget are listed below:

| Module         | Snippet                                         |
| -------------- | ----------------------------------------------- |
| Member Profile | `<div data-oke-loyalty-profile=""></div>`       |
| Redeem Rewards | `<div data-oke-loyalty-redeem=""></div>`        |
| Earn Rewards   | `<div data-oke-loyalty-earn=""></div>`          |
| VIP Tiers      | `<div data-oke-loyalty-vip-tiers=""></div>`     |
| Achievements   | `<div data-oke-loyalty-achievements=""></div>`  |
| Refer A Friend | `<div data-oke-loyalty-refer-friends=""></div>` |
| FAQ            | `<div data-oke-loyalty-faq=""></div>`           |

#### Cart Banner Widget <a href="#cart-banner-widget" id="cart-banner-widget"></a>

Display a banner showing points information at the top of your Cart page or cart drawer.

**Use cases:**

* Cart page header
* Cart drawer header
* Checkout flow

**Implementation:**

```html
<div data-oke-loyalty-banner-widget=""></div>
```

#### Points Preview Widget <a href="#points-preview-widget" id="points-preview-widget"></a>

We also offer a Points Preview widget for products, which can help inform customers how many points they will receive upon purchasing a specific product (usually displayed under the price on the Product Display Page, but also works on product carousels, etc).

This div also accepts other data attributes which will help it identify the correct product, and can also be used to help style it for different use cases on different pages:

| Attribute                          | Description                                                                                                                                                                                                                    |
| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| data-oke-loyalty-points-preview-id | We will use this Product ID to calculate the reward. If not supplied then we will try to find it elsewhere on the page.                                                                                                        |
| data-oke-loyalty-variant-id        | The Variant ID of the product for the calculation. If not supplied then we will try to find it elsewhere on the page or else use the default for the product.                                                                  |
| data-oke-loyalty-selling-plan-id   | If you offer subscription options for the product then you can use this to tell us which one is currently selected. If not supplied then we will try to find it elsewhere on the page or else use the default for the product. |
| data-oke-loyalty-background        | A Hex Color Code (e.g. `#FFFFFF`) for the background of the widget                                                                                                                                                             |
| data-oke-loyalty-icon              | The name of the Icon to be displayed in the widget. Accepts most Font Awesome icon names                                                                                                                                       |
| data-oke-loyalty-target            | If you are using this widget in the cart, please set this to `"cart"`. If you are using this widget in a cart drawer, please set this to `"cart-drawer"`. This is purely for analytics purposes.                               |

As a simple example, your snippet may look something like this:

```html
<div
    data-oke-loyalty-points-preview=""
    data-oke-loyalty-points-preview-id="8234567890123"
></div>
```

**Complete example with optional attributes:**

```html
<div
    data-oke-loyalty-points-preview=""
    data-oke-loyalty-points-preview-id="8234567890123"
    data-oke-loyalty-variant-id="45678901234567"
    data-oke-loyalty-background="#F5F5F5"
    data-oke-loyalty-icon="gift"
    data-oke-loyalty-target="product"
></div>
```

### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

#### Widget Not Appearing <a href="#widget-not-appearing" id="widget-not-appearing"></a>

**Check:**

1. ✅ Loyalty Settings metafield is rendered in `<head>` as HTML and not text (you may be required to use `dangerouslySetInnerHTML`)
2. ✅ Script tags are loading without errors (check browser console)
3. ✅ Customer access token is valid and not expired
4. ✅ Floating Widget is enabled in Okendo Admin settings

#### Customer Not Logged In to Loyalty <a href="#customer-not-logged-in-to-loyalty" id="customer-not-logged-in-to-loyalty"></a>

**Check:**

1. ✅ Customer access token script tag is present on the page
2. ✅ Token is valid (not expired)
3. ✅ Correct script ID is used (`oke-loyalty-customer-access-token` or `oke-loyalty-storefront-customer-access-token`)
4. ✅ JSON format is valid (use a JSON validator)

#### Points Not Showing on Products <a href="#points-not-showing-on-products" id="points-not-showing-on-products"></a>

**Check:**

1. ✅ Correct product ID is being passed to `data-oke-loyalty-points-preview-id`
2. ✅ Product exists in your Shopify store
3. ✅ Points earning rules are configured in Okendo Admin

#### Console Errors <a href="#console-errors" id="console-errors"></a>

Common errors and solutions:

* **"Cannot find metafield"**: Ensure Loyalty is enabled in Okendo Admin
* **"Invalid token"**: Check token format and expiry
* **"Widget initialization failed"**: Verify settings script is loaded and formatted correctly

### Testing Checklist <a href="#testing-checklist" id="testing-checklist"></a>

Before going live, verify:

* Floating Widget appears on all pages
* Customer can log in to loyalty widget when authenticated
* Points balance displays correctly for logged-in customers
* Products show points preview on product pages
* Loyalty page displays all modules correctly
* Cart banner shows points information
* Widget styling matches your brand
* All widgets work on mobile devices
* Token refresh works correctly when token expires

### Additional Resources <a href="#additional-resources" id="additional-resources"></a>

* [Okendo Admin Dashboard](https://reviews.okendo.io/admin)
* [Shopify Customer Account API Docs](https://shopify.dev/docs/api/customer/2025-01)
* [Shopify Storefront API Docs](https://shopify.dev/docs/api/storefront/2025-01)
* Need help? Contact Okendo Support


# Installing Surveys on Headless Instances

## Standard Implementations

### Introduction

There are multiple ways to configure and setup headless Connect. There are two main channels it supports:

* on-site
* post-checkout

Both channels support multiple different modes of configuration. Either by passing query string parameters to the script or by creating meta tags inside the page header.

### On Site

To display an on site survey, the system chooses from a prioritised list of surveys for the on site channel. From highest priority down, the system choses the first active survey that matches conditions and that the user is eligible for answering.&#x20;

<figure><img src="/files/XsmcMageYUu8rScVG0TY" alt=""><figcaption><p>An example on-site survey list with the priority visible in the numbered boxes.</p></figcaption></figure>

To implement on site surveys, you can add our surveys script tag to the header of the page(s) with your store Shopify domain.

#### Example Usage

```html
<script type="text/javascript"
        src="https://surveys.okendo.io/js/okendo-connect.headless.js?shop={your-store}.myshopify.com&channel=on-site&auto_initialise=true"
        async>
</script>
```

#### Parameters

These query string parameters can be added to the script src.

<table><thead><tr><th width="213">Parameter</th><th width="200">Description</th><th width="134">Value Type</th><th width="131">Supported Values</th><th>Required</th></tr></thead><tbody><tr><td><code>shop</code></td><td>The store identifier for example <code>okendo-seahorse-emporium.myshopify.com</code></td><td><code>string</code></td><td></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>channel</code></td><td>The Okendo Survey channel to load a list of surveys from.</td><td><code>string</code></td><td><code>on-site</code>, <code>post-checkout</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr><tr><td><code>auto_initialise</code></td><td>Flag to indicate if the API setup function should be run on page load. Defaults to <code>false</code></td><td><code>boolean</code></td><td><code>true</code>, <code>false</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr><tr><td><code>customEventsOnly</code></td><td>Flag to indicate if page event triggers to show surveys should be supressed. Defaults to <code>false</code></td><td><code>boolean</code></td><td><code>true</code>, <code>false</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr><tr><td><code>targetElementId</code></td><td>Optional page element id to place the survey inside of.</td><td><code>string</code></td><td></td><td><span data-gb-custom-inline data-tag="emoji" data-code="274c">❌</span></td></tr></tbody></table>

### Post Checkout

To display a post checkout survey, the system chooses from a prioritised list of surveys for the post checkout channel. From highest priority down, the system choses the first active survey that matches conditions and that the user is eligible for answering.&#x20;

Post-checkout requires extra data needed for the decision making process on which survey to display to a customer. This data is used to determine which post-checkout conditions and triggers match.

If only using a simple post checkout survey without conditions you can use the same setup as the above on site section.&#x20;

If you want to use any of the following conditions, you will need to either use the javascript API properties or meta tags as explained below:

* Order value is at least
* Order value is at most
* Purchased product
* Cart contents do not include
* New Customers
* Repeat Customers

#### Example Usage

```html
<html>
<head>
    <meta name="oke:subscriber_id" content="{your-subscriber-id}" />
    <meta name="oke:target_element_id" content="okendo-survey" />
    <meta name="oke:order_id" content="1508506" />
    <meta name="oke:order_subtotal_price" content="100.00" />
    <meta name="oke:cart_content_product_ids" content="6911181521050, 6911187714202" />
    <meta name="oke:auto_initialise" />
    <script type="text/javascript"
        src="https://surveys.okendo.io/js/okendo-connect.headless.js?channel=post-checkout" async>
    </script>
</head>
<body>
    <div style="width: 300px; height: 400px;">
        <div id="okendo-survey"></div>
    </div>
</body>
</html>

```

#### Parameters

The channel parameter needs to be provided as a query string parameter to the script src.

<table><thead><tr><th>Parameter</th><th width="188">Description</th><th width="117">Value Type</th><th width="119">Supported Values</th><th>Required</th></tr></thead><tbody><tr><td><code>channel</code></td><td>The Okendo Survey channel to load a list of surveys from.</td><td><code>string</code></td><td><code>on-site</code>, <code>post-checkout</code></td><td><span data-gb-custom-inline data-tag="emoji" data-code="2705">✅</span></td></tr></tbody></table>

#### Tags

<table><thead><tr><th width="331.3333333333333">Tag Name</th><th width="243">Description</th><th>Example Value</th></tr></thead><tbody><tr><td><code>oke:subscriber_id</code></td><td>Your Okendo subscriberId. </td><td><code>00000000-0000-0000-0000-000000000000</code></td></tr><tr><td><code>oke:target_element_id</code></td><td>The id you have given the element on the page where you want embedded surveys to be displayed. Only required for embedded.</td><td><code>okendo-survey</code></td></tr><tr><td><code>oke:order_id</code></td><td>The order id used to support revenue attribution and linking the order to the survey response. See <code>Shopify.checkout.order_id</code></td><td><code>5179739177206</code></td></tr><tr><td><code>oke:order_subtotal_price</code></td><td>The order value to be used for matching order value conditions. Value should match your store currency.</td><td><code>100</code></td></tr><tr><td><code>oke:cart_content_product_ids</code></td><td>A list of product ids being purchased. Used for cart contains or not contains conditions. Separate by commas.</td><td><code>6911181521050, 6911187714202</code></td></tr><tr><td><code>oke:auto_initialise</code></td><td>Flag to indicate if the API setup function should be run on page load. If not included you will have to manually call <code>setup</code> on the Javascript API window object <code>okeConnectApi</code></td><td></td></tr></tbody></table>

## Custom Implementations

See the link below for details on API references to support your custom implementation.

{% content-ref url="/pages/WrrvjrZURZ49atPx5uvK" %}
[Surveys - Connect Window API](/on-site/storefront-javascript-api/surveys-connect-window-api)
{% endcontent-ref %}


# Installing Quizzes on Headless Instances

## Overview

Okendo Quizzes can not only recommend products to your customers but give you insights into respondant order attribution, attributed revenue and add to cart clicks. Add to cart events can be registered from either the quiz recommendation page within the Okendo quiz or after completion on the product display page if the customer has completed a quiz.

## Quick Start Guide

A bare minimum headless implementation of Okendo Quizzes will require the following:

### Inclusion of Okendo Quizzes

The Okendo Quizzes script must be loaded on any page that:

* Will show a quiz, or
* Will provide the ability to add a product to the cart, or
* Can potentially place/confirms success of an order.

```html
<script src="https://surveys.okendo.io/js/okendo-connect.quizzes.js" defer></script>
```

### Implementation of required Integration Points

The following events must be handled and/or dispatched as part of any headless/custom cart implementation:

* Enable Add to Cart functionality for products recommended by the quiz:
  * `oke_quizCapture_addToCart`
  * `oke_quizCapture_addToCartSuccess`
  * `oke_quizCapture_addToCartFailure`
* Enable attribution of quiz response data and reporting in the Okendo backend:
  * `oke_connect_cart_itemVariantAdded`
  * `oke_connect_checkout_orderSubmitted`

See the relevant sections under **Integration Points** and **Implementation Examples** for further details and code samples.

### Add a Quiz to a page

A quiz can be included on a page in one of two ways. We currently recommend that only one quiz is shown per page.

#### Embedded Quizzes

Once a quiz has been configured in the Okendo backend it can be embedded into any page with the Install Snippet. To retrieve the snippet for any given quiz:

1. Navigate to the Quizzes section of the Okendo backend
2. Locate the quiz in the Quiz List
3. Click the “…” button to find the option to “Install” the quiz
4. Reveal the installation instructions for an Embedded Section (click ”Show Install Instructions”)
5. Copy the “Embed Quiz Snippet In Theme“ snippet and paste it into the desired location on the page

It should resemble the below:

```html
<div oke-quiz oke-channel-quiz-id="..." oke-subscriber-id="..."></div>
```

#### Pop-up Quizzes

Merchants that prefer to show the Quiz in a pop up can use the `showQuiz` function available on `okeConnectApi`. See the relevant sections under **Integration Points** and **Implementation Examples**.

## Integration Points

### Add to Cart Functionality

*Required for headless implementations*

Merchants that have a custom cart implementation will need to notify Okendo Quizzes of whether a particular “Add to Cart” operation was successful or not. The dispatch of either a “success” or “failure” event will allow Okendo Quizzes to provide accurate visual feedback when a customer clicks “Add to Cart” on a recommended product.

* `oke_quizCapture_addToCart`: Dispatched by Okendo. This event is used to notify you that a customer intends to “Add to Cart” one or more recommended products.
* `oke_quizCapture_addToCartSuccess`: Dispatched by you. This event is used to visually indicate to customers that an “Add to Cart” operation succeeded.
* `oke_quizCapture_addToCartFailure`: Dispatched by you. This event is used to visually indicate to customers that an “Add to Cart” operation failed.

### Attribution & Buyer Behavior

*Required for headless implementations*

* `oke_connect_cart_itemVariantAdded`: Dispatched by you. This event is used for the store to notify Okendo Quizzes when an add to cart event has occurred on the storefront. This event allows merchants to attribute data to the quiz response and feeds into reporting on quiz performance and buyer behavior.
* `oke_connect_checkout_orderSubmitted`: Dispatched by you. This event is used for the store to notify Okendo Quizzes when an order is placed on the storefront. This event enables merchants to attribute the order with the quiz response, gathering valuable insights and feedback from customers to improve the overall effectiveness and relevance of the quizzes.
* `okendo_attribution_session_id`: This attribute is added to cart attributes when the cart is created with the storefront API for the store to notify Okendo Quizzes when an order is processed on the storefront. This attribute enables merchants to attribute the order with the quiz response, gathering valuable insights and feedback from customers to improve the overall effectiveness and relevance of the quizzes.
* `okendo_quiz_response_id`: This attribute is added to cart attributes when the cart is created with the storefront API for the store to notify Okendo Quizzes when an order is processed on the storefront. This attribute enables merchants to attribute the order with the quiz response, gathering valuable insights and feedback from customers to improve the overall effectiveness and relevance of the quizzes.

Here is an example implementation for the `okendo_attribution_session_id` and `okendo_quiz_response_id` attributes when updating cart attributes:

```html
<script>
    const updateCartAttributesMutation = `
    mutation updateCartAttributes($attributes: [AttributeInput!]!, $cartId: ID!) {
        cartAttributesUpdate(attributes: $attributes, cartId: $cartId) {
            cart {
                id
                attributes{
                    key
                    value
                }
            }
            userErrors {
                field
                message
            }
        }
    }`;
    await client.request(updateCartAttributesMutation, {
        variables: {
        attributes: [{
            key: "okendo_quiz_response_id",
            value: "a8b5e430-6802-4084-a5af-c933c40164a5"
        },
        {
            key: "okendo_attribution_session_id",
            value: "d715e8bc-30d9-4867-a449-6c12b43baeb4"
        }],
        cartId: "gid://shopify/Cart/Z2NwLWFzaWEtc291dGhlYXN0MTowMUo0RlpRQ0NORUdZMkhDUlRCUzBKRlFYUg?key=508422975f2334d362ba2d81d2b1ef41"
        }
    });
</script>
```

### Pop-up Quizzes

*Optional*

In place of embedding a quiz on a page with an app block or embed snippet, Merchants have the alternative option to display a quiz in a pop up at a time that suits for added flexibility.

* `showQuiz`: Called by you. This function is used to display the quiz to the customer. By triggering this function at the appropriate time, merchants can engage customers and encourage them to interact with the quiz, resulting in a more interactive and personalized shopping experience.

### Custom HTML

*Optional*

* `recommendedProductMounted`: Provided by you, called by Okendo. This function is called when an ***individual*** product recommendation is mounted in the application. It can be used for inserting custom HTML or other custom product display functionality, allowing merchants to further customize the presentation of recommended products.
* `recommendedProductsMounted`: Provided by you, called by Okendo. This function is called when ***all*** product recommendations are mounted in the application. It can be used for inserting custom HTML or other custom product display functionality for the entire recommendation page, providing merchants with the flexibility to tailor the appearance of the entire recommendation section.

### Product Properties

*Optional*

* `generateCartLineItemProperties`: Provided by you, called by Okendo. This event is triggered when a product is added to the cart from the recommendation page. It can be used to insert custom data into the cart line items, allowing merchants to enhance the cart experience with personalized information.

By leveraging the Quiz Frontend API, merchants can seamlessly integrate Okendo Quizzes and provide an engaging and personalized experience for their customers.

## Implementation Examples

### `oke_quizCapture_addToCart` Event Usage

The `oke_quizCapture_addToCart` event is used by Okendo Quizzes to notify the store that a customer intends to “Add to Cart” one or more recommended products.

An example implementation on how a custom cart might react to the `oke_quizCapture_addToCart` event:

```html
<script>
	// Listen to the oke_quizCapture_addToCart event
		document.addEventListener('oke_quizCapture_addToCart', async event => {
	
		// Process each product variant to be added to the custom cart.
		for (const productVariant of event.detail.items) {
	
			try {
				// Attempt to add the variant.
				await customCart.addProductVariant({
					productId: productVariant.productId,
					variantId: productVariant.variantId,
					quantity: productVariant.quantity
				});
	
				// Tell Okendo Quizzes to visually show the customer
				// that the product variant was added successfully.
				document.dispatchEvent(new CustomEvent(
					'oke_quizCapture_addToCartSuccess',
					{	detail: { message: 'Yay! Added to cart successfully!' } }
				);
			}
			catch {
				// The variant was not able to be added to the custom cart.
				document.dispatchEvent(new CustomEvent(
					'oke_quizCapture_addToCartFailure',
					{	detail: { message: 'Oh no, something went wrong.' } }
				);
			}
		}
	
	});
</script>
```

### `oke_quizCapture_addToCartSuccess` Event Usage

The `oke_quizCapture_addToCartSuccess` event is used for the store to notify Okendo Quizzes that an add to cart event was successfully processed (by your custom cart implementation).

Here is an example implementation for the `oke_quizCapture_addToCartSuccess` event:

```markup
<script>
    document.dispatchEvent(new CustomEvent('oke_quizCapture_addToCartSuccess', { 
        detail: { message: 'Added to cart!' }
    }));
</script>
```

### `oke_quizCapture_addToCartFailure` Event Usage

The `oke_quizCapture_addToCartFailure` event is used for the store to notify Okendo Quizzes that your/a custom cart implementation failed to process an add to cart event.

Here is an example implementation for the `oke_quizCapture_addToCartFailure` event:

```markup
<script>
    document.dispatchEvent(new CustomEvent('oke_quizCapture_addToCartFailure', { 
        detail: { message: 'Could not add product to cart!' }
    }));
</script>
```

### `oke_connect_cart_itemVariantAdded` Event Usage

The `oke_connect_cart_itemVariantAdded` event is used for the store to notify Okendo Quizzes when an add to cart event has occurred on the storefront. This is particularly useful for enabling attribution on headless implementations. This event allows merchants to attribute data to the quiz response and feeds into reporting on quiz performance and buyer behavior.

Here is an example implementation for the `oke_connect_cart_itemVariantAdded` event:

```html
<script>
	const customCart = {
		addProductVariant: async ({ productId, variantId, quantity }) => {
	
				try {
					await addItemToCartBackend(productId, variantId, quantity);
	
					// Tell Okendo Quizzes to attribute add to cart data
					// to the quiz response to feed into reporting.
					document.dispatchEvent(new CustomEvent(
						'oke_connect_cart_itemVariantAdded',
						{
							detail: {
								productId: productVariant.productId,
								variantId: productVariant.variantId,
								quantity: productVariant.quantity
							}
						}				
					);
				}
				catch (error) {
					throw error;
				}
	
		}
	};
</script>
```

In the above implementation, the `oke_connect_cart_itemVariantAdded` event is dispatched using the `document.dispatchEvent` method. The event includes the following details:

* `productId` (string): The unique identifier of the product added to the cart.
* `variantId` (string): The unique identifier of the selected variant of the product.
* `quantity` (number): The quantity of the product added to the cart.

By dispatching the `oke_connect_cart_itemVariantAdded` event with the relevant information, merchants can track add to cart events and associate them with the quiz response, providing valuable insights into the effectiveness of quizzes in driving buyer behavior.

Remember to replace `'your-product-id'` and `'your-variant-id'` with the actual product and variant IDs from your storefront.

By leveraging the `oke_connect_cart_itemVariantAdded` event provided by the Quiz Frontend API, merchants can seamlessly integrate Okendo Quizzes and gather valuable data on quiz performance and buyer behavior.

### `oke_connect_checkout_orderSubmitted` Event Usage

The `oke_connect_checkout_orderSubmitted` event is used for the store to notify Okendo Quizzes when an order is placed on the storefront. This is particularly useful for enabling attribution on headless implementations. This event enables merchants to attribute the order with the quiz response, gathering valuable insights and feedback from customers to improve the overall effectiveness and relevance of the quizzes.

Here is an example implementation for the `oke_connect_checkout_orderSubmitted` event:

```html
<script>
	// Dispatch the oke_connect_checkout_orderSubmitted event
	document.dispatchEvent(new CustomEvent('oke_connect_checkout_orderSubmitted', {
	  detail: {
	    cartToken: 'your-cart-token',
	    checkoutToken: 'your-checkout-token',
	    orderId: 'your-order-id',
	    products: [
	      {
	        productId: 'your-product-id',
	        variantId: 'your-variant-id',
	        quantity: 1
	      },
	      // Add more products as needed
	    ]
	  }
	}));
</script>
```

In the above implementation, the `oke_connect_checkout_orderSubmitted` event is dispatched using the `document.dispatchEvent` method. The event includes the following details:

* `cartToken` (string)(optional): The token representing the user's cart.
* `checkoutToken` (string)(optional): The token representing the user's checkout session.
* `orderId` (string)(optional): The unique identifier of the order placed on the storefront.
* `products` (array of objects): An array of products included in the order, where each object contains the following details:
  * `productId` (string): The unique identifier of the product.
  * `variantId` (string): The unique identifier of the selected variant of the product.
  * `quantity` (number): The quantity of the product added to the cart.

By dispatching the `oke_connect_checkout_orderSubmitted` event with the relevant information, merchants can link the order with the quiz response, gaining insights into the impact of quizzes on customer purchasing behavior.

Remember to replace `'your-cart-token'`, `'your-checkout-token'`, `'your-order-id'`, `'your-product-id'`, and `'your-variant-id'` with the actual tokens, order ID, product ID, and variant ID from your storefront.

By leveraging the `oke_connect_checkout_orderSubmitted` event provided by the Quiz Frontend API, merchants can seamlessly integrate Okendo Quizzes and gather valuable data on the impact of quizzes on customer orders.

### `showQuiz` Function Usage

The `showQuiz` event can optionally be used to trigger display of Okendo Quizzes on your storefront in a modal. By triggering this event at the appropriate time, you can display the quiz to your customers and create a more interactive and personalized shopping experience. Here is an example implementation for the `showQuiz` event:

```html
<script>
	window.okeConnectApi.showQuiz(channelQuizId, subscriberId);
</script>
```

In the above implementation, the `showQuiz` event takes two parameters:

* `channelQuizId` (string): The unique identifier of the quiz channel. You can find this ID in the install dialogue of the quiz you want to display in the Okendo admin application.
* `subscriberId` (string): Your Okendo subscriberId.

Once you have implemented the `showQuiz` event, you can call it at the appropriate time in your storefront's code to display the quiz to your customers.

Remember to customize the appearance and behavior of the quiz to align with your branding and provide an engaging experience for your customers.

By leveraging the `showQuiz` event provided by the Quiz Frontend API, you can seamlessly integrate Okendo Quizzes and enhance the overall shopping experience for your customers.

A sample custom liquid snippet for a button that shows the quiz in a popup

```html
<a  
  href="#" 
  onclick="okeConnectApi.showQuiz('your-channel-quiz-id', 'your-subscriber-id')" 
  class="button button--full-width">Take our quiz
</a>
```

### `recommendedProductMounted` Function Example

The `recommendedProductMounted` event is triggered when an individual product recommendation is mounted in the application. It provides an opportunity for merchants to insert custom HTML or other custom product display functionality, allowing them to further customize the presentation of recommended products. Here is an example implementation for the `recommendedProductMounted` event and using it to insert an additional product option selector:

```html
<script>
	window.okeConnectApi.recommendedProductMounted = (sectionContent, product) => {
		const addButton = sectionContent.querySelector('button.c-addToCart');
		if (addButton && !sectionContent.loaded) {
			sectionContent.loaded = true;
			let selectorHtml = `
			<div class="c-resultLearnMore">
				<a class="c-resultButton-primary c-button c-resultButton" style="width: 100%;" href="https://sample.myshopify.com/collections/product1" target="_blank">Learn More</a>
			</div>`;
			addButton.insertAdjacentHTML('beforeBegin', selectorHtml);
		}
	};
</script>
```

In the above implementation, the `recommendedProductMounted` event provides the following:

* `sectionContent`(html): The html content that will be rendered for the recommended product.

  For example:

  ```jsx
  <div class="c-recommendedProduct">
      <a
          href="<https://okendo-seahorse-emporium.myshopify.com/products/red-seahorse>"
          data-productid="shopify-7571259490550"
          target="_blank"
      >
          <img
              alt="Red Seahorse"
              src="<https://cdn.shopify.com/s/files/1/0629/4234/7510/products/GettyImages-1159240457-79e9779a466c4b6e82d188384c34142b.jpg?v=1645164970>"
              class="c-recommendedProduct-image"
          >
      </a>
      <div class="c-recommendedProduct-nameAndPrice">
          <div class="c-recommendedProduct-name u-marginTop--small u-marginBottom--xSmall"><a
                  href="<https://okendo-seahorse-emporium.myshopify.com/products/red-seahorse>"
                  target="_blank"
              >Red Seahorse</a>
          </div>
          <div class="c-recommendedProduct-price u-marginBottom--medium"><a
                  href="<https://okendo-seahorse-emporium.myshopify.com/products/red-seahorse>"
                  target="_blank"
              >$10.00</a>
          </div>
      </div>
      <button
          class="c-resultButton-secondary c-button c-resultButton c-addToCart"
          id="shopify-7571259490550-0"
          style="width: 100%;"
      >
          <span class="c-addToCart-text">Add to Cart</span>
      </button>
  </div>
  ```
* `product` (json): A JSON object representing the recommended product and associated properties.

  For example:

  ```json
  {
      "productId": "shopify-7571259490550",
      "imageUrl": "<https://cdn.shopify.com/s/files/1/0629/4234/7510/products/GettyImages-1159240457-79e9779a466c4b6e82d188384c34142b.jpg?v=1645164970>",
      "name": "Red Seahorse",
      "url": "<https://okendo-seahorse-emporium.myshopify.com/products/red-seahorse>",
      "options": [
          {
              "name": "Title",
              "values": [
                  "Default Title"
              ]
          }
      ],
      "variants": [
          {
              "variantRemoteId": "42585640960246",
              "title": "Default Title",
              "price": 10,
              "currencyCode": "AUD",
              "availableForSale": true,
              "imageUrl": "<https://cdn.shopify.com/s/files/1/0629/4234/7510/products/GettyImages-1159240457-79e9779a466c4b6e82d188384c34142b.jpg?v=1645164970>"
          }
      ],
      "addToCartButtonId": "shopify-7571259490550-0",
      "isVariantRecommendation": false,
      "selectedVariant": {
          "variantRemoteId": "42585640960246",
          "title": "Default Title",
          "price": 10,
          "currencyCode": "AUD",
          "availableForSale": true,
          "imageUrl": "<https://cdn.shopify.com/s/files/1/0629/4234/7510/products/GettyImages-1159240457-79e9779a466c4b6e82d188384c34142b.jpg?v=1645164970>"
      },
      "variantSelectorId": "aafbcd30-837d-479a-83ab-654ab1faacac"
  }
  ```

By implementing the `recommendedProductMounted` event, merchants can customize the appearance and behavior of individual recommended products, providing a tailored and personalized shopping experience for their customers.

### `recommendedProductsMounted` Function Example

The `recommendedProductsMounted` event is triggered when all product recommendations are mounted in the application. It provides an opportunity for merchants to insert custom HTML or other custom product display functionality for the entire recommendation page. This allows merchants to have full control over the presentation of the entire recommendation section. Here is an example implementation for the `recommendedProductsMounted` event:

```html
<script>
	window.okeConnectApi.recommendedProductsMounted = (recommendationSection, products) => {
	    // Insert custom HTML or other custom product display functionality for the entire recommendation page
	    // Example:
	    recommendationSection.insertAdjacentHTML('beforeend', '<div class="custom-recommendation-section">...</div>');
	};
</script>
```

In the above implementation, the `recommendedProductsMounted` event provides the following:

* `recommendationSection` (html): The html element representing the entire recommendation section.
* `products` (json): A JSON object representing all recommended products to be displayed on the recommendation page.

By implementing the `recommendedProductsMounted` event, merchants have the flexibility to insert custom HTML or other custom product display functionality for the entire recommendation page. This allows for a highly customizable and tailored shopping experience for their customers.

### `generateCartLineItemProperties` Function Example

The `generateCartLineItemProperties` event is triggered when a product is added to the cart from the recommendation page. It provides an opportunity for merchants to insert custom data into the cart line items, allowing them to enhance the cart experience with personalized information. Here is an example implementation for the `generateCartLineItemProperties` event:

```html
<script>
	window.okeConnectApi.generateCartLineItemProperties = (addToCartButtonId, product) => {
	    // Insert custom data into the cart line items
	    // Example:
	    const customProperties = {};
	    customProperties['Customer option'] = 'Some custom option';
	    customProperties['_has_custom'] = true;
	    return customProperties;
	};
</script>
```

In the above implementation, the `generateCartLineItemProperties` event provides the following:

* `addToCartButtonId`(string): id of the add to cart button element that was clicked.
* `product` (json): A JSON object representing the product that was added to the cart from the recommendation page.

By implementing the `generateCartLineItemProperties` event, merchants can enrich the cart experience by including custom properties for each line item. This allows for a more personalized and tailored shopping experience for their customers.


# Installing Quizzes with Custom Carts

Okendo Quizzes integrates with basic Shopify themes by refreshing the cart counter and updating the cart drawer if available.

If your store uses a theme that is not fully supported, or uses additional cart plugins or custom cart integrations, you may need to perform some additional steps to make sure that the Quiz (particularly the results page, where there are cart interactions) is fully functional for your online store.

## Variant added event

Add an event listener in your theme code to react to whenever an item has been added to the cart from the Quiz results page:

```typescript
document.addEventListener('oke_connect_cart_itemVariantAdded', async event => {
    console.log(event.detail);
});
```

## “Add To Cart” doesn’t update the shopping cart icon

Use the `oke_connect_cart_itemVariantAdded` event to trigger your custom cart to update. The following is an example only. Your custom cart API may be different:

```typescript
document.addEventListener('oke_connect_cart_itemVariantAdded', async event => {
		// Example only. Check your custom cart API.
		const { detail } = event;
		const customEvent = new CustomEvent('theme:cart:update', { detail: { id, quantity } });
    document.dispatchEvent(customEvent);
});
```

## “Add To Cart” doesn’t open the cart drawer

Use the `oke_connect_cart_itemVariantAdded` event to trigger the cart drawer for your custom cart. Some custom carts may open the cart drawer for you at the same time as the cart items are updated:

```typescript
document.addEventListener('oke_connect_cart_itemVariantAdded', async event => {
		// Example only. Check your custom cart API.
		window.cart.openCartDrawer();
});
```


# Stores Running an Existing Vue App

Merchants using the standard Shopify ecosystem but running Vue on their store

If a store is running Vue and our widget markup cannot be installed outside the existing Vue app instance, we suggest using our [Vue component library](https://www.npmjs.com/package/@okendo/reviews-widget-plus-vue) or talking to us about your specific use-case by emailing <solutions@okendo.io>.


# Okendo Shopify Hydrogen Support

<figure><img src="/files/iPDqsDhWmLPfuHKIerkS" alt="" width="375"><figcaption></figcaption></figure>

Okendo proudly supports Shopify's Hydrogen 2 (Remix / React Router) and Hydrogen 1.

The goal of our integration is to seamlessly integrate with your engineering workflow for Hydrogen in the form of an [NPM package](https://www.npmjs.com/package/@okendo/shopify-hydrogen).

For licensing see `license.txt` in our [NPM package](https://www.npmjs.com/package/@okendo/shopify-hydrogen).

Please see resources below:

## Getting Started With Okendo Components For Shopify Hydrogen

1. [Tutorial](https://www.npmjs.com/package/@okendo/shopify-hydrogen)
2. [Questions / Support?](mailto:support@okendo.io?Subject=Shopify%20Hydrogen)

***

## Hydrogen Public Developer Documentation:

### Hydrogen tutorials:

1. [Overview of Shopify Hydrogen](https://shopify.dev/docs/storefronts/headless)
2. [Create a custom storefront with Hydrogen](https://shopify.dev/docs/storefronts/headless/hydrogen/getting-started)
3. [Hydrogen reference docs](https://shopify.dev/api/hydrogen)


# Getting Started

Webhooks allow your applications to receive information when customer events occur - such as submitting a product review, completing a survey, or earning loyalty points. This enables seamless integration with your existing tools - whether you want to track reviews in your CRM, send data to custom analytics platforms or trigger custom workflows. This documentation will detail how to configure and test webhooks for Okendo.

### Setting Up Webhooks

You can configure webhooks using the [Okendo Merchant REST API](https://docs.okendo.io/merchant-rest-api/endpoints#webhooks). Follow the API documentation to create a webhook subscription.

**Important Notes:**

* **Webhook Ordering:** Delivery order is not guaranteed. However, each webhook includes a `sequenceNumber` that can be used to order events for the same resource type.
* **Response Requirements:** Your server must respond with an HTTP `2xx` status code (e.g., `200 OK`) within 15 seconds of receiving a webhook event.
  * Best practice is to immediately acknowledge receipt and delegate processing to an asynchronous task or queue.

### Verifying Webhooks

For security purposes, we strongly recommend verifying the webhook signature to ensure that the payloads are coming from Okendo and not a malicious third party.

Refer to [this guide](https://www.svix.com/guides/receiving/receive-webhooks-with-svix-cli/) for an example of how to verify webhook signatures using the Svix CLI.


# Topics

<details>

<summary><code>loyalty_adjustment_transaction.create</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "amount": 100,
        "customer": {
            "email": "name@example.com",
            "customerId": "123e4567-e89b-12d3-a456-426614174000"
        },
        "date": "2025-06-18T05:31:46.915Z",
        "internalReason": "Manual Adjustment",
        "notificationText": "Manual Store Adjustment",
        "status": "complete"
    },
    "resourceType": "loyalty_adjustment_transaction",
    "sequenceNumber": "123123412",
    "topic": "create",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_adjustment_transaction.update</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "amount": 100,
        "customer": {
            "email": "name@example.com",
            "customerId": "123e4567-e89b-12d3-a456-426614174000"
        },
        "date": "2025-06-18T05:31:46.915Z",
        "internalReason": "Manual Adjustment",
        "notificationText": "Manual Store Adjustment",
        "status": "complete"
    },
    "resourceType": "loyalty_adjustment_transaction",
    "sequenceNumber": "123123412",
    "topic": "update",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_adjustment_transaction.delete</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "amount": 100,
        "date": "2025-06-18T05:31:46.915Z",
        "internalReason": "Manual Adjustment",
        "notificationText": "Manual Store Adjustment",
        "status": "complete"
    },
    "resourceType": "loyalty_adjustment_transaction",
    "sequenceNumber": "123123412",
    "topic": "delete",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_customer.create</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "customer": {
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "name@example.com",
        },
        "birthday": {
            "day": 10,
            "month": 3
        },
        "dateCreated": "2025-06-18T05:31:46.915Z",
        "dateEnrolled": "2025-06-18T05:31:46.915Z",
        "datePointsExpire": "2025-06-18T05:31:46.915Z",
        "dateTierEntered": "2025-06-18T05:31:46.915Z",
        "dateTierExpires": "2025-06-18T05:31:46.915Z",
        "isTierLocked": true,
        "minimumVipTierId": "123e4567-e89b-12d3-a456-426614174000",
        "points": {
            "balance": 100,
            "dateUpdated": "2025-06-18T05:31:46.915Z",
            "pending": 0,
            "spent": 0
        },
        "rewardsClaimed": 0,
        "status": "enrolled",
        "vipTierId": "123e4567-e89b-12d3-a456-426614174000",
        "vipTierName": "Gold"
    },
    "resourceType": "loyalty_customer",
    "sequenceNumber": "123123412",
    "topic": "create",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_customer.update</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "customer": {
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "name@example.com",
        },
        "birthday": {
            "day": 10,
            "month": 3
        },
        "dateCreated": "2025-06-18T05:31:46.915Z",
        "dateEnrolled": "2025-06-18T05:31:46.915Z",
        "datePointsExpire": "2025-06-18T05:31:46.915Z",
        "dateTierEntered": "2025-06-18T05:31:46.915Z",
        "dateTierExpires": "2025-06-18T05:31:46.915Z",
        "isTierLocked": true,
        "minimumVipTierId": "123e4567-e89b-12d3-a456-426614174000",
        "points": {
            "balance": 100,
            "dateUpdated": "2025-06-18T05:31:46.915Z",
            "pending": 0,
            "spent": 0
        },
        "rewardsClaimed": 0,
        "status": "enrolled",
        "vipTierId": "123e4567-e89b-12d3-a456-426614174000",
        "vipTierName": "Gold"
    },
    "resourceType": "loyalty_customer",
    "sequenceNumber": "123123412",
    "topic": "update",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_customer.delete</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "customer": {
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "name@example.com",
        },
        "birthday": {
            "day": 10,
            "month": 3
        },
        "dateCreated": "2025-06-18T05:31:46.915Z",
        "dateEnrolled": "2025-06-18T05:31:46.915Z",
        "datePointsExpire": "2025-06-18T05:31:46.915Z",
        "dateTierEntered": "2025-06-18T05:31:46.915Z",
        "dateTierExpires": "2025-06-18T05:31:46.915Z",
        "isTierLocked": true,
        "minimumVipTierId": "123e4567-e89b-12d3-a456-426614174000",
        "points": {
            "balance": 100,
            "dateUpdated": "2025-06-18T05:31:46.915Z",
            "pending": 0,
            "spent": 0
        },
        "rewardsClaimed": 0,
        "status": "enrolled",
        "vipTierId": "123e4567-e89b-12d3-a456-426614174000",
        "vipTierName": "Gold"
    },
    "resourceType": "loyalty_customer",
    "sequenceNumber": "123123412",
    "topic": "delete",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_earning_transaction.create</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "action": "purchase",
        "amount": 100,
        "customer": {
            "email": "name@example.com",
            "customerId": "123e4567-e89b-12d3-a456-426614174000"
        },
        "date": "2025-06-18T05:31:46.915Z",
        "notificationText": "Placed an Order",
        "status": "complete",
        "remoteOrderId": "123456789",
    },
    "resourceType": "loyalty_earning_transaction",
    "sequenceNumber": "123123412",
    "topic": "create",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_earning_transaction.update</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "action": "purchase",
        "amount": 100,
        "customer": {
            "email": "name@example.com",
            "customerId": "123e4567-e89b-12d3-a456-426614174000"
        },
        "date": "2025-06-18T05:31:46.915Z",
        "notificationText": "Placed an Order",
        "status": "complete",
        "remoteOrderId": "123456789",
    },
    "resourceType": "loyalty_earning_transaction",
    "sequenceNumber": "123123412",
    "topic": "update",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_earning_transaction.delete</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "action": "purchase",
        "amount": 100,
        "customer": {
            "email": "name@example.com",
            "customerId": "123e4567-e89b-12d3-a456-426614174000"
        },
        "date": "2025-06-18T05:31:46.915Z",
        "notificationText": "Placed an Order",
        "status": "complete",
        "remoteOrderId": "123456789",
    },
    "resourceType": "loyalty_earning_transaction",
    "sequenceNumber": "123123412",
    "topic": "delete",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_redemption_transaction.create</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "amount": -100,
        "customer": {
            "email": "name@example.com",
            "customerId": "123e4567-e89b-12d3-a456-426614174000"
        },
        "date": "2025-06-18T05:31:46.915Z",
        "notificationText": "Converted Points",
        "reward": {
            "status": "issued",
            "type": "coupon",
            "coupon": {
                "status": "issued",
                "description": "$10 Off",
                "code": "OKRX-XXXXX-XXXX"
            }
        },
        "status": "complete"
    },
    "resourceType": "loyalty_redemption_transaction",
    "sequenceNumber": "123123412",
    "topic": "create",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_redemption_transaction.update</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "amount": -100,
        "customer": {
            "email": "name@example.com",
            "customerId": "123e4567-e89b-12d3-a456-426614174000"
        },
        "date": "2025-06-18T05:31:46.915Z",
        "notificationText": "Converted Points",
        "reward": {
            "status": "issued",
            "type": "coupon",
            "coupon": {
                "status": "issued",
                "description": "$10 Off",
                "code": "OKRX-XXXXX-XXXX"
            }
        },
        "status": "complete"
    },
    "resourceType": "loyalty_redemption_transaction",
    "sequenceNumber": "123123412",
    "topic": "update",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>loyalty_redemption_transaction.delete</code></summary>

```json
{
    "resource": {
        "loyaltyCustomerId": "123e4567-e89b-12d3-a456-426614174000",
        "loyaltyTransactionId": "123e4567-e89b-12d3-a456-426614174000",
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "amount": -100,
        "customer": {
            "email": "name@example.com",
            "customerId": "123e4567-e89b-12d3-a456-426614174000"
        },
        "date": "2025-06-18T05:31:46.915Z",
        "notificationText": "Converted Points",
        "reward": {
            "status": "issued",
            "type": "coupon",
            "coupon": {
                "status": "issued",
                "description": "$10 Off",
                "code": "OKRX-XXXXX-XXXX"
            }
        },
        "status": "complete"
    },
    "resourceType": "loyalty_redemption_transaction",
    "sequenceNumber": "123123412",
    "topic": "delete",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>quiz_response.create</code></summary>

```
{
    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "quizResponseId": "123e4567-e89b-12d3-a456-426614174000",
        "quizId": "123e4567-e89b-12d3-a456-426614174000",
        "quizName": "Find your fit quiz",
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "channel": "on-site-embed",
        "customer":{
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "example@okendo.io"
        },
        "emailMarketingOptIn": true,
        "order": {
            "remoteOrderId": "123456789"
        },
        "answeredQuestions": [
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "multi-select",
                "text": "Which colors do you usually wear?",
                "answer": [
                    "Red",
                    "Blue",
                    "Other"
                ],
                "customAnswerOptionText": "Other",
                "customAnswer": "Orange"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "single-select",
                "text": "Help us understand! Why did you choose to leave our site?",
                "answer": "Didn't find what I was looking for",
                "customAnswerOptionText": "Other"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "star",
                "text": "How would you rate our customer service?",
                "answer": 5
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "five-point",
                "text": "How was your online shopping experience?",
                "answer": 4
            }
        ],
        "recommendation":{
            "type": "conditional-outcomes",
            "outcomeType": "result",
            "outcomeId": "123e4567-e89b-12d3-a456-426614174000",
            "outcomeTitle": "These are our top recommendations for you!",
            "recommendedProducts": [
                {
                    "defaultRemoteVariantId": "1234567890123",
                    "remoteProductId": "1234567890123",
                    "remoteVariantIds": [
                        "1234567890123"
                    ]
                },
                {
                    "defaultRemoteVariantId": "1234567890123",
                    "remoteProductId": "1234567890123",
                    "remoteVariantIds": [
                        "1234567890123",
                        "1234567890123"
                    ]
                },
                {
                    "remoteProductId": "1234567890123"
                }
            ]
        },
        "reward": {
            "description": "$10 off your next order over $40",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX"
        }
    },
    "resourceType": "quiz_response",
    "sequenceNumber": "123123412",
    "topic": "create",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>quiz_response.update</code></summary>

```
{
    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "quizResponseId": "123e4567-e89b-12d3-a456-426614174000",
        "quizId": "123e4567-e89b-12d3-a456-426614174000",
        "quizName": "Find your fit quiz",
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "channel": "on-site-embed",
        "customer":{
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "example@okendo.io"
        },
        "emailMarketingOptIn": true,
        "order": {
            "remoteOrderId": "123456789"
        },
        "answeredQuestions": [
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "multi-select",
                "text": "Which colors do you usually wear?",
                "answer": [
                    "Red",
                    "Blue",
                    "Other"
                ],
                "customAnswerOptionText": "Other",
                "customAnswer": "Orange"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "single-select",
                "text": "Help us understand! Why did you choose to leave our site?",
                "answer": "Didn't find what I was looking for",
                "customAnswerOptionText": "Other"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "star",
                "text": "How would you rate our customer service?",
                "answer": 5
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "five-point",
                "text": "How was your online shopping experience?",
                "answer": 4
            }
        ],
        "recommendation":{
            "type": "weighted-products",
            "recommendedProducts": [
                {
                    "points": 2,
                    "product": {
                        "remoteProductId": "1234567890123"
                    }
                },
                {
                    "points": 1,
                    "product": {
                        "defaultRemoteVariantId": "1234567890123",
                        "remoteProductId": "1234567890123",
                        "remoteVariantIds": [
                            "1234567890123"
                        ]
                    }
                },
                {
                    "points": 1,
                    "product": {
                        "remoteProductId": "1234567890123"
                    }
                }
            ],
            "runnerUpProducts": [
                {
                    "points": 2,
                    "product": {
                        "remoteProductId": "1234567890123"
                    }
                },
                {
                    "points": 1,
                    "product": {
                        "remoteProductId": "1234567890123"
                    }
                },
                {
                    "points": 1,
                    "product": {
                        "defaultRemoteVariantId": "1234567890123"
                        "remoteProductId": "1234567890123",
                        "remoteVariantIds: [
                            "1234567890123",
                            "1234567890123",
                            "1234567890123"
                        ]
                    }
                }
            ]
        },
        "reward": {
            "description": "$10 off your next order over $40",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX"
        }
    },
    "resourceType": "quiz_response",
    "sequenceNumber": "123123412",
    "topic": "update",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>quiz_response.delete</code></summary>

```
{
    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "quizResponseId": "123e4567-e89b-12d3-a456-426614174000",
        "quizId": "123e4567-e89b-12d3-a456-426614174000",
        "quizName": "Find your fit quiz",
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "channel": "on-site-embed",
        "customer":{
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "example@okendo.io"
        },
        "emailMarketingOptIn": true,
        "order": {
            "remoteOrderId": "123456789"
        },
        "answeredQuestions": [
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "multi-select",
                "text": "Which colors do you usually wear?",
                "answer": [
                    "Red",
                    "Blue",
                    "Other"
                ],
                "customAnswerOptionText": "Other",
                "customAnswer": "Orange"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "single-select",
                "text": "Help us understand! Why did you choose to leave our site?",
                "answer": "Didn't find what I was looking for",
                "customAnswerOptionText": "Other"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "star",
                "text": "How would you rate our customer service?",
                "answer": 5
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "five-point",
                "text": "How was your online shopping experience?",
                "answer": 4
            }
        ],
        "recommendation":{
            "type": "weighted-tags",
            "recommendedProducts": [
                {
                    "points": 5,
                    "product": {
                        "remoteProductId": "1234567890123",
                        "tags": [
                            "red"
                        ]
                    }
                },
                {
                    "points": 2,
                    "product": {
                        "remoteProductId": "1234567890123",
                        "tags": [
                            "blue"
                        ]
                    }
                },
                {
                    "points": 2,
                    "product": {
                        "remoteProductId": "1234567890123",
                        "tags": [
                            "blue"
                        ]
                    }
                }
            ],
            "runnerUpProducts": [
                {
                    "points": 2,
                    "product": {
                        "remoteProductId": "1234567890123",
                        "tags": [
                            "blue"
                        ]
                    }
                },
                {
                    "points": 1,
                    "product": {
                        "remoteProductId": "1234567890123",
                        "tags": [
                            "green"
                        ]
                    }
                },
                {
                    "points": 1,
                    "product": {
                        "remoteProductId": "1234567890123",
                        "tags": [
                            "purple"
                        ]
                    }
                }
            ],
            "tagPoints: [
                {
                    "points": 5,
                    "tag": "red"
                },
                {
                    "points": 2,
                    "tag": "blue"
                },
                {
                    "points": 1,
                    "tag": "green"
                },
                {
                    "points": 1,
                    "tag": "purple"
                }
            ]
        },
        "reward": {
            "description": "$10 off your next order over $40",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX"
        }
    },
    "resourceType": "quiz_response",
    "sequenceNumber": "123123412",
    "topic": "delete",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>review.create</code></summary>

```json
{

    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "reviewId": "123e4567-e89b-12d3-a456-426614174000",
        "productId": "shopify-123456789",
        "attributesWithRating": [
            {
                "minLabel": "Too Small",
                "midLabel": "Just Right",
                "maxLabel": "Too Big",
                "title": "Sizing",
                "type": "centered-range",
                "value": 1
            }
        ],
        "body": "Great quality and price! Would buy again!",
        "containsProfanity": true,
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "helpfulCount": 1,
        "isRecommended": true,
        "media": [
            {
                "streamId": "123e4567-e89b-12d3-a456-426614174000",
                "fullSizeUrl": "https://example.com",
                "largeUrl": "https://example.com",
                "thumbnailUrl": "https://example.com",
                "type": "image",
                "isHidden": true
            }
        ],
        "productAttributes": [
            {
                "title": "Pros",
                "type": "drop-down",
                "value": "Powerful"
            }
        ],
        "productName": "Laptop Pro",
        "order": {
            "orderId": "123456789",
            "orderNumber": "#OKRXXXX"
        },
        "rating": 5,
        "reply": {
            "body": "<p><b>Thanks</b> for your review</p>",
            "dateCreated": "2025-03-24T07:32:17.872Z",
            "rawBody": "*Thanks* for your review",
            "isPrivate": true
        },
        "reviewer": {
            "attributes": [
                {
                    "title": "Pros",
                    "type": "drop-down",
                    "value": "Powerful"
                }
            ],
            "avatarUrl": "https://example.com",
            "displayName": "Alex S.",
            "email": "name@gmail.com",
            "isVerified": true,
            "location": {
                "country": {
                    "code": "au",
                    "name": "Australia"
                },
                "zoneCode": "NSW"
            },
            "name": "Alex Stevens",
            "socialConnection": "facebook",
            "verifiedStatus": "Verified Buyer"
        },
        "reward": {
            "description": "$10 off your next order over $40",
            "integration": "rewardsPlatform",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX",
            "isCouponUpgrade": true
        },
        "sentiment": "positive",
        "status": "approved",
        "tags": [
            "Support Needed",
            "Favourite"
        ],
        "title": "Fantastic product!",
        "unhelpfulCount": 1,
        "variantId": "1234567890",
        "variantName": "Laptop Pro - 15 Inch"
    },
    "resourceType": "review",
    "sequenceNumber": "123123412",
    "topic": "create",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>review.update</code></summary>

```json
{
    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "reviewId": "123e4567-e89b-12d3-a456-426614174000",
        "productId": "shopify-123456789",
        "attributesWithRating": [
            {
                "minLabel": "Too Small",
                "midLabel": "Just Right",
                "maxLabel": "Too Big",
                "title": "Sizing",
                "type": "centered-range",
                "value": 1
            }
        ],
        "body": "Great quality and price! Would buy again!",
        "containsProfanity": true,
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "helpfulCount": 1,
        "isRecommended": true,
        "media": [
            {
                "streamId": "123e4567-e89b-12d3-a456-426614174000",
                "fullSizeUrl": "https://example.com",
                "largeUrl": "https://example.com",
                "thumbnailUrl": "https://example.com",
                "type": "image",
                "isHidden": true
            }
        ],
        "productAttributes": [
            {
                "title": "Pros",
                "type": "drop-down",
                "value": "Powerful"
            }
        ],
        "productName": "Laptop Pro",
        "order": {
            "orderId": "123456789",
            "orderNumber": "#OKRXXXX"
        },
        "rating": 5,
        "reply": {
            "body": "<p><b>Thanks</b> for your review</p>",
            "dateCreated": "2025-03-24T07:32:17.872Z",
            "rawBody": "*Thanks* for your review",
            "isPrivate": true
        },
        "reviewer": {
            "attributes": [
                {
                    "title": "Pros",
                    "type": "drop-down",
                    "value": "Powerful"
                }
            ],
            "avatarUrl": "https://example.com",
            "displayName": "Alex S.",
            "email": "name@gmail.com",
            "isVerified": true,
            "location": {
                "country": {
                    "code": "au",
                    "name": "Australia"
                },
                "zoneCode": "NSW"
            },
            "name": "Alex Stevens",
            "socialConnection": "facebook",
            "verifiedStatus": "Verified Buyer"
        },
        "reward": {
            "description": "$10 off your next order over $40",
            "integration": "rewardsPlatform",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX",
            "isCouponUpgrade": true
        },
        "sentiment": "positive",
        "status": "approved",
        "tags": [
            "Support Needed",
            "Favourite"
        ],
        "title": "Fantastic product!",
        "unhelpfulCount": 1,
        "variantId": "1234567890",
        "variantName": "Laptop Pro - 15 Inch"
    },
    "resourceType": "review",
    "sequenceNumber": "123123412",
    "topic": "update",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>review.delete</code></summary>

```json
{
    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "reviewId": "123e4567-e89b-12d3-a456-426614174000",
        "productId": "shopify-123456789",
        "attributesWithRating": [
            {
                "minLabel": "Too Small",
                "midLabel": "Just Right",
                "maxLabel": "Too Big",
                "title": "Sizing",
                "type": "centered-range",
                "value": 1
            }
        ],
        "body": "Great quality and price! Would buy again!",
        "containsProfanity": true,
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "helpfulCount": 1,
        "isRecommended": true,
        "media": [
            {
                "streamId": "123e4567-e89b-12d3-a456-426614174000",
                "fullSizeUrl": "https://example.com",
                "largeUrl": "https://example.com",
                "thumbnailUrl": "https://example.com",
                "type": "image",
                "isHidden": true
            }
        ],
        "productAttributes": [
            {
                "title": "Pros",
                "type": "drop-down",
                "value": "Powerful"
            }
        ],
        "productName": "Laptop Pro",
        "order": {
            "orderId": "123456789",
            "orderNumber": "#OKRXXXX"
        },
        "rating": 5,
        "reply": {
            "body": "<p><b>Thanks</b> for your review</p>",
            "dateCreated": "2025-03-24T07:32:17.872Z",
            "rawBody": "*Thanks* for your review",
            "isPrivate": true
        },
        "reviewer": {
            "attributes": [
                {
                    "title": "Pros",
                    "type": "drop-down",
                    "value": "Powerful"
                }
            ],
            "avatarUrl": "https://example.com",
            "displayName": "Alex S.",
            "email": "name@gmail.com",
            "isVerified": true,
            "location": {
                "country": {
                    "code": "au",
                    "name": "Australia"
                },
                "zoneCode": "NSW"
            },
            "name": "Alex Stevens",
            "socialConnection": "facebook",
            "verifiedStatus": "Verified Buyer"
        },
        "reward": {
            "description": "$10 off your next order over $40",
            "integration": "rewardsPlatform",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX",
            "isCouponUpgrade": true
        },
        "sentiment": "positive",
        "status": "approved",
        "tags": [
            "Support Needed",
            "Favourite"
        ],
        "title": "Fantastic product!",
        "unhelpfulCount": 1,
        "variantId": "1234567890",
        "variantName": "Laptop Pro - 15 Inch"
    },
    "resourceType": "review",
    "sequenceNumber": "123123412",
    "topic": "delete",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>survey_response.create</code></summary>

```
{
    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyResponseId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyName": "Website Experience",
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "channel": "post-checkout",
        "channelSurveyId": "123e4567-e89b-12d3-a456-426614174000",
        "channelSurveyDescription": "New customers purchasing product X",
        "customer":{
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "example@okendo.io"
        },
        "order": {
            "remoteOrderId": "123456789"
        },
        "answeredQuestions": [
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "multi-select",
                "text": "Which colors do you usually wear?",
                "answer": [
                    "Red",
                    "Blue",
                    "Other"
                ],
                "customAnswerOptionText": "Other",
                "customAnswer": "Orange"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "single-select",
                "text": "Help us understand! Why did you choose to leave our site?",
                "answer": "Didn't find what I was looking for",
                "customAnswerOptionText": "Other"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "star",
                "text": "How would you rate our customer service?",
                "answer": 5
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "five-point",
                "text": "How was your online shopping experience?",
                "answer": 4
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "nps",
                "text": "How likely is it that you would recommend us to a friend or colleague?",
                "answer": 8,
                "answerNpsCategory": "passive"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "text",
                "text": "Any other comments?",
                "answer": "I can't find a shirt in my size."
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "email",
                "text": "What's your email address?",
                "answer": "example@okendo.io",
                "marketingOptIn": true
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "What are your skin concerns?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "multi-value",
                    "value": [
                        "Pigmentation",
                        "Redness",
                        "Sensitivity"
                    ]
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "How old are you?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "single-value",
                    "value": "25-34"
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "Where do you live, country and zone?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "location",
                    "value": {
                        "countryCode": "BD"
                    }
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "When is your birthday?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer": {
                    "type": "date-components",
                    "value": {
                        "day": 1,
                        "month": 1
                    }
                }
            }
        ],
        "reward": {
            "description": "$10 off your next order over $40",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX"
        }
    },
    "resourceType": "survey_response",
    "sequenceNumber": "123123412",
    "topic": "create",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>survey_response.update</code></summary>

```
{
    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyResponseId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyName": "Website Experience",
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "channel": "post-checkout",
        "channelSurveyId": "123e4567-e89b-12d3-a456-426614174000",
        "channelSurveyDescription": "New customers purchasing product X",
        "customer":{
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "example@okendo.io"
        },
        "order": {
            "remoteOrderId": "123456789"
        },
        "answeredQuestions": [
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "multi-select",
                "text": "Which colors do you usually wear?",
                "answer": [
                    "Red",
                    "Blue",
                    "Other"
                ],
                "customAnswerOptionText": "Other",
                "customAnswer": "Orange"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "single-select",
                "text": "Help us understand! Why did you choose to leave our site?",
                "answer": "Didn't find what I was looking for",
                "customAnswerOptionText": "Other"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "star",
                "text": "How would you rate our customer service?",
                "answer": 5
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "five-point",
                "text": "How was your online shopping experience?",
                "answer": 4
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "nps",
                "text": "How likely is it that you would recommend us to a friend or colleague?",
                "answer": 8,
                "answerNpsCategory": "passive"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "text",
                "text": "Any other comments?",
                "answer": "I can't find a shirt in my size."
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "email",
                "text": "What's your email address?",
                "answer": "example@okendo.io",
                "marketingOptIn": true
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "What are your skin concerns?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "multi-value",
                    "value": [
                        "Pigmentation",
                        "Redness",
                        "Sensitivity"
                    ]
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "How old are you?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "single-value",
                    "value": "25-34"
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "Where do you live, country and zone?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "location",
                    "value": {
                        "countryCode": "BD"
                    }
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "When is your birthday?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer": {
                    "type": "date-components",
                    "value": {
                        "day": 1,
                        "month": 1
                    }
                }
            }
        ],
        "reward": {
            "description": "$10 off your next order over $40",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX"
        }
    },
    "resourceType": "survey_response",
    "sequenceNumber": "123123412",
    "topic": "update",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>survey_response.delete</code></summary>

```
{
    "resource": {
        "subscriberId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyResponseId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyId": "123e4567-e89b-12d3-a456-426614174000",
        "surveyName": "Website Experience",
        "dateCreated": "2025-03-24T07:32:17.872Z",
        "channel": "post-checkout",
        "channelSurveyId": "123e4567-e89b-12d3-a456-426614174000",
        "channelSurveyDescription": "New customers purchasing product X",
        "customer":{
            "customerId": "123e4567-e89b-12d3-a456-426614174000",
            "email": "example@okendo.io"
        },
        "order": {
            "remoteOrderId": "123456789"
        },
        "answeredQuestions": [
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "multi-select",
                "text": "Which colors do you usually wear?",
                "answer": [
                    "Red",
                    "Blue",
                    "Other"
                ],
                "customAnswerOptionText": "Other",
                "customAnswer": "Orange"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "single-select",
                "text": "Help us understand! Why did you choose to leave our site?",
                "answer": "Didn't find what I was looking for",
                "customAnswerOptionText": "Other"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "star",
                "text": "How would you rate our customer service?",
                "answer": 5
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "five-point",
                "text": "How was your online shopping experience?",
                "answer": 4
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "nps",
                "text": "How likely is it that you would recommend us to a friend or colleague?",
                "answer": 8,
                "answerNpsCategory": "passive"
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "text",
                "text": "Any other comments?",
                "answer": "I can't find a shirt in my size."
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "email",
                "text": "What's your email address?",
                "answer": "example@okendo.io",
                "marketingOptIn": true
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "What are your skin concerns?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "multi-value",
                    "value": [
                        "Pigmentation",
                        "Redness",
                        "Sensitivity"
                    ]
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "How old are you?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "single-value",
                    "value": "25-34"
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "Where do you live, country and zone?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer":{
                    "type": "location",
                    "value": {
                        "countryCode": "BD"
                    }
                }
            },
            {
                "id": "123e4567-e89b-12d3-a456-426614174000",
                "type": "profile",
                "text": "When is your birthday?",
                "profileQuestionId": "123e4567-e89b-12d3-a456-426614174000",
                "answer": {
                    "type": "date-components",
                    "value": {
                        "day": 1,
                        "month": 1
                    }
                }
            }
        ],
        "reward": {
            "description": "$10 off your next order over $40",
            "type": "coupon",
            "value": "OKRX-XXXXX-XXXX"
        }
    },
    "resourceType": "survey_response",
    "sequenceNumber": "123123412",
    "topic": "delete",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>referral.create</code></summary>

```
{
    "resource": {
        "channel": "on-site",
        "dateCreated": "2025-11-04T04:37:38.079Z",
        "localeCode": "en-US",
        "recipient": {
            "customerId": "ac74dbb1-b420-4276-8e4b-3659d5ce3833",
            "email": "example@okendo.io",
            "status": "invited",
            "statusHistory": [
                {
                    "date": "2025-11-04T04:37:38.079Z",
                    "status": "invited"
                }
            ]
        },
        "referralId": "77c73dfc-fd02-4fc1-9597-2b5a49a4a7e3",
        "sender": {
            "customerId": "9fb076d1-aa1a-41bd-ba6f-c8ee6bd1e0a0",
            "email": "example@okendo.io",
            "status": "awaiting-recipient-order",
            "statusHistory": [
                {
                    "date": "2025-11-04T04:37:38.079Z",
                    "status": "awaiting-recipient-order"
                }
            ]
        },
        "source": "email",
        "subscriberId": "2c49b59d-d728-47da-94dd-613b89ccbb0b"
    },
    "resourceType": "referral",
    "sequenceNumber": "4600756000000592691356915672",
    "topic": "create",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>referral.update</code></summary>

```
{
    "resource": {
        "channel": "on-site",
        "dateCreated": "2025-10-31T01:54:42.893Z",
        "localeCode": "en",
        "recipient": {
            "customerId": "a5b6b7c1-1ee5-4dc5-9580-77f54c4d50ee",
            "email": "example@okendo.io",
            "issuedReward": {
                "code": "OKRJ-CFY2Y-MUGG",
                "description": "10% off your first order",
                "expiryDate": "2025-11-30T01:54:46.114Z",
                "type": "coupon",
                "value": {
                    "value": 10,
                    "valueType": "percentage"
                }
            },
            "order": {
                "orderDiscountAmount": 16,
                "orderId": "shopify-5669829509253",
                "orderNumber": "#1113",
                "orderTotalPrice": 158.4
            },
            "status": "order-placed",
            "statusHistory": [
                {
                    "date": "2025-10-31T01:54:42.893Z",
                    "status": "invited"
                },
                {
                    "date": "2025-10-31T01:55:34.733Z",
                    "status": "identified"
                },
                {
                    "date": "2025-10-31T01:55:38.637Z",
                    "status": "coupon-issued"
                },
                {
                    "date": "2025-10-31T01:58:04.907Z",
                    "status": "order-placed"
                }
            ]
        },
        "referralId": "d6de8d7e-9da6-42eb-9ad9-7e7a8f23157b",
        "sender": {
            "customerId": "eba5c3e8-db82-41ab-9747-6b35cca28078",
            "email": "example@okendo.io",
            "issuedReward": {
                "type": "none"
            },
            "status": "coupon-issued",
            "statusHistory": [
                {
                    "date": "2025-10-31T01:54:42.893Z",
                    "status": "awaiting-recipient-order"
                },
                {
                    "date": "2025-10-31T01:58:04.907Z",
                    "status": "awaiting-coupon-delay"
                },
                {
                    "date": "2025-10-31T01:58:21.766Z",
                    "status": "coupon-issued"
                }
            ]
        },
        "source": "shareable-link",
        "subscriberId": "f843f629-3fdd-49b1-845a-6bfa37dd311b"
    },
    "resourceType": "referral",
    "sequenceNumber": "4543935900003604676094650312",
    "topic": "update",
    "version": "2025-02-01"
}
```

</details>

<details>

<summary><code>referral.delete</code></summary>

```
{
    "resource": {
        "channel": "on-site",
        "dateCreated": "2025-10-31T01:54:42.893Z",
        "localeCode": "en",
        "recipient": {
            "customerId": "a5b6b7c1-1ee5-4dc5-9580-77f54c4d50ee",
            "email": "example@okendo.io",
            "issuedReward": {
                "code": "OKRJ-CFY2Y-MUGG",
                "description": "10% off your first order",
                "expiryDate": "2025-11-30T01:54:46.114Z",
                "type": "coupon",
                "value": {
                    "value": 10,
                    "valueType": "percentage"
                }
            },
            "order": {
                "orderDiscountAmount": 16,
                "orderId": "shopify-5669829509253",
                "orderNumber": "#1113",
                "orderTotalPrice": 158.4
            },
            "status": "order-placed",
            "statusHistory": [
                {
                    "date": "2025-10-31T01:54:42.893Z",
                    "status": "invited"
                },
                {
                    "date": "2025-10-31T01:55:34.733Z",
                    "status": "identified"
                },
                {
                    "date": "2025-10-31T01:55:38.637Z",
                    "status": "coupon-issued"
                },
                {
                    "date": "2025-10-31T01:58:04.907Z",
                    "status": "order-placed"
                }
            ]
        },
        "referralId": "d6de8d7e-9da6-42eb-9ad9-7e7a8f23157b",
        "sender": {
            "customerId": "eba5c3e8-db82-41ab-9747-6b35cca28078",
            "email": "example@okendo.io",
            "issuedReward": {
                "type": "none"
            },
            "status": "coupon-issued",
            "statusHistory": [
                {
                    "date": "2025-10-31T01:54:42.893Z",
                    "status": "awaiting-recipient-order"
                },
                {
                    "date": "2025-10-31T01:58:04.907Z",
                    "status": "awaiting-coupon-delay"
                },
                {
                    "date": "2025-10-31T01:58:21.766Z",
                    "status": "coupon-issued"
                }
            ]
        },
        "source": "shareable-link",
        "subscriberId": "f843f629-3fdd-49b1-845a-6bfa37dd311b"
    },
    "resourceType": "referral",
    "sequenceNumber": "4543935900003604676094650312",
    "topic": "delete",
    "version": "2025-02-01"
}
```

</details>


