---
# System prepended metadata

title: KohGenDo - BazaarVoice | YotPo integration

---

# KohGenDo - BazaarVoice | YotPo integration

> [name=Jan Kaczorowski]

[repo: https://github.com/0xb8n/yotpo-bazaarvoice]

## Business case

> [name=Milosz] We need to retrieve an xml file from bazaarvoice, parse it for customer data (i think basically just email address) and ship it to yotpo via their rest api.

> Bazaarvoice is a service that aggregates customer for a brand's products across the web. yotpo is a service that gives customers brand loyalty points. the idea is to give customers loyalty points if they review the product positively.


## Expected Flow

```plantuml
@startuml
autonumber

control "Our SinatraApp" as ourApp #99FF99
participant "BazaarVoice API" as BV
participant "YotPo API" as YP

ourApp -> BV : connects to SFTP, gets XML with Standard Client Feed
BV -> ourApp : responds with XML file
ourApp -> ourApp : parses XML, plucks Customer data from Review/<UserProfileReference> or <UserProfile>
note over ourApp
    then for every Customer found:
end note
ourApp -> YP : register new action 'Leave a Review' \n **POST /api/v2/actions**
@enduml
```


## BazaarVoice Standard Client feed (basically, XML file(s) on SFTP)
- has to be enabled, looks like by default it's disabled
- they say `If you use standard client feeds to build your data store, you should have the ability to consume a full client feed in addition to incremental feeds.`
- is available as an XML at `sftp-stg.bazaarvoice.com` in `/feeds` folder [more info here](https://knowledge.bazaarvoice.com/wp-content/conversations/en_US/Display/content_exports.html#standard-client-feed)
- :exclamation: **looks like we have to set it so that we'd get PII data. Only then we'll get `<UserEmailAddress>`** field

XPath to email: `/Feed/Product/Reviews/Review/UserEmailAddress[string-length(text()) > 0]`


#### Example client feed

https://knowledge.bazaarvoice.com/wp-content/conversations/en_US/Display/content_exports.html#example-standard-client-feed

- :warning: **<UserEmailAddress>** is present in **<Reviews>** but **not by default**, as it seems. 

specs say `If client prefers to get PII data in the feed, this field should be included. This is the author's (reviewer's) email address.` **need to enable it**

otherwise you just get stuff like this, w/o Email address:
```xml=
    <UserProfileReference id="202752">
         <Anonymous>false</Anonymous>
         <DisplayName>George Tsougarakis</DisplayName>
         <ExternalId>202752</ExternalId>
         <HyperlinkingEnabled>false</HyperlinkingEnabled>
      </UserProfileReference>
```
## :question: Questions:

1. How exactly is this sync process is supposed to be triggered? Am I right to assume that ultimately we need a scheduler to be able to initialize this action say at 1:00 AM every night or sth?

2. Shouldn't we filter only positive approved reviews? Shouldn't we be picking only those customer emails for which reviews meet the following criteria:
    - `<ModerationStatus>APPROVED</ModerationStatus>`
    - if `<RatingRange>5</RatingRange>`
    - then `<Rating>3</Rating>` or more etc.
    
3. Should we have sth like mini-dashboard, eg. one damn button to manually trigger sync + summary report from last sync or something?

4. When we push customers, should we tag them as "from BV" in YotPo, so that folks over there could se the origin of this customer or it just does not matter?

5. Since there's no customers index endpoint on YotPo API doing some sort of initial sync would be difficult. (there's only customers/recent, but that won't do) Are we okay with that? So sync-ing would only apply to customers of the new reviews from BV.


### YotPo API

#### Requests

register an action (No PATCH/PUT)
:8ball: **POST** `https://app.swellrewards.com/api/v2/actions`

```jsx=
// Headers:
// X-Guid: (from the account settings)
// X-Api-Key: (likewise)
{
    type: 'CustomAction'
    email: 'john.doe@example.com',
    action_name: 'Leave a Review'
}
```
[more info, API specs](https://loyaltyapi.yotpo.com/reference#createupdate-customer-records)


## Project tech notes 
(ignore those trivialities unless you also work on this)




#### Parsing example XML file


`xidel -se "//UserEmailAddress[string-length(text()) > 0]/text()" standard-feed-example.xml`
`xidel -se "/Feed/Product/Reviews/Review/UserEmailAddress[string-length(text()) > 0]" standard-feed-example.xml`