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 successfully400- Invalid request body404- Project not found500- Server error
Example Request:
javascriptfetch('/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 numbertype(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:
typescriptconst 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 added400- Invalid request401- Unauthorized404- Project or feedback not found
Example:
typescriptawait 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 UUIDlabelId(string, required) - Label UUID
Response:
json{ "success": true }
Status Codes:
200- Label deleted401- Unauthorized404- 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 rangeendDate(ISO string, optional) - End of date rangeprojectIds(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:
typescriptconst 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:
typescriptconst 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:
typescriptconst 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:
typescriptawait 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 Found500- 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