REST API Documentation
Build custom integrations and automate workflows with FeatureShark's comprehensive REST API. This guide covers authentication, endpoints, and best practices for developers.
API Overview
Base URL
All API requests should be made to:
https://api.featureshark.com/v1
Authentication
FeatureShark uses API keys for authentication. Include your API key in the request headers:
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Rate Limiting
- Free Plan: 100 requests/hour
- Pro Plan: 1,000 requests/hour
- Enterprise Plan: 10,000 requests/hour
- Rate limit headers included in all responses
Response Format
All responses are in JSON format:
{
"success": true,
"data": { /* response data */ },
"meta": {
"page": 1,
"per_page": 25,
"total": 150,
"total_pages": 6
}
}
Authentication
Getting Your API Key
- Navigate to Settings > API Keys in your FeatureShark dashboard
- Click "Generate New API Key"
- Choose permissions for the key:
- Read-only (safe for analytics)
- Read/Write (full access)
- Admin (all operations including settings)
- Copy and securely store the generated key
API Key Management
Security Best Practices
- Never commit API keys to version control
- Use environment variables for key storage
- Rotate keys regularly (recommended: every 90 days)
- Use separate keys for different environments (dev/staging/prod)
- Revoke unused keys immediately
Key Scopes
{
"read": ["requests", "votes", "comments", "users", "analytics"],
"write": ["requests", "votes", "comments", "status_updates"],
"admin": ["settings", "team", "integrations", "billing"]
}
Core Endpoints
Feature Requests
List Feature Requests
GET /requests
Parameters:
page(integer): Page number (default: 1)per_page(integer): Items per page (default: 25, max: 100)category(string): Filter by categorystatus(string): Filter by statussort(string): Sort order (votes,created_at,updated_at)order(string): Sort direction (asc,desc)
Example Request:
curl -X GET "https://api.featureshark.com/v1/requests?category=mobile&status=planned&sort=votes&order=desc" \
-H "Authorization: Bearer YOUR_API_KEY"
Example Response:
{
"success": true,
"data": [
{
"id": "req_123abc",
"title": "Dark Mode for Mobile App",
"description": "Add dark theme option to reduce eye strain",
"category": "mobile",
"status": "planned",
"priority": "high",
"votes": 127,
"comments_count": 23,
"created_at": "2024-03-15T10:30:00Z",
"updated_at": "2024-03-20T14:22:00Z",
"user": {
"id": "user_456def",
"name": "Sarah Johnson",
"email": "sarah@example.com",
"avatar_url": "https://..."
},
"tags": ["ui", "mobile", "accessibility"]
}
],
"meta": {
"page": 1,
"per_page": 25,
"total": 150,
"total_pages": 6
}
}
Get Single Feature Request
GET /requests/{id}
Example Response:
{
"success": true,
"data": {
"id": "req_123abc",
"title": "Dark Mode for Mobile App",
"description": "Add dark theme option to reduce eye strain during night usage...",
"category": "mobile",
"status": "planned",
"priority": "high",
"votes": 127,
"comments_count": 23,
"created_at": "2024-03-15T10:30:00Z",
"updated_at": "2024-03-20T14:22:00Z",
"user": {
"id": "user_456def",
"name": "Sarah Johnson",
"email": "sarah@example.com",
"customer_tier": "enterprise"
},
"assignee": {
"id": "team_789ghi",
"name": "Mike Chen",
"role": "developer"
},
"tags": ["ui", "mobile", "accessibility"],
"custom_fields": {
"effort_estimate": "6 weeks",
"business_value": "high",
"technical_complexity": "medium"
}
}
}
Create Feature Request
POST /requests
Request Body:
{
"title": "Bulk User Import",
"description": "Allow importing multiple users via CSV file upload",
"category": "admin",
"priority": "medium",
"tags": ["import", "admin", "csv"],
"custom_fields": {
"business_value": "high",
"effort_estimate": "4 weeks"
}
}
Response:
{
"success": true,
"data": {
"id": "req_789xyz",
"title": "Bulk User Import",
"status": "under_review",
"created_at": "2024-03-22T09:15:00Z",
"url": "https://yourapp.featureshark.com/requests/req_789xyz"
}
}
Update Feature Request
PUT /requests/{id}
Request Body:
{
"status": "in_development",
"assignee_id": "team_789ghi",
"priority": "high",
"custom_fields": {
"sprint": "Sprint 24",
"github_issue": "https://github.com/company/repo/issues/456"
}
}
Votes
Get Votes for Request
GET /requests/{id}/votes
Example Response:
{
"success": true,
"data": [
{
"id": "vote_abc123",
"user": {
"id": "user_456def",
"name": "Sarah Johnson",
"customer_tier": "enterprise"
},
"created_at": "2024-03-20T11:30:00Z"
}
],
"meta": {
"total_votes": 127,
"vote_breakdown": {
"enterprise": 45,
"pro": 32,
"free": 50
}
}
}
Add Vote
POST /requests/{id}/votes
Request Body:
{
"user_id": "user_456def"
}
Remove Vote
DELETE /requests/{id}/votes/{vote_id}
Comments
List Comments
GET /requests/{id}/comments
Example Response:
{
"success": true,
"data": [
{
"id": "comment_123",
"content": "This would be incredibly helpful for our onboarding process!",
"user": {
"id": "user_456def",
"name": "Sarah Johnson",
"avatar_url": "https://..."
},
"created_at": "2024-03-20T15:45:00Z",
"updated_at": "2024-03-20T15:45:00Z",
"is_internal": false
}
]
}
Add Comment
POST /requests/{id}/comments
Request Body:
{
"content": "We're starting development on this feature next sprint!",
"is_internal": false,
"notify_subscribers": true
}
Users
List Users
GET /users
Parameters:
page,per_page(pagination)customer_tier(string): Filter by tieractive(boolean): Filter by active statussort(string): Sort by (created_at,last_active,requests_count)
Get User Details
GET /users/{id}
Example Response:
{
"success": true,
"data": {
"id": "user_456def",
"name": "Sarah Johnson",
"email": "sarah@example.com",
"customer_tier": "enterprise",
"created_at": "2024-01-15T08:00:00Z",
"last_active": "2024-03-22T16:30:00Z",
"stats": {
"requests_submitted": 8,
"votes_cast": 45,
"comments_posted": 23
}
}
}
Analytics Endpoints
Overview Analytics
GET /analytics/overview
Parameters:
start_date(date): Start of date rangeend_date(date): End of date rangegranularity(string):day,week,month
Example Response:
{
"success": true,
"data": {
"summary": {
"total_requests": 247,
"total_votes": 1856,
"total_users": 423,
"active_requests": 189
},
"trends": {
"requests_growth": "+12%",
"user_growth": "+8%",
"engagement_growth": "+15%"
},
"top_categories": [
{"name": "mobile", "count": 67},
{"name": "web", "count": 45},
{"name": "api", "count": 34}
]
}
}
Request Analytics
GET /analytics/requests
Example Response:
{
"success": true,
"data": {
"submission_trends": [
{"date": "2024-03-01", "count": 12},
{"date": "2024-03-02", "count": 8},
{"date": "2024-03-03", "count": 15}
],
"category_distribution": {
"mobile": 67,
"web": 45,
"api": 34,
"integrations": 28
},
"status_breakdown": {
"under_review": 23,
"planned": 45,
"in_development": 12,
"testing": 6,
"released": 89,
"declined": 18
}
}
}
Voting Analytics
GET /analytics/votes
Example Response:
{
"success": true,
"data": {
"vote_trends": [
{"date": "2024-03-01", "votes": 45},
{"date": "2024-03-02", "votes": 38},
{"date": "2024-03-03", "votes": 52}
],
"top_voted_requests": [
{
"id": "req_123abc",
"title": "Dark Mode for Mobile App",
"votes": 127
}
],
"voter_segments": {
"enterprise": 245,
"pro": 156,
"free": 89
}
}
}
Webhooks
Setting Up Webhooks
Create Webhook
POST /webhooks
Request Body:
{
"url": "https://your-app.com/webhooks/featureshark",
"events": ["request.created", "request.status_changed", "vote.added"],
"secret": "your_webhook_secret",
"active": true
}
Available Events
request.created- New feature request submittedrequest.updated- Feature request modifiedrequest.status_changed- Status transitionrequest.deleted- Feature request removedvote.added- New vote castvote.removed- Vote withdrawncomment.created- New comment postedcomment.updated- Comment modifieduser.registered- New user signed up
Webhook Payload Examples
Request Created
{
"event": "request.created",
"timestamp": "2024-03-22T10:30:00Z",
"data": {
"request": {
"id": "req_123abc",
"title": "Advanced Search Filters",
"description": "Need ability to filter by multiple criteria",
"category": "search",
"status": "under_review",
"user": {
"id": "user_456def",
"name": "Sarah Johnson",
"customer_tier": "enterprise"
}
}
}
}
Status Changed
{
"event": "request.status_changed",
"timestamp": "2024-03-22T14:15:00Z",
"data": {
"request": {
"id": "req_123abc",
"title": "Advanced Search Filters",
"previous_status": "planned",
"new_status": "in_development",
"assignee": {
"id": "team_789ghi",
"name": "Mike Chen"
}
}
}
}
Webhook Security
Signature Verification
Verify webhook authenticity using HMAC-SHA256:
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, secret) {
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
Example Usage:
app.post('/webhooks/featureshark', (req, res) => {
const signature = req.headers['x-featureshark-signature'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, process.env.WEBHOOK_SECRET)) {
return res.status(401).send('Unauthorized');
}
// Process webhook...
res.status(200).send('OK');
});
SDKs and Libraries
Official SDKs
JavaScript/Node.js
npm install featureshark-js
Basic Usage:
const FeatureShark = require('featureshark-js');
const client = new FeatureShark({
apiKey: process.env.FEATURESHARK_API_KEY,
baseURL: 'https://api.featureshark.com/v1'
});
// Get all requests
const requests = await client.requests.list({
status: 'planned',
sort: 'votes',
order: 'desc'
});
// Create new request
const newRequest = await client.requests.create({
title: 'Mobile Push Notifications',
description: 'Send push notifications for important updates',
category: 'mobile'
});
// Add vote
await client.votes.add('req_123abc', 'user_456def');
Python
pip install featureshark-python
Basic Usage:
from featureshark import FeatureSharkClient
client = FeatureSharkClient(
api_key=os.environ['FEATURESHARK_API_KEY']
)
# Get requests with filtering
requests = client.requests.list(
category='mobile',
status='planned',
sort='votes'
)
# Create new request
new_request = client.requests.create({
'title': 'Offline Mode',
'description': 'Work without internet connection',
'category': 'mobile',
'priority': 'high'
})
# Update request status
client.requests.update('req_123abc', {
'status': 'in_development',
'assignee_id': 'team_456def'
})
PHP
composer require featureshark/php-sdk
Basic Usage:
use FeatureShark\Client;
$client = new Client([
'api_key' => $_ENV['FEATURESHARK_API_KEY']
]);
// List requests
$requests = $client->requests()->list([
'category' => 'api',
'status' => 'planned'
]);
// Create request
$request = $client->requests()->create([
'title' => 'GraphQL API Support',
'description' => 'Add GraphQL endpoint for better data fetching',
'category' => 'api'
]);
Community SDKs
Ruby
# Gemfile
gem 'featureshark-ruby'
# Usage
client = FeatureShark::Client.new(
api_key: ENV['FEATURESHARK_API_KEY']
)
requests = client.requests.list(
category: 'web',
sort: 'votes'
)
Go
import "github.com/featureshark/go-sdk"
client := featureshark.NewClient(os.Getenv("FEATURESHARK_API_KEY"))
requests, err := client.Requests.List(&featureshark.RequestListOptions{
Category: "mobile",
Status: "planned",
})
Error Handling
HTTP Status Codes
200 OK- Success201 Created- Resource created successfully400 Bad Request- Invalid request parameters401 Unauthorized- Invalid or missing API key403 Forbidden- Insufficient permissions404 Not Found- Resource not found422 Unprocessable Entity- Validation errors429 Too Many Requests- Rate limit exceeded500 Internal Server Error- Server error
Error Response Format
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "The request contains invalid data",
"details": [
{
"field": "title",
"message": "Title is required and must be at least 10 characters"
},
{
"field": "category",
"message": "Category must be one of: mobile, web, api, integration"
}
]
}
}
Common Error Codes
INVALID_API_KEY- API key is invalid or expiredINSUFFICIENT_PERMISSIONS- API key lacks required permissionsRATE_LIMIT_EXCEEDED- Too many requests in time periodVALIDATION_ERROR- Request data validation failedRESOURCE_NOT_FOUND- Requested resource doesn't existDUPLICATE_RESOURCE- Attempting to create duplicate resource
Best Practices
Performance Optimization
Pagination
Always use pagination for large datasets:
// Good: Use pagination
const getAllRequests = async () => {
let allRequests = [];
let page = 1;
while (true) {
const response = await client.requests.list({
page: page,
per_page: 100
});
allRequests.push(...response.data);
if (page >= response.meta.total_pages) break;
page++;
}
return allRequests;
};
Filtering and Sorting
Use API-side filtering instead of client-side:
// Good: Filter on server
const highPriorityRequests = await client.requests.list({
priority: 'high',
status: 'planned',
sort: 'votes',
order: 'desc'
});
// Avoid: Fetching all and filtering client-side
const allRequests = await client.requests.list();
const filtered = allRequests.data.filter(r => r.priority === 'high');
Security
API Key Management
// Good: Use environment variables
const client = new FeatureShark({
apiKey: process.env.FEATURESHARK_API_KEY
});
// Avoid: Hardcoding keys
const client = new FeatureShark({
apiKey: 'fs_1234567890abcdef' // Never do this!
});
Input Validation
Always validate input before sending to API:
const createRequest = (requestData) => {
// Validate required fields
if (!requestData.title || requestData.title.length < 10) {
throw new Error('Title must be at least 10 characters');
}
if (!['mobile', 'web', 'api'].includes(requestData.category)) {
throw new Error('Invalid category');
}
return client.requests.create(requestData);
};
Rate Limiting
Implement Backoff Strategy
const makeRequestWithRetry = async (fn, maxRetries = 3) => {
for (let i = 0; i < maxRetries; i++) {
try {
return await fn();
} catch (error) {
if (error.status === 429 && i < maxRetries - 1) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
continue;
}
throw error;
}
}
};
Example Integrations
Slack Bot Integration
const { App } = require('@slack/bolt');
const FeatureShark = require('featureshark-js');
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
signingSecret: process.env.SLACK_SIGNING_SECRET
});
const featureShark = new FeatureShark({
apiKey: process.env.FEATURESHARK_API_KEY
});
// Command to create feature request
app.command('/feature-request', async ({ command, ack, respond }) => {
await ack();
const [title, description] = command.text.split(' | ');
try {
const request = await featureShark.requests.create({
title: title.trim(),
description: description?.trim() || 'Created via Slack',
category: 'general'
});
await respond(`✅ Feature request created: ${request.url}`);
} catch (error) {
await respond(`❌ Error: ${error.message}`);
}
});
// Command to check top requests
app.command('/top-requests', async ({ ack, respond }) => {
await ack();
const requests = await featureShark.requests.list({
sort: 'votes',
order: 'desc',
per_page: 5
});
const list = requests.data.map((req, i) =>
`${i + 1}. ${req.title} (${req.votes} votes)`
).join('\n');
await respond(`🔥 Top Feature Requests:\n${list}`);
});
GitHub Action Integration
name: Sync Feature Requests
on:
schedule:
- cron: '0 9 * * 1' # Every Monday at 9 AM
jobs:
sync-requests:
runs-on: ubuntu-latest
steps:
- name: Get Planned Features
id: requests
run: |
curl -s -H "Authorization: Bearer ${{ secrets.FEATURESHARK_API_KEY }}" \
"https://api.featureshark.com/v1/requests?status=planned" \
| jq '.data[] | {id, title, votes}' > planned_features.json
- name: Create GitHub Issues
run: |
while IFS= read -r feature; do
title=$(echo "$feature" | jq -r '.title')
votes=$(echo "$feature" | jq -r '.votes')
gh issue create \
--title "Feature: $title" \
--body "User votes: $votes\nFeatureShark ID: $(echo "$feature" | jq -r '.id')" \
--label "feature-request"
done < planned_features.json
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Custom Dashboard Integration
// Express.js dashboard endpoint
app.get('/dashboard/data', async (req, res) => {
try {
const [overview, requests, topUsers] = await Promise.all([
featureShark.analytics.overview(),
featureShark.requests.list({
status: 'in_development',
sort: 'votes',
order: 'desc'
}),
featureShark.users.list({
sort: 'requests_count',
order: 'desc',
per_page: 10
})
]);
res.json({
metrics: overview.data.summary,
activeFeatures: requests.data,
topContributors: topUsers.data
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
What's Next?
Complete your integration knowledge:
- Slack Integration Setup - Team communication
- GitHub Issue Sync - Development workflow
- Managing Feature Requests - Request lifecycle
Getting Help
- 🛠️ API Support: api-help@featureshark.com
- 📚 Interactive API Explorer: Try our API browser
- 💬 Developer Community: Join our Slack channel
- 🎥 Video Tutorials: API integration examples
API Version: v1
Rate Limits: Apply to all plans
Last Updated: September 2025
Was this helpful?
Still need help? Contact our support team