> For the complete documentation index, see [llms.txt](https://developer.emporix.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.emporix.io/ce/system-management/search/algolia.md).

# Algolia Search Provider

This guide covers Algolia integration with Emporix:

* **Webhook-based configuration** – Forward `index-item.updated` and `index-item.deleted` events through Svix to Algolia endpoints, with transformations to match Algolia API requirements. See [Webhook-based search configuration](#webhook-based-search-configuration).
* **Indexing output by strategy** – Reference document formats produced by the Indexing Service for SPLIT and MERGE strategies. See [Indexing output by strategy](#indexing-output-by-strategy).

## Webhook-based search configuration

Before configuring Algolia endpoints, complete the shared webhook setup in [Search Configuration with Webhooks](/ce/system-management/search/search-configuration.md).

### Creating and updating products

{% stepper %}
{% step %}

#### Add an endpoint

In **Endpoints**, choose **Add Endpoint** and fill in the fields with the following values:

* Endpoint URL - `https://{ALGOLIA_APPLICATION_ID}.algolia.net/1/indexes` - provide your Algolia application ID
* Description - `Algolia Create/Update`
* Message filtering - select only the `index-item.updated` event

<figure><img src="/files/ofqyN1zKP70NHyVu0d1Q" alt="Svix endpoint configuration for Algolia create and update" width="563"><figcaption><p>Svix endpoint configuration for Algolia create and update</p></figcaption></figure>
{% endstep %}

{% step %}

#### Save the endpoint

Choose **Create** and check if your configuration was properly saved.
{% endstep %}

{% step %}

#### Add custom headers

Go to the **Advanced** tab, provide the required custom headers and enable the transformation feature:

* Key: `X-Algolia-API-Key`\
  Value: `YOUR_ALGOLIA_ADMIN_API_KEY`
* Key: `X-Algolia-Application-Id`\
  Value: `YOUR_ALGOLIA_APPLICATION_ID`

Find the right values for your keys in your application settings (API Keys) in your Algolia account.
{% endstep %}

{% step %}

#### Enable transformations

In the **Transformations** section, set the **transformation** feature to **enabled**.

<figure><img src="/files/KX7gjjvqSHPSx3eoBTXc" alt="Transformations enabled in Svix endpoint Advanced tab" width="563"><figcaption><p>Transformations enabled in Svix endpoint Advanced tab</p></figcaption></figure>
{% endstep %}

{% step %}

#### Configure the transformation mapping

In **Edit transformation**, start working on the Algolia mapping.

Since there are differences between the default mapping in Svix and Algolia requirements, we need to adjust the mapping to make it work properly.

The default mapping available in Svix is as follows:

```javascript
/**
 * @param webhook the webhook object
 * @param webhook.method destination method. Allowed values: "POST", "PUT"
 * @param webhook.url current destination address
 * @param webhook.eventType current webhook Event Type
 * @param webhook.payload JSON payload
 * @param webhook.cancel whether to cancel dispatch of the given webhook
 */
function handler(webhook) {
  // modify the webhook object...
  
  // and return it
  return webhook
}
```

\
According to Algolia API Reference, the request that should be sent is as follows:

```bash
curl "https://${APPLICATION_ID}.algolia.net/1/indexes/contacts/myID" \
     -X PUT \
     -H "X-Algolia-API-Key: ${API_KEY}" \
     -H "X-Algolia-Application-Id: ${APPLICATION_ID}" \
     -d '{
            "name": "Betty Jane Mccamey",
            "company": "Vita Foods Inc.",
            "email": "betty@mccamey.com"
         }'
```

To learn more about Algolia API, see [Algolia API Reference](https://www.algolia.com/doc/rest-api/search/#add-or-replace-object-by-id).

In the **Edit transformation** section, change the code to create the right mapping:\
\
a. Change the http method:

```javascript
/**
 * @param webhook the webhook object
 * @param webhook.method destination method. Allowed values: "POST", "PUT"
 * @param webhook.url current destination address
 * @param webhook.eventType current webhook Event Type
 * @param webhook.payload JSON payload
 * @param webhook.cancel whether to cancel dispatch of the given webhook
 */
function handler(webhook) {

  webhook.method = "PUT";
  return webhook
}
```

\
b. Modify the target URL:

```javascript
/**
 * @param webhook the webhook object
 * @param webhook.method destination method. Allowed values: "POST", "PUT"
 * @param webhook.url current destination address
 * @param webhook.eventType current webhook Event Type
 * @param webhook.payload JSON payload
 * @param webhook.cancel whether to cancel dispatch of the given webhook
 */
function handler(webhook) {

  var indexName = "emporix_" + webhook.payload.siteCode;
  webhook.url = webhook.url + "/" + indexName + "/" + webhook.payload.id;
  webhook.method = "PUT";
  return webhook
}
```

\
c. Optional: Modify the message body. For example, you can add additional field like image based on media field:

```javascript

/**
 * @param webhook the webhook object
 * @param webhook.method destination method. Allowed values: "POST", "PUT"
 * @param webhook.url current destination address
 * @param webhook.eventType current webhook Event Type
 * @param webhook.payload JSON payload
 * @param webhook.cancel whether to cancel dispatch of the given webhook
 */
function handler(webhook) {

  if(webhook.payload.medias && webhook.payload.medias.length > 0) {
    webhook.payload.image = webhook.payload.medias[0].url;
  }

  var indexName = "emporix_" + webhook.payload.siteCode;
  webhook.url = webhook.url + "/" + indexName + "/" + webhook.payload.id;
  webhook.method = "PUT";
  return webhook
}
```

{% endstep %}

{% step %}

#### Run the transformation test

Choose **Run test** for the `index-item.updated` payload. As a result, you can see your transformed output.
{% endstep %}

{% step %}

#### Save your changes

If the output is correct, save your changes.
{% endstep %}

{% step %}

#### Test the configuration

Create a product in Management Dashboard and after a few minutes check if it appears in your index in the Algolia account. With this configuration, every time when a product is created or updated, the appropriate event is propagated to Svix, transformed and sent to Algolia.
{% endstep %}
{% endstepper %}

### Deleting products

{% stepper %}
{% step %}

#### Add an endpoint

In **Endpoints**, choose the **Add Endpoint**. Fill in the fields with the following values:

* Endpoint URL - `https://{ALGOLIA_APPLICATION_ID}.algolia.net/1/indexes` - provide your Algolia application ID
* Description - `Algolia Delete`
* Message filtering - select only the `index-item.deleted` event

<figure><img src="/files/C773ObkaZkeu92kmwaDD" alt="Svix endpoint configuration for Algolia delete" width="563"><figcaption><p>Svix endpoint configuration for Algolia delete</p></figcaption></figure>
{% endstep %}

{% step %}

#### Save the endpoint

Choose **Create** and check if your configuration was properly saved.
{% endstep %}

{% step %}

#### Add custom headers

Go to the **Advanced** tab, provide the required custom headers and enable the transformation feature:

* Key: `X-Algolia-API-Key`\
  Value: `YOUR_ALGOLIA_ADMIN_API_KEY`
* Key: `X-Algolia-Application-Id`\
  Value: `YOUR_ALGOLIA_APPLICATION_ID`

Find the right values for your keys in your application settings (API Keys) in your Algolia account.
{% endstep %}

{% step %}

#### Enable transformations

In the **Transformations** section, set the **transformation** feature to **enabled**.

<figure><img src="/files/KX7gjjvqSHPSx3eoBTXc" alt="Transformations enabled in Svix endpoint Advanced tab" width="563"><figcaption><p>Transformations enabled in Svix endpoint Advanced tab</p></figcaption></figure>
{% endstep %}

{% step %}

#### Configure the transformation mapping

According to Algolia API Reference, the request that should be sent is as follows:

```bash
curl -X DELETE \
     -H "X-Algolia-API-Key: ${API_KEY}" \
     -H "X-Algolia-Application-Id: ${APPLICATION_ID}" \
    "https://${APPLICATION_ID}.algolia.net/1/indexes/contacts/myID"
```

To learn more about Algolia API, see [Algolia API Reference](https://www.algolia.com/doc/rest-api/search/#add-or-replace-object-by-id).

In the **Edit transformation** section, change the code to create the right mapping:\
\
a. Change the http method:

```javascript
/**
 * @param webhook the webhook object
 * @param webhook.method destination method. Allowed values: "POST", "PUT"
 * @param webhook.url current destination address
 * @param webhook.eventType current webhook Event Type
 * @param webhook.payload JSON payload
 * @param webhook.cancel whether to cancel dispatch of the given webhook
 */
function handler(webhook) {

  webhook.method = "DELETE";
  return webhook
}
```

\
b. Change the target URL:

```javascript
/**
 * @param webhook the webhook object
 * @param webhook.method destination method. Allowed values: "POST", "PUT"
 * @param webhook.url current destination address
 * @param webhook.eventType current webhook Event Type
 * @param webhook.payload JSON payload
 * @param webhook.cancel whether to cancel dispatch of the given webhook
 */
function handler(webhook) {

  var indexName = "emporix_" + webhook.payload.siteCode;
  webhook.url = webhook.url + "/" + indexName + "/" + webhook.payload.id;
  webhook.method = "DELETE";
  return webhook
}
```

{% endstep %}

{% step %}

#### Save your changes

If the output is correct, save your changes.
{% endstep %}

{% step %}

#### Test the configuration

Delete a product in Management Dashboard and after a few minutes check if it was deleted in your index in the Algolia account. With this configuration, every time when a product gets deleted, the appropriate event is propagated to Svix, transformed and then sent to Algolia.
{% endstep %}
{% endstepper %}

## Indexing output by strategy

The following sections describe Algolia index document structure produced by Indexing Service for SPLIT and MERGE strategies.

{% tabs %}
{% tab title="SPLIT strategy" %}
The example below shows the document format stored in the Algolia index when the SPLIT strategy is active. BatteryIncluded does not support this strategy.

<details>

<summary>See an example document with SPLIT strategy</summary>

```json
  {
  "name": [
    "Banana"
  ],
  "localizedName": {
    "en": "Banana"
  },
  "categories": [
    "Food"
  ],
  "popularity": 0,
  "prices": [
    {
      "id": "659bd4e09862ec2ec136a61b",
      "itemId": {
        "itemType": "PRODUCT",
        "id": "659bd4bfb9ce7a0b975c33eb",
        "name": {
          "en": "Banana"
        }
      },
      "currency": "EUR",
      "originalAmount": 1.99,
      "effectiveAmount": 1.99,
      "location": {
        "countryCode": "DE"
      },
      "priceModelId": "63402c86af907617bb4e1234",
      "priceModel": {
        "id": "63402c86af907617bb4e1234",
        "name": {
          "en": "Default price model"
        },
        "description": {
          "en": "Default price model"
        },
        "includesTax": false,
        "measurementUnit": {
          "quantity": 1,
          "unitCode": "pc"
        },
        "tierDefinition": {
          "tierType": "BASIC",
          "tiers": [
            {
              "minQuantity": {
                "quantity": 0,
                "unitCode": "pc"
              },
              "id": "63402c86af907617bb4e9826"
            }
          ]
        }
      },
      "restrictions": {
        "validity": null,
        "siteCodes": [
          "main"
        ]
      },
      "tierValues": [
        {
          "id": "63402c86af907617bb4e9826",
          "priceValue": 1.99
        }
      ],
      "siteCode": "main"
    }
  ],
  "description": [
    "Banana "
  ],
  "localizedDescription": {
    "en": "Banana "
  },
  "image": "http://res.cloudinary.com/saas-ag/image/upload/v1704711465/lspaymentstage/media/659bd5286bec48360e3b3a83",
  "code": "Banana",
  "categoriesMissing": false,
  "available": false,
  "distributionChannel": [
    "ASSORTMENT"
  ],
  "category_assignments": [
    {
      "id": "2918ddc4-0c1c-4977-bb91-a4c366c535a6",
      "name": "Food",
      "localizedName": {
        "en": "Food"
      },
      "code": "food",
      "localizedSlug": {
        "en": "food"
      },
      "parent": null
    }
  ],
  "category_levels": {
    "level0": [
      "Food"
    ]
  },
  "_tags": [
    "product",
    "published"
  ],
  "category_ids": [
    "2918ddc4-0c1c-4977-bb91-a4c366c535a6"
  ],
  "objectID": "urn:yaas:saasag:caasproduct:product:TENANT;659bd4bfb9ce7a0b975c33eb"
  }
  
```

</details>
{% endtab %}

{% tab title="MERGE strategy" %}
The example below shows the document format stored in the Algolia index when the MERGE strategy is active.

<details>

<summary>See an example document with MERGE strategy</summary>

```json
{
"name": [
  "Banana"
],
"localizedName": {
  "en": "Banana"
},
"categories": [
  "Food"
],
"popularity": 0,
"prices": [
  {
    "id": "659bd4e09862ec2ec136a61b",
    "itemId": {
      "itemType": "PRODUCT",
      "id": "659bd4bfb9ce7a0b975c33eb",
      "name": {
        "en": "Banana"
      }
    },
    "currency": "EUR",
    "originalAmount": 1.99,
    "effectiveAmount": 1.99,
    "location": {
      "countryCode": "DE"
    },
    "priceModelId": "63402c86af907617bb4e1234",
    "priceModel": {
      "id": "63402c86af907617bb4e1234",
      "name": {
        "en": "Default price model"
      },
      "description": {
        "en": "Default price model"
      },
      "includesTax": false,
      "measurementUnit": {
        "quantity": 1,
        "unitCode": "pc"
      },
      "tierDefinition": {
        "tierType": "BASIC",
        "tiers": [
          {
            "minQuantity": {
              "quantity": 0,
              "unitCode": "pc"
            },
            "id": "63402c86af907617bb4e9826"
          }
        ]
      }
    },
    "restrictions": {
      "validity": null,
      "siteCodes": [
        "main"
      ]
    },
    "tierValues": [
      {
        "id": "63402c86af907617bb4e9826",
        "priceValue": 1.99
      }
    ],
    "siteCode": "main"
  }
],
"description": [
  "Banana"
],
"localizedDescription": {
  "en": "Banana"
},
"image": "http://res.cloudinary.com/saas-ag/image/upload/v1704711465/lspaymentstage/media/659bd5286bec48360e3b3a83.jpg",
"code": "Banana",
"categoriesMissing": false,
"available": false,
"distributionChannel": [
  "ASSORTMENT"
],
"sitePrices": {
  "DE": [
    {
      "id": "659bd4f29862ec2ec136a61c",
      "itemId": {
        "itemType": "PRODUCT",
        "id": "659bd4bfb9ce7a0b975c33eb",
        "name": {
          "en": "Banana"
        }
      },
      "currency": "EUR",
      "originalAmount": 2.49,
      "effectiveAmount": 2.49,
      "location": {
        "countryCode": "DE"
      },
      "priceModelId": "63402c86af907617bb4e1234",
      "priceModel": {
        "id": "63402c86af907617bb4e1234",
        "name": {
          "en": "Default price model"
        },
        "description": {
          "en": "Default price model"
        },
        "includesTax": false,
        "measurementUnit": {
          "quantity": 1,
          "unitCode": "pc"
        },
        "tierDefinition": {
          "tierType": "BASIC",
          "tiers": [
            {
              "minQuantity": {
                "quantity": 0,
                "unitCode": "pc"
              },
              "id": "63402c86af907617bb4e9826"
            }
          ]
        }
      },
      "restrictions": {
        "validity": null,
        "siteCodes": [
          "DE",
          "FR"
        ]
      },
      "tierValues": [
        {
          "id": "63402c86af907617bb4e9826",
          "priceValue": 2.49
        }
      ],
      "siteCode": "DE"
    }
  ],
  "main": [
    {
      "id": "659bd4e09862ec2ec136a61b",
      "itemId": {
        "itemType": "PRODUCT",
        "id": "659bd4bfb9ce7a0b975c33eb",
        "name": {
          "en": "Banana"
        }
      },
      "currency": "EUR",
      "originalAmount": 1.99,
      "effectiveAmount": 1.99,
      "location": {
        "countryCode": "DE"
      },
      "priceModelId": "63402c86af907617bb4e1234",
      "priceModel": {
        "id": "63402c86af907617bb4e1234",
        "name": {
          "en": "Default price model"
        },
        "description": {
          "en": "Default price model"
        },
        "includesTax": false,
        "measurementUnit": {
          "quantity": 1,
          "unitCode": "pc"
        },
        "tierDefinition": {
          "tierType": "BASIC",
          "tiers": [
            {
              "minQuantity": {
                "quantity": 0,
                "unitCode": "pc"
              },
              "id": "63402c86af907617bb4e9826"
            }
          ]
        }
      },
      "restrictions": {
        "validity": null,
        "siteCodes": [
          "main"
        ]
      },
      "tierValues": [
        {
          "id": "63402c86af907617bb4e9826",
          "priceValue": 1.99
        }
      ],
      "siteCode": "main"
    }
  ],
  "FR": [
    {
      "id": "659bd4f29862ec2ec136a61c",
      "itemId": {
        "itemType": "PRODUCT",
        "id": "659bd4bfb9ce7a0b975c33eb",
        "name": {
          "en": "Banana"
        }
      },
      "currency": "EUR",
      "originalAmount": 2.49,
      "effectiveAmount": 2.49,
      "location": {
        "countryCode": "DE"
      },
      "priceModelId": "63402c86af907617bb4e1234",
      "priceModel": {
        "id": "63402c86af907617bb4e1234",
        "name": {
          "en": "Default price model"
        },
        "description": {
          "en": "Default price model"
        },
        "includesTax": false,
        "measurementUnit": {
          "quantity": 1,
          "unitCode": "pc"
        },
        "tierDefinition": {
          "tierType": "BASIC",
          "tiers": [
            {
              "minQuantity": {
                "quantity": 0,
                "unitCode": "pc"
              },
              "id": "63402c86af907617bb4e9826"
            }
          ]
        }
      },
      "restrictions": {
        "validity": null,
        "siteCodes": [
          "DE",
          "FR"
        ]
      },
      "tierValues": [
        {
          "id": "63402c86af907617bb4e9826",
          "priceValue": 2.49
        }
      ],
      "siteCode": "FR"
    }
  ]
},
"siteAvailabilities": {
  "DE": {
    "id": "DE:659bd4bfb9ce7a0b975c33eb",
    "stockLevel": 700,
    "productId": "659bd4bfb9ce7a0b975c33eb",
    "site": "DE",
    "available": false,
    "popularity": 0,
    "distributionChannel": "ASSORTMENT"
  },
  "main": {
    "id": "main:659bd4bfb9ce7a0b975c33eb",
    "stockLevel": 999,
    "productId": "659bd4bfb9ce7a0b975c33eb",
    "site": "main",
    "available": false,
    "popularity": 0,
    "distributionChannel": "ASSORTMENT"
  },
  "FR": {
    "id": "FR:659bd4bfb9ce7a0b975c33eb",
    "stockLevel": 50,
    "productId": "659bd4bfb9ce7a0b975c33eb",
    "site": "FR",
    "available": false,
    "popularity": 0,
    "distributionChannel": "ASSORTMENT"
  }
},
"category_assignments": [
  {
    "id": "2918ddc4-0c1c-4977-bb91-a4c366c535a6",
    "name": "Food",
    "localizedName": {
      "en": "Food"
    },
    "code": "food",
    "localizedSlug": {
      "en": "food"
    },
    "parent": null
  }
],
"category_levels": {
  "level0": [
    "Food"
  ]
},
"_tags": [
  "product",
  "published"
],
"category_ids": [
  "2918ddc4-0c1c-4977-bb91-a4c366c535a6"
],
"objectID": "urn:yaas:saasag:caasproduct:product:lspaymentstage;659bd4bfb9ce7a0b975c33eb"
}
```

</details>
{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://developer.emporix.io/ce/system-management/search/algolia.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
