Any interaction with the UserVoice Admin API requires a trusted API client. You can create one by followingthis guide.
The UserVoice Admin API provides a fast and easy way of working with your feedback data that allows you to build client applications and custom integrations.
The UserVoice Admin API will respond to all requests with a JSON data structure. Bodies for POST and PUT requests can be passed as either JSON or url-form-encoded data.
JSON Request: $ curl https://SUBDOMAIN.uservoice.com/api/v2/admin/suggestions \ -X "POST" \ -H "Authorization: Bearer 096e8ae9c6a3c039" \ -H "Content-type: application/json" \ -d "{ 'title': 'Test Suggestion', 'links': { 'forum': 1 } }"Form Request:$ curl https://SUBDOMAIN.uservoice.com/api/v2/admin/suggestions \ -X "POST" \ -H "Authorization: Bearer 096e8ae9c6a3c039" \ -H "Content-type: application/x-www-form-urlencoded" \ -d "title=Test+Suggestion&links.forum=1"Response:
{ "links": { "suggestions.category": { "type": "categories" }, "suggestions.created_by": { "type": "users" }, "suggestions.forum": { "type": "forums" }, "suggestions.labels": { "type": "labels" }, "suggestions.last_status_update": { "type": "status_updates" }, "suggestions.parent_suggestion": { "type": "suggestions" }, "suggestions.status": { "type": "statuses" }, "suggestions.ticket": { "type": "tickets" } }, "suggestions": [ { "id": 184102, "title": "Test Suggestion", "body": "", "body_mime_type": "", "portal_url": "http://SUBDOMAIN.uservoice.com/forums/1/suggestions/184102", "admin_url": "https://SUBDOMAIN.uservoice.com/admin/v3/suggestions/184102", "created_at": "2017-02-24T16:27:36Z", "creator_user_agent": null, "creator_referrer": null, "creator_browser": null, "creator_browser_version": null, "creator_os": null, "creator_mobile": false, "state": "approved", "inappropriate_flags_count": 0, "approved_at": null, "updated_at": "2017-02-24T16:27:36Z", "closed_at": null, "comments_count": 0, "notes_count": 0, "requests_count": 0, "votes_count": 0, "supporters_count": 0, "supporting_accounts_count": 0, "supporter_revenue": 0, "supporter_satisfaction_score": 0, "satisfaction_detractor_count": 0, "satisfaction_promoter_count": 0, "satisfaction_neutral_count": 0, "average_engagement": 0, "recent_engagement": 1, "engagement_trend": 0, "first_support_at": null, "links": { "forum": 1, "category": null, "labels": null, "status": null, "parent_suggestion": null, "ticket": null, "last_status_update": null, "created_by": 9182 } } ] }The response JSON object contains a key for each collection you request. The value of each key is an array of objects. Using the “includes” param, you can easily side-load associated records. This allows you to request additional data in a single query and gives you control over the weight of the response. The “links” object in a response provides a list of available associations.
In this example, we’re requesting a list of suggestions and side-loading the associated forums and users:
$ curl https://SUBDOMAIN.uservoice.com/api/v2/admin/suggestions?includes=forums,users \ -H "Authorization: Bearer 096e8ae9c6a3c039"(Simplified) Response:
{ "forums": [ { "id": 2002, "name": "Product Ideas", "open_suggestions_count": 1, "suggestions_count": 1, "is_public": true, "created_at": "2017-01-20T14:24:45Z", "updated_at": "2017-01-20T14:24:45Z", "links": { "updated_by": null } } ], "links": { "forums.updated_by": { "type": "users" }, "suggestions.category": { "type": "categories" }, "suggestions.created_by": { "type": "users" }, "suggestions.forum": { "type": "forums" }, "suggestions.labels": { "type": "labels" }, "suggestions.last_status_update": { "type": "status_updates" }, "suggestions.parent_suggestion": { "type": "suggestions" }, "suggestions.status": { "type": "statuses" }, "suggestions.ticket": { "type": "tickets" }, "users.current_nps_rating": { "type": "nps_ratings" }, "users.external_users": { "type": "external_users" }, "users.previous_nps_rating": { "type": "nps_ratings" }, "users.teams": { "type": "teams" } }, "list_meta": null, "pagination": { "page": 1, "per_page": 20, "total_pages": 1, "total_records": 1 }, "suggestions": [ { "id": 303, "title": "Make the logo bigger", "body": "I love your logo but I can barely see it!", "created_at": "2012-07-19T14:23:16Z", "state": "published", "updated_at": "2017-01-20T14:24:47Z", "comments_count": 1, "links": { "forum": 2002, "category": null, "labels": null, "status": null, "parent_suggestion": null, "ticket": null, "last_status_update": null, "created_by": 1001 } } ], "users": [ { "id": 1001, "name": "Logo Fan", "email_address": "logofan@example.com", "avatar_url": "https://cdn.uservoice.com/pkg/admin/icons/user_80-fc2452956c9d66d679a429bd81acd3f3.png", "created_at": "2017-01-20T14:24:47Z", "updated_at": "2017-01-20T14:24:47Z", } ] }Using the “links” property of the suggestion object, we can map the “forum” and “created_by” ids to the forum our suggestion belongs to and the user that created it.
There are two methods of pagination: cursor-based and page-based. Cursor-based pagination is not available for every sort order on every collection, but it should be preferred whenever it is available because it offers a more reliable ordering of results and more consistent API performance. There is also a Link header provided which will make this decision for you.
In either case the number of records you receive is controlled by theper_page parameter. The defaultper_page is 20 and the maximum is 100. There will be apagination object in the response with metadata about the current page:
"pagination": { "page": 1, "per_page": 100, "total_pages": 3, "total_records": 272 } When you get the first page of results, if cursor-based pagination is supported, there will be acursor value in thepagination part of the response. Pass thiscursor value as a parameter to the same endpoint to retrieve the next page of results along with a newcursor value.
Example:
GET /api/v2/admin/suggestions?sort=-supporters_count{ "suggestions": [ … ], "pagination": { "total_records": 200, "total_pages": 10, "page_size": 20, "page": 1, "cursor": "eyJzb3J0IjoiIiwidmFsIjoyNjMsImxhc3RfaWQiOjIzMTUyMjJ9" }}GET /api/v2/suggestions?cursor=eyJzb3J0IjoiIiwidmFsIjoyNjMsImxhc3RfaWQiOjIzMTUyMjJ9&sort=-supporters_count{ "suggestions": [ … ], "pagination": { "total_records": 200, "total_pages": 10, "page_size": 20, "page": 1, "cursor": "eyJzb3J0IjoiIiwidmFsIjoxNzgsImxhc3RfaWQiOjIwODc3OX0=" }} When using cursor-based pagination thepage value in the response will always be 1. You will know that you are on the last page of results when there is no longer acursor value in the response.
With cursor-based pagination you must always start at the beginning of a list and work your way forward. It is not possible to move backward or to jump to certain offset the way you can with page-based pagination. A cursor token can only be used to request records in the same sort order as the request that provided it. If you want the records in a different order, you must start at the beginning without a cursor parameter.
The cursor represents a fixed point in the ordered set of results. If you change theper_page parameter when using a cursor you will get a different number of results but they will start with the same record.
Cursor-based pagination is ideal for scenarios where you want to pull a long list of records from the API. Its performance should be basically constant from the first page of results to the last, whereas page-based pagination will degrade in performance the deeper you get into the list.
Another benefit of cursors is that your position in the list will not be shifted if objects are created or deleted while you are paging. With page-based pagination those events could result in a record being skipped, or a record being returned twice.
With page-based pagination, the records you get are determined by multiplying thepage number by theper_page parameter. To get the next page of results, you simply increment thepage parameter.
Example:
GET /api/v2/admin/suggestions?sort=-cf_my_field{ "suggestions": [ … ], "pagination": { "total_records": 200, "total_pages": 10, "page_size": 20, "page": 1 }}GET /api/v2/suggestions?sort=-cf_my_field&page=2{ "suggestions": [ … ], "pagination": { "total_records": 200, "total_pages": 10, "page_size": 20, "page": 2 }} If you change the per_page parameter when requesting a page other that 1, you will get completely different results since the offset is computed by (page - 1) *per_page.
Page-based pagination is different from cursor-based pagination. If records are added or removed while retrieving paginated results, items may appear to shift across pages. Paginated results also do not perform as well as cursor-based results. Use cursor-based pagination wherever it is available.
A link header is provided along with every API response when another page of results is available. If you are on the last page of results, there will not be a link header.
Cursor example:
Link: </api/v2/admin/suggestions?cursor=eyJzb3J0IjoiIiwidmFsIjoxNzgsImxhc3RfaWQiOjIwODc3OX0%3D&sort=-supporters_count>; rel=next
Page example:
Link: </api/v2/admin/suggestions?page=2&sort=-cf_my_field>; rel=next
The link header will automatically switch between page-based and cursor-based pagination depending on whether the latter is available for the requested sort order.
API requests have per-minute rate limiting. Each request counts toward your limit. Not all requests are created equal: if a request takes longer than 1 second to compute then another “request” is counted for every whole second after the first. This helps us account for expensive endpoints (like complex searches) that use more resources.
Once you have exceeded your limit for the current minute, the UserVoice Admin API will return a 429 HTTP error response for subsequent requests.
Every request returns the following HTTP headers:
Once rate limited, every request returns the following HTTP header:
The limit depends on your plan. SeeTerms of Service for details.
Take advantage of side-loading, per_page settings and bulk endpoints to consolidate your requests.
The UserVoice Admin API allows you to upload files and link them to suggestions. This is done through a two-step process.
$ curl https://SUBDOMAIN.uservoice.com/api/v2/admin/attachments \ -H "Authorization: Bearer <token>" \ -F "file=@/path/to/file"
{ "attachments": [ { "id": 116876320, "file_name": "test.jpg", "content_type": "image/jpeg", "size_in_bytes": 14919, "updated_at": "2017-02-16T14:06:35Z", "created_at": "2017-02-16T14:06:35Z", "url": "someUrl.com", "thumb_url": "someOtherUrl.com", "token": "1234567890ebcf3635a209ab4ozp1kd9", "links": { "suggestion": null, "note": null } } ], "links": { "attachments.note": { "type": "notes" }, "attachments.suggestion": { "type": "suggestions" } } }$ curl https://SUBDOMAIN.uservoice.com/api/v2/admin/suggestions/ID \ -X "PUT" \ -H "Authorization: Bearer <token>" \ -d attachment_tokens=1234567890ebcf3635a209ab4ozp1kd9,someOtherToken
{ "links": { "suggestions.category": { "type": "categories" }, "suggestions.created_by": { "type": "users" }, "suggestions.forum": { "type": "forums" }, "suggestions.labels": { "type": "labels" }, "suggestions.last_status_update": { "type": "status_updates" }, "suggestions.parent_suggestion": { "type": "suggestions" }, "suggestions.status": { "type": "statuses" }, "suggestions.ticket": { "type": "tickets" } }, "suggestions": [ { "id": 12345, "title": "Make a Getting Started Guide", "body": "A good starting guide would be helpful thanks!", "body_mime_type": "", "portal_url": "http://SUBDOMAIN.uservoice.com/forums/54321/suggestions/12345", "admin_url": "https://SUBDOMAIN.uservoice.com/admin/v3/suggestions/12345", "created_at": "2013-03-08T00:17:42Z", "creator_user_agent": null, "creator_referrer": null, "creator_browser": null, "creator_browser_version": null, "creator_os": null, "creator_mobile": false, "state": "approved", "inappropriate_flags_count": 0, "approved_at": null, "updated_at": "2017-02-16T14:09:34Z", "closed_at": null, "comments_count": 2, "notes_count": 0, "requests_count": 0, "votes_count": 1, "supporters_count": 0, "supporting_accounts_count": 0, "supporter_revenue": 0, "supporter_satisfaction_score": 0, "satisfaction_detractor_count": 0, "satisfaction_promoter_count": 0, "satisfaction_neutral_count": 0, "average_engagement": 0, "recent_engagement": 0, "engagement_trend": 0, "first_support_at": null, "links": { "forum": 54321, "category": null, "labels": null, "status": 567899, "parent_suggestion": null, "ticket": null, "last_status_update": 5321563, "created_by": 32364234 } } ] }File Size: 50 MB (50000000 bytes)
A complete list of endpoints is available in ourAdmin API Reference.
Use our API to tightly integrate your application or website with UserVoice.
Check out the UserVoice Help Center for more documentation.