Introduction
Welcome to Version 2 of the Promoter API! You can use our API to access endpoints, which can get information on various contacts, feedback, and campaign metrics in our database.
We have a robust API to provide tons of options for all needs, but the most popular use is triggering to send surveys, found in the Contacts section below.
Enhancements for V2
- Valid JSON now accepted. Before, data passed in needed to be 'strings'. Data can now be formatted to be valid JSON.
Contacts
- "Survey a contact" has survey-level attributes. Your attributes on the contact object can be continually updated, but now you can capture attributes at the time the survey was sent. Also a new endpoint with enhanced performance.
Feedback
"Get feedback" call will return survey-level attributes. If you passed in survey-level attributes in your survey call, you can retrieve that info in the "get feedback" call on the survey object.
Follow-up actions available. Reply and Forward using the API.
Tagging feedback is now available.
Update the status of a feedback to be either OPEN or CLOSED.
Common Replies
- Now you can get/create/delete common replies to be used within the app.
Webhooks
We've added more webhooks!
- feedback.status_changed
- feedback.tags_added_or_changed
- tag.merged
- tag.removed
API Rate Limiting
Based on your plan, you will be allowed an API request rate of X requests per minute. Your limit can be found by visiting the "API" section of your account.
When the requests per minute exceed the allotment, you will receive the following:
A response status code of: 429 (Too many Requests)
A response body of:
{ "detail": "Request was throttled. Expected available in 42.0 seconds."}
A response header to inform of the client when in time you can retry the call:
- Retry-After: 42
- Retry-After header value will be in <delay-seconds>
- For more information see:
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
Authentication
Promoter uses API keys to allow access to the API. You can register for a Promoter Account and access the API key in your main account settings under 'API'. Promoter expects for the API key to be included in all API requests to the server in a header that looks like the following: Authorization: Token YOUR_API_KEY
. The key should be prefixed by the string literal "Token", with whitespace separating the two strings.
With curl, you can pass the correct header with each request curl "https://app.promoter.io/api"
.
Error Codes
403
Forbidden
The resource requested is hidden for administrators only
404
Not Found
The specified resource could not be found
405
Method Not Allowed
You tried to access a resource with an invalid method
406
Not Acceptable
You requested a format that isn’t json
410
Gone
The resource requested has been removed from our servers
429
Too Many Requests
You’re requesting too much! Slow down!
500
Internal Server Error
We had a problem with our server. Try again later.
503
Service Unavailable
We’re temporarily offline for maintenance. Please try again later.
Data Policy
letters “a - z” / ”A - Z
“plan” , “ID”, “Company”
numbers 0 - 9
009, 49, 1234
underscores ( _ )
“region_024”, “company_name"
spaces ( )
“Plan Name”, “company name”
Characters NOT accepted:
dollar signs ($)
“MRR$”, “$plan”
periods (.)
“MRR.1”, “plan.name”
percentage signs (%)
“%revenue”, “% of data”
Ampersand (&)
“Address & Phone”
Dates as Attribute Values
Date/times must be in the “yyyy-mm-ddThh:mm:ss” format (“ISO 8601” format) to be recognized as dates.
✔ Correct:
2017-09-23
2017-09-23T15:25
2017-09-23 15:25
2017-09-23T15:25:45
2017-09-23T15:25:45Z
X Incorrect:
9-23-17
9/23/17
23/09/17
2017-9-23
09-23-2017
Survey a contact
The minimum requirements for surveying a contact are the contact’s email and the campaign id to survey them from.
- Before sending surveys via the API, a campaign must be first created manually in the app.
- After creating the campaign, visit the API settings in the "Integrations" section.
- Click to '+ Add Integration' and choose the campaign.
- Choose the delivery settings for surveys being triggered with the API for that campaign.
When surveying contacts, there are not limits to how many attributes can be passed in. These can be useful when filtering NPS analytics on the campaign's dashboard.
- Depending on your Survey Throttle setting, your contact may not be eligible for a survey when making the survey call. (Survey Throttle setting can be found in your account settings.) You'll receive the message "Contact is not eligible for survey."
24 Hour Survey Throttle
Our system has a 24 hour throttle built in so any contact cannot be surveyed more than once in a 24 hour period. Due to this, you may need to use aliases of your email while testing.
Ex: joe+1@mac.com, joe+2@mac.com...
If you would like this temporarily disabled while testing, please write in to support@promoter.io.
Update a Contact - python example not using V2
I believe should be: https://app.promoter.io/api/v2/contacts/
This action only updates a contact's info and does not send them a survey.
You can add as many attributes as you’d like along with your contact. These can be useful when analyzing NPS data on the campaign dashboard and using the 'Filter Segments' option.
The parameter required when updating a contact is the contact’s email. A contact's email is stored as a primary key, and this is how our system identifies which contact to update. We keep a master record of every contact even if they were removed from a contact list. Running this call will update their master record and be reflected all throughout the app (all lists, campaigns, etc.).
When attribute data is passed in the "/survey/" call, this will also update your contact's data while triggering a survey.
Unsubscribe a contact
Unsubscribing a contact will prevent the contact from being surveyed in the future and cancel all pending surveys that were scheduled.
Get contact
This endpoint retrieves contacts in your organization.
Query by:
The contact's email to find a particular contact.
/v2/contacts/?email=kate@mac.com
A contact_list_id to grab all contacts within a list.
/v2/contacts/?contact_list__id=2099
When this call is made, it will return 100 results at a time and will require paginating through the results. To paginate, you would add a page parameter to the url. Ex: <api_call>/api/v2/contacts/?page=3
Get contact by id
Retrieves a specific contact in your organization by providing the contact id.
Remove a contact
This endpoint removes a contact for an organization. This is a delete action and all of the contact’s data and history will be removed from the organization.
Get feedback
Since there may be feedback in different campaigns, feedback can be queried by campaign_id, show only open feedback, filter by score type, along with a few more options as query parameters.
Ex: /api/v2/feedback/?score=10
When this call is made, it will return 100 results at a time and will require paginating through the results. To paginate, you would add a page parameter to the url. Ex: <api_call>/api/v2/feedback/?page=3
Feedback can be queried by specific time periods using date queries in the URL. All dates are using UTC time. Due to this, there may be a slightly different number of feedbacks than what's displayed on the campaign's dashboard since the dashboard respects user timezone settings. Date formats accepted are yyyy-mm-dd and mm/dd/yyyy.
Date Examples
All feedback before a specific date: /api/v2/feedback/?posted_date_before=2016-10-23
All feedback after a specific date: /api/v2/feedback/?posted_date_after=2016-10-31
Feedback for a specific time period: /api/v2/feedback/?posted_date_after=2016-10-03&posted_date_before=2016-10-23
Get feedback by id
Retrieves a specific feedback in your organization by providing the feedback id.
Close feedback
Using this API call will allow you to update the status of a feedback. You have the options to update the feedback to 'OPEN' or 'CLOSED.
Reply to feedback
This endpoint will allow you to follow-up with your contacts and reply to their feedback.
You'll need to provide the feedback_id to which you're replying to, who's email the reply is coming from, and the message you want to send. The 'from_user' email must be an email that belongs to a member of the organization.
You also have to option to cc or bcc other addresses in your reply. There's no limit to how many emails that can be included, but they'll need to be in a list.
Forward feedback
This endpoint will allow you to forward a feedback.
You'll need to provide the feedback_id of the feedback you're forwarding, who's email the forward is coming from, and the message you want to send. The 'from_user' email must be an email that belongs to a member of the organization. Feedback can only be forwarded to one recipient at a time.
Why can't I forward?
A feedback can only be forwarded when it's not in a 'complete' status. You cannot forward a feedback when:
- A reply has been sent.
- The feedback has been marked as 'complete'.
Tag feedback
This endpoint will allow you to add a tag to your feedback.
The category options are:
DETRACTOR - negative sentiment (red)
PASSIVE - neutral sentiment (yellow)
PROMOTER - postive sentiment (green)
Since this is a 'POST' action, each call will add on a tag to your feedback. Multiple tags with the same name cannot exist on a feedback.
e.g. Tag price => detractor and price => passive could not exist on the same feedback. It must be one or the other.
Create feedback
When creating a feedback for a campaign, the minimum requirements are a score, email address, and campaign ID.
Passing in the 'status' of the feedback is optional and will be OPEN by default. Options are OPEN or CLOSED.
Tags can be applied during the creation of a feedback, but are not required. A 'name' of each tag needs to be given, and then a 'category' sentiment. Category options are PROMOTER, PASSIVE, DETRACTOR.
If a contact record does not exist for the email, then the endpoint will create a contact.
If contact attributes exist for the contact, then current contact attributes will still be saved with the creation of the feedback.
The endpoint will create a survey object to reference for the feedback. This is why you'll see survey object data returned in the response body.
Get metrics
This endpoint will retrieve all current campaign metrics within your organization.
When retrieving metrics, the default is to show metrics for the past 30 days.
You can grab metrics for a specific time period by date queries in the URL. All dates are using UTC time. Due to this, you may see slightly different metrics than what's displayed on your dashboard since your dashboard respects your timezone settings. Date formats accepted are yyyy-mm-dd and mm/dd/yyyy.
Date Examples
All metrics before a specific date: /api/v2/metrics/?posted_date_1=2016-10-23
All metrics after a specific date: /api/v2/metrics/?posted_date_0=2016-10-31
Metrics for a specific time period: /api/v2/metrics/?posted_date_0=2016-10-03&posted_date_1=2016-10-23
Score analysis values:
(-100) - (-1): "AT RISK"
0 - 49: "GOOD"
50 - 74: "EXCELLENT"
75 - 100: "WORLD CLASS"
Get metrics by id
This endpoint will retrieve metrics for the campaign_id specified.
When retrieving metrics, the default is to show metrics for the past 30 days.
You can grab metrics for a specific time period by date queries in the URL. All dates are using UTC time. Due to this, you may see slightly different metrics than what's displayed on your dashboard since your dashboard respects your timezone settings. Date formats accepted are yyyy-mm-dd and mm/dd/yyyy.
Date Examples
All metrics before a specific date: /api/v2/metrics/?posted_date_1=2016-10-23
All metrics after a specific date: /api/v2/metrics/?posted_date_0=2016-10-31
Metrics for a specific time period: /api/v2/metrics/?posted_date_0=2016-10-03&posted_date_1=2016-10-23
Score analysis values:
(-100) - (-1): "AT RISK"
0 - 49: "GOOD"
50 - 74: "EXCELLENT"
75 - 100: "WORLD CLASS"
Get common replies
View all of the Common Replies that exist for your organization.
id - The id of the common reply
title - The title of the common reply
reply - The message within the common reply
category.id - The id of the category that the common reply is -> within
category.name - The name of the category that the common reply is within.
Create a common reply
Create a common reply within your organization. You'll be able to give your reply a message and a title, and have it stored within a category of your choosing.
If you choose a category name that does not exist, a new category will be created and store the common reply within it.
Webhooks
Webhooks can be set up in the Integrations section of your Promoter account.
Events we currently support
feedback.added_or_changed
- Feedback was created or changed.feedback.tags_added_or_changed
- Feedback had a Tag added/updated/removedfeedback.status_changed
- Status of a feedback changedfeedback.removed
- Feedback was removedmetric.score_changed
- NPS score changed for a given campaigncontact.unsubscribed
- Contact unsubscribedtag.merged
- Tag was merged in a campaign via Tag Managementtag.removed
- Tag was deleted from a campaign via Tag Managementtag.renamed
- Tag was renamed from a campaign via Tag Management
Response Bodies
The requestbin.com URLs below can be generated from RequestBin.com. You can use the service to create a free HTTPS endpoint. Any HTTP requests sent to that endpoint will be recorded with the associated payload and headers so you can observe the data sent from our webhooks before configuring your application to accept it.
feedback.added_or_changed
This webhook will have a 15 minute delay. This is so a contact has plenty of time to leave a comment before we push data to another source.
{
"hook": {
"id": 84,
"event": "feedback.added_or_changed",
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com"
},
"data": {
"status": "OPEN",
"comment": "Loved my new tablet!",
"score_changed": "2017-12-29T18:31:30.433Z",
"score": 10,
"campaign": {
"status": "ACTIVE",
"launch_date": "2017-08-15T21:16:02Z",
"id": 2070,
"name": "Pear Computers"
},
"tags": [],
"score_type": "promoter",
"comment_created": "2017-12-29T18:31:30.429Z",
"contact": {
"attributes": {},
"first_name": "Kate",
"last_name": "Mac",
"id": 1192319,
"email": "kate@mac.com"
},
"survey": {
"id": 1234,
"attributes": {},
"sent_date": "2017-12-29T18:31:00.230Z"
},
"followup_href": "http://app.promoter.io/org/327/campaign/2070/responses/all/response/12445/",
"created": "2017-12-29T18:31:20.951Z",
"comment_modified": "2017-12-29T18:31:30.429Z",
"status_changed": "2017-12-29T18:31:20.951Z",
"id": 12445
}
}
{
"hook": {
"id": 122,
"event": "feedback.tags_added_or_changed",
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com"
},
"data": {
"status": "OPEN",
"comment": "Support took too long to answer my questions.",
"score_changed": "2017-12-24T04:54:05.867Z",
"score": 8,
"campaign": {
"status": "ACTIVE",
"launch_date": "2017-08-15T21:16:02Z",
"id": 2070,
"name": "My NPS Campaign"
},
"tags": [
{
"category": "PASSIVE",
"name": "support"
}
],
"score_type": "passive",
"comment_created": "2017-12-13T21:15:23Z",
"contact": {
"attributes": {
"signed_up": "2014-12-12",
"Plan": "gold"
},
"first_name": "Kate",
"last_name": "Mac",
"id": 1174538,
"email": "kate@mac.com"
},
"survey": {
"attributes": {
"OrderId": 123456789
},
"sent_date": "2017-12-13T21:15:00.241Z"
},
"followup_href": "http://app.promoter.io/org/327/campaign/2070/responses/all/response/12445/",
"created": "2017-12-13T21:15:19.498Z",
"comment_modified": "2017-12-24T04:54:05.857Z",
"status_changed": "2017-12-13T21:15:19.498Z",
"id": 12445
}
}
{
"hook": {
"id": 122,
"event": "feedback.status_changed",
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com"
},
"data": {
"status": "CLOSED",
"comment": "Support took too long to answer my questions.",
"score_changed": "2017-12-24T04:54:05.867Z",
"score": 8,
"campaign": {
"status": "ACTIVE",
"launch_date": "2017-08-15T21:16:02Z",
"id": 2070,
"name": "My NPS Campaign"
},
"tags": [
{
"category": "PASSIVE",
"name": "support"
}
],
"score_type": "passive",
"comment_created": "2017-12-13T21:15:23Z",
"contact": {
"attributes": {
"signed_up": "2014-12-12",
"Plan": "gold"
},
"first_name": "Kate",
"last_name": "Mac",
"id": 1174538,
"email": "kate@mac.com"
},
"survey": {
"attributes": {
"OrderId": 123456789
},
"sent_date": "2017-12-13T21:15:00.241Z"
},
"followup_href": "http://app.promoter.io/org/327/campaign/2070/responses/all/response/12445/",
"created": "2017-12-13T21:15:19.498Z",
"comment_modified": "2017-12-24T04:54:05.857Z",
"status_changed": "2017-12-13T21:15:19.498Z",
"id": 12445
}
}
{
"hook": {
"id": 83,
"event": "feedback.removed",
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com"
},
"data": {
"status": "OPEN",
"comment": "I loved my tablet and the price!",
"score_changed": "2018-01-03T20:35:13.991Z",
"score": 10,
"campaign": {
"status": "ACTIVE",
"launch_date": "2017-08-15T21:16:02Z",
"id": 2070,
"name": "Pear Computers"
},
"tags": [
{
"category": "PROMOTER",
"name": "price"
}
],
"score_type": "promoter",
"comment_created": "2018-01-03T20:34:43.687Z",
"contact": {
"attributes": {},
"first_name": "Kate",
"last_name": "Mac",
"id": 1174602,
"email": "kate@mac.com"
},
"survey": {
"attributes": {},
"sent_date": "2017-11-10T20:56:00.252Z"
},
"followup_href": "https://app.promoter.io/org/327/campaign/2070/responses/all/response/12445/",
"created": "2017-11-10T20:57:16Z",
"comment_modified": "2018-01-03T20:34:43.687Z",
"status_changed": "2017-12-06T17:41:22Z",
"id": 12445
}
}
{
"hook": {
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com",
"id": 251,
"event": "metric.score_changed"
},
"data": {
"potential_new_revenue": 73,
"average_revenue_per_customer": 123,
"formatted_long_term_revenue_at_risk": 73,
"campaign_name": "Pear Computers",
"followups_outstanding": 5,
"promoter_percentage": 34,
"formatted_potential_new_revenue": 73,
"followup_rate_percentage": 17,
"followup_count": 1,
"formatted_surveys_scheduled_count": "0",
"surveys_scheduled_count": 0,
"formatted_surveys_delivered_count": "0",
"score_analysis": GOOD,
"detractor_percentage": 33,
"formatted_average_revenue_per_customer": 0,
"long_term_revenue_at_risk": 0,
"passive_percentage": 0,
"surveys_delivered_count": 10,
"nps": 1,
"feedback_count": 6,
"formatted_short_term_revenue_at_risk": 123,
"feedback_rate_percentage": 60,
"short_term_revenue_at_risk": 123
}
}
{
"hook": {
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com",
"id": 249,
"event": "contact.unsubscribed"
},
"data": {
"attributes": {
"plan": "bronze"
},
"first_name": "Kate",
"last_name": "Bell",
"id": 12345,
"email": "kate@mac.com"
}
}
{
"hook": {
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com",
"id": 249,
"event": "tag.merged"
},
"data": {
“campaign” : {
“id”: 1234,
“Name”: “My NPS Campaign”
}
"before":"too expensive",
"after":"price"
}
}
}
{
"hook": {
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com",
"id": 249,
"event": "tag.removed"
},
"data": {
“campaign”: {
“id” : 124,
“Name”: “My NPS Campaign”,
}
"name" : “price”
}
}
{
"hook": {
"target": "https://[YOUR ENDPOINT ID].x.requestbin.com",
"id": 249,
"event": "tag.renamed"
},
"data": {
“campaign” : {
“id”: 1234,
“Name”: “My NPS Campaign”
}
"before":"too expensive",
"after":"price"
}
}
}