REST API Documentation

Last updated: September 20255-10 min read

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

  1. Navigate to Settings > API Keys in your FeatureShark dashboard
  2. Click "Generate New API Key"
  3. Choose permissions for the key:
    • Read-only (safe for analytics)
    • Read/Write (full access)
    • Admin (all operations including settings)
  4. 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 category
  • status (string): Filter by status
  • sort (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 tier
  • active (boolean): Filter by active status
  • sort (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 range
  • end_date (date): End of date range
  • granularity (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 submitted
  • request.updated - Feature request modified
  • request.status_changed - Status transition
  • request.deleted - Feature request removed
  • vote.added - New vote cast
  • vote.removed - Vote withdrawn
  • comment.created - New comment posted
  • comment.updated - Comment modified
  • user.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 - Success
  • 201 Created - Resource created successfully
  • 400 Bad Request - Invalid request parameters
  • 401 Unauthorized - Invalid or missing API key
  • 403 Forbidden - Insufficient permissions
  • 404 Not Found - Resource not found
  • 422 Unprocessable Entity - Validation errors
  • 429 Too Many Requests - Rate limit exceeded
  • 500 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 expired
  • INSUFFICIENT_PERMISSIONS - API key lacks required permissions
  • RATE_LIMIT_EXCEEDED - Too many requests in time period
  • VALIDATION_ERROR - Request data validation failed
  • RESOURCE_NOT_FOUND - Requested resource doesn't exist
  • DUPLICATE_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:

  1. Slack Integration Setup - Team communication
  2. GitHub Issue Sync - Development workflow
  3. Managing Feature Requests - Request lifecycle

Getting Help


API Version: v1
Rate Limits: Apply to all plans
Last Updated: September 2025

Was this helpful?

Still need help? Contact our support team

Api Docs - FeatureShark Help Center | FeatureShark