API Reference

Complete API documentation for Feedback Pulse

Last updated January 29, 2026


API Reference

Complete reference for all Feedback Pulse API endpoints.

Base URL

https://pulsefeedback.vercel.app/api

Authentication

Most endpoints require authentication via NextAuth.js session. Public endpoints are marked below.


Widget API

Submit Feedback

Submit user feedback to a project.

Endpoint: POST /api/widget/[projectKey]

Authentication: ❌ Public (CORS enabled)

Route Parameters:

  • projectKey (string, required) - Project's unique key

Request Body:

json
{
  "type": "bug" | "feature" | "other",
  "message": "string (required, max 5000 chars)",
  "email": "string (optional)",
  "name": "string (optional)"
}

Response:

json
{
  "success": true
}

Status Codes:

  • 201 - Feedback created successfully
  • 400 - Invalid request body
  • 404 - Project not found
  • 500 - Server error

Example Request:

javascript
fetch('/api/widget/abc123', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    type: 'bug',
    message: 'The login button is not working',
    email: 'user@example.com',
    name: 'John Doe'
  })
});

Behavior:

  • Sanitizes message content (removes HTML)
  • Generates 2-3 labels automatically in background
  • Sets initial sentiment to "neutral"
  • Triggers async label generation (doesn't block response)

CORS Preflight

Handle CORS preflight requests.

Endpoint: OPTIONS /api/widget/[projectKey]

Authentication: ❌ Public

Response Headers:

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: POST, OPTIONS
Access-Control-Allow-Headers: Content-Type

Feedback API

List Feedback

Retrieve feedback for a specific project with filtering and pagination.

Endpoint: GET /api/feedback/[projectId]

Authentication: ✅ Required (Project owner only)

Route Parameters:

  • projectId (string, required) - Project UUID

Query Parameters:

  • page (number, optional, default: 1) - Page number
  • type (string, optional, default: "all") - Filter by type (all, bug, feature, other)
  • search (string, optional) - Search in message or email

Response:

json
{
  "data": [
    {
      "id": "uuid",
      "type": "bug" | "feature" | "other",
      "message": "string",
      "userEmail": "string | null",
      "userName": "string | null",
      "sentiment": "positive" | "neutral" | "negative" | null,
      "resolved": boolean,
      "createdAt": "ISO date string",
      "labels": ["string"]
    }
  ],
  "pagination": {
    "total": number,
    "page": number,
    "totalPages": number
  }
}

Example Request:

typescript
const res = await fetch('/api/feedback/project-uuid-123?page=1&type=bug&search=login');
const { data, pagination } = await res.json();

Add Label

Add a custom label to feedback.

Endpoint: POST /api/feedback/[projectId]/labels

Authentication: ✅ Required (Project owner only)

Route Parameters:

  • projectId (string, required) - Project UUID

Request Body:

json
{
  "feedbackId": "string (required)",
  "label": "string (required, trimmed)"
}

Response:

json
{
  "success": true
}

Status Codes:

  • 201 - Label added
  • 400 - Invalid request
  • 401 - Unauthorized
  • 404 - Project or feedback not found

Example:

typescript
await fetch('/api/feedback/project-uuid/labels', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    feedbackId: 'feedback-uuid',
    label: 'urgent'
  })
});

Remove Label

Remove a label from feedback.

Endpoint: DELETE /api/feedback/[projectId]/labels/[labelId]

Authentication: ✅ Required (Project owner only)

Route Parameters:

  • projectId (string, required) - Project UUID
  • labelId (string, required) - Label UUID

Response:

json
{
  "success": true
}

Status Codes:

  • 200 - Label deleted
  • 401 - Unauthorized
  • 404 - Label not found

Analytics API

Get Analytics Data

Retrieve aggregated analytics across projects.

Endpoint: GET /api/analytics

Authentication: ✅ Required

Query Parameters:

  • startDate (ISO string, optional) - Start of date range
  • endDate (ISO string, optional) - End of date range
  • projectIds (comma-separated UUIDs, optional) - Filter by specific projects

Response:

json
{
  "totalFeedback": number,
  "feedbackByType": {
    "bug": number,
    "feature": number,
    "other": number
  },
  "sentimentDistribution": {
    "positive": number,
    "neutral": number,
    "negative": number
  },
  "resolutionStats": {
    "resolved": number,
    "unresolved": number,
    "rate": number
  },
  "feedbackTrend": [
    {
      "date": "YYYY-MM-DD",
      "count": number
    }
  ],
  "topLabels": [
    {
      "label": "string",
      "count": number
    }
  ]
}

Example:

typescript
const endDate = new Date();
const startDate = new Date();
startDate.setDate(startDate.getDate() - 30);

const params = new URLSearchParams({
  startDate: startDate.toISOString(),
  endDate: endDate.toISOString()
});

const res = await fetch(`/api/analytics?${params}`);
const analytics = await res.json();

AI Summarize

Generate AI-powered insights from analytics data.

Endpoint: POST /api/analytics/summarize

Authentication: ✅ Required

Request Body:

json
{
  "analyticsData": {
    "totalFeedback": number,
    "feedbackByType": { "bug": number, "feature": number, "other": number },
    "sentimentDistribution": { "positive": number, "neutral": number, "negative": number },
    "resolutionStats": { "resolved": number, "unresolved": number, "rate": number },
    "topLabels": [{ "label": string, "count": number }]
  }
}

Response:

json
{
  "summary": "string (markdown formatted)"
}

Example:

typescript
const res = await fetch('/api/analytics/summarize', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ analyticsData: data })
});
const { summary } = await res.json();

AI Model: Uses Llama 3.2 3B Instruct via Hugging Face Inference API


AI API

Analyze Sentiment

Manually trigger sentiment analysis for feedback.

Endpoint: GET /api/sentiment/[feedbackId]

Authentication: ✅ Required (Project owner only)

Route Parameters:

  • feedbackId (string, required) - Feedback UUID

Response:

json
{
  "sentiment": "positive" | "neutral" | "negative"
}

Example:

typescript
const res = await fetch('/api/sentiment/feedback-uuid-123');
const { sentiment } = await res.json();

AI Model: Uses cardiffnlp/twitter-roberta-base-sentiment-latest via Hugging Face

Timeout: 10 seconds

Fallback: Returns "neutral" on timeout or error


Generate Labels (Internal)

Auto-generate labels for feedback using keyword extraction.

Endpoint: POST /api/labels/[feedbackId]

Authentication: ✅ Required (Project owner only)

Note: This endpoint is primarily used internally. Labels are auto-generated via widget API.

Route Parameters:

  • feedbackId (string, required) - Feedback UUID

Response:

json
{
  "labels": ["string"]
}

Label Categories:

  • UI/UX
  • Performance
  • Bug
  • Feature Request
  • Documentation
  • Pricing
  • Integration
  • Security
  • Accessibility
  • Mobile

Max Labels: 2-3 per feedback


Project API

List Projects

Get all projects for the authenticated user.

Endpoint: GET /api/projects

Authentication: ✅ Required

Response:

json
[
  {
    "id": "uuid",
    "name": "string",
    "projectKey": "string",
    "url": "string | null",
    "description": "string | null",
    "createdAt": "ISO date string"
  }
]

Create Project

Create a new project.

Endpoint: POST /api/projects

Authentication: ✅ Required

Request Body:

json
{
  "name": "string (required)",
  "url": "string (optional)",
  "description": "string (optional)"
}

Response:

json
{
  "id": "uuid",
  "name": "string",
  "projectKey": "string (auto-generated)",
  "url": "string | null",
  "description": "string | null",
  "createdAt": "ISO date"
}

Delete Project

Delete a project and all associated feedback.

Endpoint: DELETE /api/projects/[id]

Authentication: ✅ Required (Project owner only)

Route Parameters:

  • id (string, required) - Project UUID

Response:

json
{
  "success": true
}

Warning: This action is irreversible and cascades to all feedback and labels.


Status API

Toggle Resolved Status

Mark feedback as resolved or unresolved.

Endpoint: PATCH /api/resolve/[feedbackId]

Authentication: ✅ Required (Project owner only)

Route Parameters:

  • feedbackId (string, required) - Feedback UUID

Request Body:

json
{
  "resolved": boolean
}

Response:

json
{
  "success": true
}

Example:

typescript
await fetch('/api/resolve/feedback-uuid', {
  method: 'PATCH',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ resolved: true })
});

Error Responses

All endpoints follow a consistent error format:

json
{
  "error": "Error message description"
}

Common Status Codes:

  • 400 - Bad Request (invalid parameters)
  • 401 - Unauthorized (not authenticated)
  • 403 - Forbidden (not project owner)
  • 404 - Not Found
  • 500 - Internal Server Error

Rate Limiting

Currently, there is no rate limiting implemented. This may be added in future versions.

CORS Policy

  • Widget API (/api/widget/*) - Allows all origins (*)
  • All other endpoints - Same-origin only

Data Sanitization

  • All user-submitted text is sanitized to remove HTML tags
  • Maximum message length: 5000 characters
  • Labels are trimmed of whitespace