Changelog
January 2024
Design & API changes
- Webhooks are no longer limited to only 1 URL for the entire configuration. Instead, every webhook can have its specific destination URL.
- Webhooks now have their dedicated API endpoint – /api/sales-partners/webhooks
- Previously, they were set by the PUT /api/sales-partners/$id endpoint and passing the
pushUrl
andsubscribedWebhookEventTypes
which is no longer supported.
- Previously, they were set by the PUT /api/sales-partners/$id endpoint and passing the
New webhooks
We have introduced new webhooks explained in the Event types definitions section.
- LISTING_DATAPOINT_INVALID
- BRAND_DATAPOINT_CHECK
- DIRECTORY_BUSINESS_PAGE_DATA_POINT_INVALID
- LOCATION_DATA_SUGGESTION
Existing webhook changes
We have added parameters to streamline the handling of data points.
LISTING_DATAPOINT_CHECK
– when you listen for new data points, now you also receive which are the new datapoints so that they can be directly queried after
- The boolean field
newDatapointsFound
indicates if any new data point has been found - The array
newDataPointIds
lists the ids of each newly scraped datapoint. The same logic is applicable forBRAND_DATAPOINT_CHECK
- The array
updatedDataPointIds
will contain information for existing data points that have been updated, e.g. the end user has modified a customer review.
What is the event service? What are webhooks?
Webhooks are automated messages sent from apps when something happens. The platform's Event Service (Webhooks) allows enables real-time communication between our platform and other applications. It works by sending HTTP POST requests to a provided URL for subscribed events, such as changes in location information, updates to business listings, or modifications to social media interactions (e.g. reviews). This seamless integration allows you to stay informed about dynamic changes and facilitates the transfer of real-time data.
It can help you get real-time pings when and only a change happens
Setting up the service
The service can be set up in two ways:
Set up via the platform's interface
This is the most straightforward way. Log in with an Admin user in the platform, navigate to Org settings and you should see Webhooks tab. There you can add a designated target URL, per webhook, and also see the available webhooks.
API set up
Webhooks can be also set up by the API.
Supported webhook types
We offer various webhooks explained further below. Based on your use cases, you may decide to consume one or multiple webhooks.
To understand which are the currently supported event types (webhooks) you can query the following endpoint:
curl --location 'https://$yourdomain.com/api/sales-partners/subscribable-event-types' \
--header 'privateKey: $privateKey'
Subscribing to a webhook
To set up a new webhook you can run the following query. We allow sending the same webhook to multiple destinations (pushUrl
)
curl --location 'https://$yourdomain.com/api/salespartners/webhooks' \
--header 'privateKey: $privateKey' \
--data '{
"pushUrl" : "https://webhook.site/e84ba9cc-d56f-4e30-9607-cd3ddc65952f",
"type" : "LISTING_DATAPOINT_CHECK"
}'
Event types definitions
The application offers the following events (webhooks):
Type |
Description |
LISTING_SYNC_CHECK | a listing was sync checked, including possible status listing changes |
LISTING_LINK_CHANGE | the url of a listing has changed |
LISTING_UPDATE | listing's data was attempted to be submitted to the directory |
LISTING_STATUS_CHANGE | Indicates that the status of a listing was changed manually. This happens rarely and often is the result of a manual check by our Operations or Engineering teams. |
LISTING_DATAPOINT_CHECK | New datapoint(s) for a listing have been found or changes to existing datapoints have occurred |
LISTING_DATAPOINT_INVALID | a listing datapoint has been deleted from the directory so we have invalidated it, too |
DIRECTORY_BUSINESS_PAGE_DATA_POINT_CHECK | new datapoint(s) for a brand page been found |
DIRECTORY_BUSINESS_PAGE_DATA_POINT_INVALID | a brand datapoint has been deleted from the directory so we have invalidated it, too |
LOCATION_CREATED | a location has been created |
LOCATION_STATUS_CHANGED | a location's status has changed |
LOCATION_PROFILE_CHANGED | a location has been updated by a user |
BUSINESS_PRODUCT_PLAN_CHANGED | a business (and its subsequent locations) has changed product plans |
BUSINESS_CREATED | a business has been created |
The target URL and the subscribed events can be changed during runtime. In case the transmission of an event fails, the system will retry a few times and then discard the event.
What a payload looks like
Here's the basic structure of a payload. More information about the different event types and loads can be found in the Field Descriptions and Events.
{
"event": {
"comment": "Location profile has been updated",
"id": 2926113683,
"location": 636605,
"time": "2018-11-05T17:35:07.000+01:00",
"type": "LOCATION_PROFILE_CHANGED",
"user": "user@test.com"
},
"signature": "X"
}
All JSON payloads will always have the event and signature fields.
Field Description
Event
The event represents the change that has happened in the platform and it serves as the actual payload and varies based on the event type. Key fields include but are not limited to:
Field | Description | Comment |
id | unique id of the event being sent | can be used to make sure no events ever are handled twice |
time | the time the event occurred | |
type | the type of events | see below description for possible values |
listing | the id of the listing to which the event is related | |
location | the id of the location to which the event is related | can be used to react to the event and e.g. get the new location data after a change |
business | the id of the business to which the event is related | can be used to react to the event and e.g. get the new business after its creation |
salesPartnerIdentifier | the identifier of the partner account | can be used to react to the event and e.g. identify in which account the object was created (if you manage several) |
All other fields are different per event type and described further down.
Signature
The signature is calculated by casting the event field to a String and then HMAC_SHA256 encrypted using the sales partner's private key and BASE64 encode the result. The events fields need to be ordered alphabetically before decoding!
Pseudo Code:
let json = {"asd": "qwe", "foo": "bar"};
let str = json.encodeAsJson();
assert str === '{"asd": "qwe", "foo": "bar"}';
let privateKey = "this-is-a-secret-key"
let encrypted = hmacShaEncrypt(privateKey, str)
let signature = encrypted.encodeAsBase64()
assert signature === 'UAQuAderRxKW8nMPhyU8oVhS6U8PgG8d/I03lcbNAG4='
Events
Below is the list of the supported events. We continue
LISTING_SYNC_CHECK
Indicates that any of the three main listing statuses (Claim, Flow, Sync) changed. It includes information about the lifecycle of the listing and the Google status of the listing.
{
"signature": "X",
"event": {
"claimStatusChanged": false,
"googleStatusChanged": false,
"directoryType": "ABCLOCAL",
"flowStatusChanged": true,
"fromListingClaimStatus": "CLAIMED_BY_US",
"fromListingFlowStatus": "ALL_INFORMATION_SUBMITTED",
"fromListingSyncStatus": "NOT_IN_SYNC",
"id": 213581003,
"listing": 332874,
"location": 34838,
"syncStatusChanged": true,
"time": "2016-05-03T10:42:06.000+02:00",
"toListingClaimStatus": "CLAIMED_BY_US",
"toListingFlowStatus": "NO_ACTION_NEEDED",
"toListingSyncStatus": "IN_SYNC",
"type": "LISTING_SYNC_CHECK"
}
}
Field |
Type |
Description |
directoryType | string | the directory this listing belongs to |
claimStatusChanged | boolean | indicating whether the listing's claim status has changed |
googleStatusChanged |
boolean | indicating whether the listing's Google connection status has changed |
flowStatusChanged | boolean | indicating whether the listing's flow status changed |
syncStatusChanged | boolean | indicating whether the listing's sync status changed |
fromListingClaimStatus | ListingClaimStatus | the previous ClaimStatus |
fromListingFlowStatus | FlowStatus | the previous FlowStatus |
fromListingSyncStatus | SyncStatus | the previous SyncStatus |
toListingClaimStatus | ListingClaimStatus | the new ClaimStatus |
toListingFlowStatus | FlowStatus | the new FlowStatus |
toListingSyncStatus | SyncStatus | the new SyncStatus |
LISTING_STATUS_CHANGE
Indicates that the status of a listing was changed manually. This happens rarely and often is the result of a manual check by our Operations or Engineering teams.
{
"signature": "X",
"event": {
"claimStatusChanged": false,
"directoryType": "ABCLOCAL",
"flowStatusChanged": true,
"fromListingClaimStatus": "CLAIMED_BY_US",
"fromListingFlowStatus": "NO_ACTION_NEEDED",
"fromListingSyncStatus": "NOT_IN_SYNC",
"id": 213581003,
"listing": 332874,
"location": 34838,
"syncStatusChanged": false,
"time": "2016-05-03T10:42:06.000+02:00",
"toListingClaimStatus": "CLAIMED_BY_US",
"toListingFlowStatus": "SUBMISSION_NEEDED",
"toListingSyncStatus": "NOT_IN_SYNC",
"type": "LISTING_STATUS_CHANGE",
"user": "user@example.com"
}
}
Field | Type | Description |
directoryType |
string |
the directory this listing belongs to |
claimStatusChanged |
boolean |
indicating whether the claim status changed |
flowStatusChanged |
boolean |
indicating whether the flow status changed |
syncStatusChanged |
boolean |
indicating whether the sync status changed |
fromListingClaimStatus |
the previous ClaimStatus |
|
fromListingFlowStatus |
FlowStatus |
the previous FlowStatus |
fromListingSyncStatus |
the previous SyncStatus |
|
toListingClaimStatus |
the new ClaimStatus |
|
toListingFlowStatus |
FlowStatus |
the new FlowStatus |
toListingSyncStatus |
the new SyncStatus |
|
user |
string |
the user that changed the status |
LISTING_LINK_CHANGE
The platform listing is now pointing to a different directory listing. This can happen either manually or automatically, by detecting a better listing on the directory side than the one previously linked.
{
"event": {
"business": 1234,
"comment": "Listing link changed",
"fromListingId": "456",
"fromListingUrl": "http://old-listing.url/456",
"id": 5549734563,
"listing": 2345,
"location": 3456,
"time": "2019-11-18T14:12:36.000+01:00",
"toListingId": "789",
"toListingUrl": "http://new-listing.url/789",
"type": "LISTING_LINK_CHANGE"
},
"signature": "X"
}
Field |
Type |
Description |
fromListingUrl | string | the old listing url |
fromListingId | string | the old external id of the listing |
toListingUrl | string | the new listing url |
toListingId | string | the new external id of the listing |
LISTING_DATAPOINT_CHECK
Indicates that while doing a check for listing datapoints (i.e. customer feedback such as reviews, photos, etc.), we found new ones.
{
"event": {
"business": 1420951,
"directoryType": "JUDYS_BOOK"
"id": 213580990,
"listing": 332874,
"location": 34838,
"newCheckinsFound": 1,
"newCommentsFound": 1,
"newConversationsFound": 1,
"newDatapointsFound": true,
"newPhotosFound": 1,
"newQuestionsFound": 1,
"newReviewsFound": 1,
"newDataPointIds": [
250976288,
250976289
],
"time": "2016-05-03T10:19:14.000+02:00",
"type": "LISTING_DATAPOINT_CHECK"
},
"signature": "X"
}
Field |
Type |
Description |
directoryType | string | the directory this listing belongs to |
newPhotosFound |
integer |
the number of new photos found |
newReviewsFound |
integer |
the number of new reviews found |
newCheckinsFound |
integer |
the number of new checkins found |
newConversationsFound |
integer |
the number of new conversations found |
newCommentsFound |
integer |
the number of new comments found |
newQuestionsFound |
integer |
the number of new questions found |
newDatapointsFound | boolean | indicates if any new data points have been fond |
newDataPointIds | array | contains the ids of the newly found data points |
updatedDataPointIds | array | contains the ids of any existing and modified data points (e.g. customer review) |
LISTING_DATAPOINT_INVALID
Indicates that a listing's datapoint has been deleted or invalidated on the directory, so we invalidate it on our side. You can delete or invalidate them on your side too. It's unlikely that a datapoint will be reinstated by the directory.
{
"event": {
"business": 1107630,
"deletedDataPointIds": [],
"directoryType": "YELP_API",
"id": "99",
"invalidDataPointIds": [
434424555
],
"listing": 119934719,
"location": 4154762,
"time": "2023-12-20T19:00:34.508+01:00",
"type": "LISTING_DATAPOINT_INVALID"
},
"signature": "YIfeSTln/p2JaPTY3WhVSsFRvy3NgtRhCFzGI/Fc+60="
}
Field |
Type |
Description |
deletedDataPointIds | Array | The ids of the invalidated data point replies (e.g. owner reply to a customer review) |
invalidDataPointIds | Array | The ids of the invalidated data points (e.g. customer review) |
DIRECTORY_BUSINESS_PAGE_DATA_POINT_CHECK
Indicates that a new brand data point has been found, e.g. review on a Facebook brand page
{
"event": {
"business": 244397,
"directoryBusinessPage": 1220,
"directoryType": "FACEBOOK",
"id": 4,
"newDataPointIds": [
289,
299
],
"newDatapointsFound": true,
"time": "2023-12-21T12:03:31.358+01:00",
"type": "DIRECTORY_BUSINESS_PAGE_DATA_POINT_CHECK",
"updatedDataPointIds": [
79,
253
]
},
"signature": "9kTmfuFg9T5LDD59ZodiyOFtoLSItG737ZRL2fBD7O4="
}
Field |
Type |
Description |
directoryBusinessPage | Integer | The id of the business page associated with the brand data point |
newDataPointIds | Array | The ids of the newly found brand data points |
updatedDataPointIds | Array | contains the ids of any existing and modified data points (e.g. customer review) |
DIRECTORY_BUSINESS_PAGE_DATA_POINT_INVALID
Indicates that a brand's datapoint has been deleted or invalidated on the directory, so we invalidate it on our side. You can delete or invalidate them on your side too. It's unlikely that a datapoint will be reinstated by the directory.
{
"event": {
"business": 909288,
"deletedDataPointIds": [],
"directoryBusinessPage": 173,
"directoryType": "FACEBOOK",
"id": 7,
"invalidDataPointIds": [
4737279
],
"time": "2024-01-02T17:17:49.664+01:00",
"type": "DIRECTORY_BUSINESS_PAGE_DATA_POINT_INVALID"
},
"signature": "/GHkwuBIxYadsaWPq1V8vztXVuSlf1txDSxZuBAH1UQ="
}
Field |
Type |
Description |
directoryBusinessPage | Integer | The id of the business page associated with the brand data point |
deletedDataPointIds | Array | The ids of the invalidated data point replies (e.g. owner reply to a customer review) |
invalidDataPointIds | Array | The ids of the invalidated data points (e.g. customer review) |
LISTING_UPDATE
Indicates that we tried to submit the listing to the directory.
{
"event": {
"business": 7141,
"directoryType": "BING",
"id": 17518447719,
"listing": 7198166,
"location": 450978,
"messages": [
"Listing was updated successfully!"
],
"time": "2021-10-27T16:21:14.000+02:00",
"type": "LISTING_UPDATE",
"updateResult": "SUCCESS",
"updateStatus": null
},
"signature": "X"
}
Field |
Type |
Description |
directoryType | string | The directory's listing type which we tried to submit |
updateResult |
string |
|
updateStatus | string |
null if updateResult = SUCCESS. Else can be one of:
|
LOCATION_CREATED
Indicates that a new location has been created in your account.
{
"event": {
"comment": "A new Location has been created",
"id": 2926113683,
"location": 636605,
"time": "2018-11-05T17:35:07.000+01:00",
"type": "LOCATION_CREATED",
"source": "API"
},
"signature": "X"
}
Field |
Type |
Description |
source |
string |
one among [API, CHECKOUT, CSV_UPLOAD, DEMO_JOB, LOCATION_DATA_DOWNLOAD] |
LOCATION_STATUS_CHANGED
Indicates that the status of a location changed.
{
"event": {
"comment": "Checked and activated by a human being.",
"from": "ACTIVE",
"id": 213580999,
"location": 34838,
"time": "2016-05-03T10:34:43.000+02:00",
"to": "CANCELLED",
"type": "LOCATION_STATUS_CHANGED",
"user": "user@example.com"
},
"signature": "X"
}
Field |
Type |
Description |
from | LocationStatus | the previous LocationStatus |
to | LocationStatus | the new LocationStatus |
user | string | the user who changed the status (if it was a manual change) |
LOCATION_PROFILE_CHANGED
Indicates that a user changed data of a location.
{
"event": {
"comment": "Location profile has been updated",
"id": 2926113683,
"location": 636605,
"time": "2018-11-05T17:35:07.000+01:00",
"type": "LOCATION_PROFILE_CHANGED",
"user": "user@example.com"
},
"signature": "X"
}
Field |
Type |
Description |
user | string | the user that changed the data |
BUSINESS_PRODUCT_PLAN_CHANGED
Indicates that a user and API update or our system has changed the ProductPlan of a Business and its assigned Locations
{
"event": {
"business": 1,
"comment": "Business product plan has been changed",
"id": 5136210330,
"salesPartnerIdentifier": "identifier",
"newProductPlanId": 2,
"newProductPlanName": "My Product Plan 2",
"newProductPlanPrice": 20,
"oldProductPlanId": 1,
"oldProductPlanName": "My Product Plan 1",
"oldProductPlanPrice": 10,
"time": "2019-10-09T15:10:01.000+02:00",
"type": "BUSINESS_PRODUCT_PLAN_CHANGED",
"changedBy": "user@example.com"
},
"signature": "XYZ"
}
Field |
Type |
Description |
newProductPlanId | Long | the id of newly assigned ProductPlan |
newProductPlanName | String | the name of the newly assigned ProductPlan |
newProductPlanPrice | Integer | the price (in Cent) of newly assigned ProductPlan |
oldProductPlanId | Long | the id of the previously assigned ProductPlan |
oldProductPlanName | String | the name of the previously assigned ProductPlan |
oldProductPlanPrice | Integer | the price (in Cent) of the previously assigned ProductPlan |
changedBy | String | Either one of the following, indicating who triggered the change: 1. user email 2. “PRIVATE_TOKEN” 3. “SYSTEM” |
BUSINESS_CREATED
Indicates that a new Business has been created in the partner account
{
"event": {
"business": 631498,
"changedBy": "PRIVATE_TOKEN",
"comment": "New business has been created",
"id": 5385813249,
"salesPartnerIdentifier": "identifier",
"time": "2019-11-07T16:30:19.000+01:00",
"type": "BUSINESS_CREATED"
},
"signature": "X”
}
Field |
Type |
Description |
changedBy | String | Either one of the following, indicating who triggered change: 1. user email 2. “PRIVATE_TOKEN” 3. “SYSTEM” |