API Overview
We use a RESTful API, in which all endpoints are prefixed with the API version and a unique hash identifying your shop.
https://api.reveal.omniconvert.com/v1/s/shpdmo/...
The v1
part indicated you’re using the version 1 of the API, while the shpdmo
represents the unique alphanumeric hash identifying your shop. However, the login endpoint does not contain this unique, as it is performed outside a shop context.
API Authentication
Our API is secured using JWT token, so before anything else, will first need to authenticate:
POST https://api.reveal.omniconvert.com/v1/login
Body: {
"username": "your_username",
"key": "your_api_key"
}
Headers: Content-type: application/json
As a response, you will receive something similar to:
{
"code": 200,
"expire": "2019-06-03T08:05:34Z",
"token": "K0FIc0FJZy1hb...K0FDSS10eXBlK0FDSTorQUNJQUlnQjlBQWcg"
}
The token expires after 1 hour and it must be used in all subsequent API requests.
Customer RFM
Availability – When to download
The files are available only after the Onboarding process is finished, and are refreshed daily, when the daily sequence runs. If you want to know exactly when the daily sequence is done, check the Webhooks section below.
Endpoints
To fetch the complete list of customers with their associated RFM information you can call:
GET
https://api.reveal.omniconvert.com/v1/s/shpdmo/rfm/download/customers.csv
GET
https://api.reveal.omniconvert.com/v1/s/shpdmo/rfm/download/customers.json
To fetch only the list of customers with recently switched RFM Groups or changed RFM Scores, also with their associated RFM information you can call:
GET
https://api.reveal.omniconvert.com/v1/s/shpdmo/rfm/download/customers_diff.csv
GET
https://api.reveal.omniconvert.com/v1/s/shpdmo/rfm/download/customers_diff.json
What “recently” means can be configure from Settings > Export Settings > RFM Customer Difference Window
Headers: Authorization:"Bearer token here"
The shpdmo part of the URL must be substituted with your shop unique ID, which you can find in the URL of your Reveal Dashboard.
Customer data structure – export
Attribute | Type | Limits | Description |
---|---|---|---|
customer_eid | string | 255 | The identifier you have defined for the customer |
string | 255 | The email of the customer | |
first_name | string | 255 | First name |
last_name | string | 255 | Last name |
rfm_score | string | 3 | 3-digit score |
rfm_group_id | int | – | Ther RFM Group id |
rfm_group_name | string | 255 | The name of the RFM Group |
{
"customers_rfm": [
{
"custom_attributes": null,
"customer_eid": "1894",
"customer_email": "[email protected]",
"customer_first_name": "Horace",
"customer_last_name": "Kshlerin",
"profit": null,
"revenue": null,
"rfm_group_id": null,
"rfm_group_name": null,
"rfm_score": ""
},
{
"custom_attributes": null,
"customer_eid": "1916",
"customer_email": "[email protected]",
"customer_first_name": "Coy",
"customer_last_name": "Cummerata",
"profit": 27.8219,
"revenue": 140.08,
"rfm_group_id": 8,
"rfm_group_name": "Breakup",
"rfm_score": "112"
},
}
Customers with rfm_group_id
and rfm_group_name
containing null
values must also be taken into account. They placed an order, but then canceled it, so they are not eligible for RFM segmentation. The RFM score and segmentation must be updated (removed) for them.
NPS Invitations
Availability – When to download
The files are available only after the daily sequence. The files are regenerated daily, after the daily sequence runs and contains only the new NPSInvitations that should be sent.
If no new NPSInvitation was generated since the last daily sequence, the file will contain only the CSV header or a JSON with an empty nps_invitations_rfm
object . If you want to know exactly when the daily sequence is done, check the Webhooks section below.
Endpoints
To fetch the list of daily generated NPS Invitations (the list can also be empty if no NPS Invitation could be generated for that day, say no new orders or no one passed the capping rules):
GET
https://api.reveal.omniconvert.com/v1/s/shpdmo/nps/download/daily_invitations.csvGET
https://api.reveal.omniconvert.com/v1/s/shpdmo/nps/download/daily_invitations.json
Headers: Authorization: "Bearer token here"
The shpdmo part of the URL must be substituted with your shop unique ID, which you can find in the URL of your Reveal Dashboard.
NPS Invitation data structure – export
Column | Type | Description |
---|---|---|
nps_unique | string | The identifier of the NPS Invitation; just in case you want to mark it as sent through API |
customer_eid | string | The identifier you have defined for the customer |
customer_email | string | The customer email |
customer_first_name | string | |
customer_last_name | string | |
status | string | The status of the invitation: to_send, not_sent, sent, consumed, expired. |
send_until | string | DateTime in format YYYY-MM-dd HH:mm:ss |
nps_open_link | string | The link that should be added in email as a “tracking” pixel, in order to measure the email open rate |
nps_link | string | The link of the NPS |
nps_link_0 | string | The link of the NPS with prefilled overall score = 0; to use in email in grid |
nps_link_1 | string | The link of the NPS with prefilled overall score = 1; to use in email in grid |
… | … | … |
nps_link_10 | string | The link of the NPS with prefilled overall score = 10; to use in email in grid |
nps_list_id | int | If is part of an NPS Invitations List |
rfm_score | string | The RFM score of the customer for the moment when he placed the order (that order included) |
rfm_group_id | int | The RFM Group Id of the customer for the moment when he placed the order (that order included) |
rfm_group_name | string | The RFM Group name of the customer for the moment when he placed the order (that order included) |
If no daily NPS Invitations were generated, the csv will contain solely the header row, while the json will contain an empty array within the “nps_invitations_rfm” field ({"nps_invitations_rfm":[]}
).
NPS Invitation API methods
Create & Delete
These methods are not immplemented, since they have no real use. The NPS Invitation is created automatically and cannot be deleted.
Mark as sent
Method: POST
/nps-invitations/{nps_invitation_unique}/mark-sent
Body: empty
Response: 200
with nps_invitation object, or error status with error message
This will also update the NPS Invitation List to “mark as sent” if this was the last unsent NPS
Invitation in the list, so the data will be consistent.
Show
Method: GET /nps-invitations/{nps_invitation_unique}
Body: empty
Response: 200
with nps_invitation object, or error status with error message
List
Method: GET /nps-invitations?filters&page
Body: empty
Response: 200
with page object, or error status with error message
You can filter the nps_invitations by:
Attribute | Type | Description |
---|---|---|
status | string | One of: to_send, not_sent, sent, consumed, expired. One thing to notice, if you don’t use the “mark as sent” feature, a NPS Invitation can transition from to_send in not_sent then in consumed. |
customer_eid | string | The unique identifier you have defined for the customer |
customer_email | string | Customer email |
order_eid | string | The unique identifier you have defined for the order |
nps_list | int | The id of the NPS Invitation List the invitations were included in. |
rfm_score | string | |
rfm_group | int |
Invitation data structure – API
Attribute | Type | Description |
---|---|---|
id | int | The id of the invitation |
unique | string | The unique generated for this invitation |
link | string | The link of the NPS; you can add to it &q=X for prefilling the overall score with X, where X is between 0-10 |
customer_eid | string | The unique identifier you have defined for the customer |
customer_email | string | Customer email |
customer_first_name | string | |
customer_last_name | string | |
order_eid | string | The unique identifier you have defined for the order, you may need it for your internal tracking |
nps_list | int | |
rfm_score | string | |
rfm_group_id | int | |
send_until | datetime | |
sent_at | ||
consumed_at | ||
status | string | The status of the invitation: to_send, not_sent, sent, consumed, expired. You should email the invitation only when the status is “to_send”, otherwise you risk sending it twice, too late or even after it was consumed. Also you should use the “mark as sent” feature for the invitations you sent, otherwise you will risk seeing again in the “to_send” status and send them twice or more. |
Export
Method: GET /nps/export/invitations.{format}?filter
Body: empty
Response: 200
status, or error status
CSV or JSON file with structure described at the beginning of chapter.
The returned list is composed of all to_send
NPS Invitations (unless otherwise specified in filter).
Note the list_id
field, which tells you if that invitation is part of an NPS Invitation List, which probably you downloaded before and maybe already sent it. We recommend to use one of the 2 variants, individual invites or lists to avoid double sends or skipping some emails.
The export data structure is the one in NPS Invitation data structure – export section above
Bulk Mark as sent
Method: POST /bulk/nps-invitations/mark-sent
Body:
{ "nps_invitations": [ nps_invitation_unique, nps_invitation_unique, ] }
Response: 204
status, or error status with error message
The data structure supports multiple nps_invitations uniques, defined in the array under “nps_invitations” key. For a better tracking it is your responsibility to perform this call for all the NPSInvitations for which the email was sent. You can also use the NPSInvitationList “mark as sent” feature.
NPS Invitation List data structure
Attribute | Type | Description |
---|---|---|
id | int | The id of the invitation list |
status | string | The NPS Invitation List status, one of: to_send, not_sent, sent. Even if the status is to_send or not_sent, there might be some NPS Invitations in it that are sent, because they were “marked as sent” individually, and also some other NPS Invitations that are in fact sent but with status not updated. So it’s a good idea to use the “mark as sent” feature. If the status is sent, it means all the invitations are also “marked as sent”, but it is in your job to actually send them, we just want to help you track the progress. |
send_until | datetime | |
sent_at | datetime | |
nps_invitations | array | Array with nps_invitation objects, but only with unique and status field. |
NPS Invitation List API methods
Create & Delete
These methods have no use. The NPS Invitation List is created automatically and cannot be deleted.
Mark as sent
Method: POST
/nps-invitations-lists/{nps_invitations_list_id}/mark-sent
Body: empty
Response: 200
with nps_invitations_list
object, or error status with error message
This will update all the NPS Invitations in the list to “mark as sent” so the data will be consistent. If the status is already “consumed”, it will return a 409
.
Show
Method: GET /nps-invitations-lists/{nps_invitations_list_id}
Body: empty
Response: 200
with nps_invitations_list
object, or error status with error message
List
Method: GET /nps-invitations-lists?filters&page
Body: empty
Response: 200
with page object, or error status with error message
You can use this instead of daily feed, he will get here all the lists even if they were generated from GUI. Then use the nps_invitations
API method list to get the actual invitations.
You can filter the nps_invitations_lists by:
Attribute | Type | Description |
---|---|---|
status | string | One of: to_send, not_sent, sent, Remember to use the “mark as sent” feature for an accurate response |
Bulk Mark as sent
Method: POST /bulk/nps-invitations-lists/mark-sent
Body:
{ "nps_invitations_lists": [ nps_invitations_list_id, nps_invitations_list_id, ] }
Response: 204
status, or error status with error message
Webhooks
Implementing webhooks allows you to use the most fresh information from Reveal.
If you need to know when the daily sequence is finished, so you can start download the RFM customers or the NPS Invitations, you can subscribe to a webhook and Reveal will call your endpoint to notify that the information was updated.
Endpoints
POST https://api.reveal.omniconvert.com/v1/s/shpdmo/webhooks
Headers: Authorization:"Bearer token here"
Body: {
"url": "http://yourdomain.com/any/path/you/want",
"events": [
"job.notification_sequence_daily.done",
"job.notification_sequence_daily.exited"
],
"secret": “a secret string max length 64",
"description": "I want to know when daily sequence is finished"
}
Security
During the creation process of the webhook, Reveal will call the endpoint on the URL provided.
If Reveal does not receive a 200 OK
and also the expected response content, the webhook creation will fail. This way, Reveal is assured that the webhooks will deliver you the needed information.
Below, details are provided on how you can check the call is actually from Reveal and also how to compose the response.
Reveal sends these headers in the webhook call:
X-Reveal-Signature: t=timestamp,v1=hmac_string X-Reveal-Shop-Unique: shpdmo X-Reveal-Event-Name: job.notification_sequence_daily.done X-Reveal-Test: true
X-Reveal-Shop-Unique
– states the shop fow which the webhook was called; useful when handling multiple shopsX-Reveal-Event-Name
– contains the event which caused the webhook to trigger; useful in case you registered for multiple events on the same webhook;
If the event is job.notification_sequence_daily.done, the daily sequence finished with success, so you can download the RFM customers and the NPSInvitations
If the event is job.notification_sequence_daily.exited, the daily sequence encountered errors, and you should not download the files, because they were not updated, and thus, are not freshX-Reveal-Test
– signals if the call is just a test call, such as the one that is triggered when you create the webhook on Reveal
If the value is true, you still have to return 200 OK
and the expected content, but you shouldn’t do anything on your side, because no actual event happenedX-Reveal-Signature
– the security header;
The Unix timestamp of the request is included within the t parameter; you can check this not to be too old, to prevent replay attacks; we recommend to check the timestamp to be somewhere now() +/- 30 seconds (keep in mind Reveal servers and your server may not have the exact same time, so adjust this interval as you need).
The next parameter is the version of the Webhook API, which can only be v1 for now.
The value of the above parameter is the actual security hash, hmac_string.
Computing the hmac
Concatenate the timestamp from header with the dot character and with the request bodysignedPayload = "timestamp.requestBody"
Compute the SHA256 hmac with the secret you used in the Webhook create requestexpectedHmac = hash_hmac('sha256', signedPayload, secret);
Compare the hmac_string from header with the expected hmachash_equals(hmac_string, expectedHmac)
If the hashes are not equal, don’t trust the request! It’s not originating from Reveal.
If the hashes are equal you know the request is a valid Reveal Webhook request, so you need to compute the result Reveal is expecting to.
Building the response
First, you have to JSON-decode the requestBody; you will find an object with 2 keys
{ "_hook_id": "hook_id_string", "_payload": payloadObject }
Get the current Unix timestamp and create a new JSON object like this:
obj = { "_hook_id": "hook_id_string", "timestamp": currentTimestamp, }
Concatenate the current timestamp with the dot character and with the objsignedPayload = "currentTimestamp.obj"
Compute the SHA256 hmac with the secret you used in the Webhook create requesthmac = hash_hmac('sha256', signedPayload, secret);
Concatenate the current timestamp with the pipe character and with the obtained hmacresponse = "now|hmac"
Return a 200 OK
response with the above response as the content
See more about Reveal Webhooks in this article .
If you need any assistance in implementing the Data Export, we’re more than happy to help. 🙂
Was this post helpful?