Issues
The issues API is the core of CivicPulse. It provides CRUD for civic issues, upvoting, status management, assignment to officials, and aggregated statistics.
GET /api/issuesβ
Retrieve a paginated list of civic issues with optional filters.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
city | string | β | Filter by city slug (e.g. mumbai) |
category | string | β | Filter by category slug |
status | string | β | open, in_progress, or resolved |
priority | string | β | low, medium, or high |
sort | string | createdAt_desc | createdAt_desc, createdAt_asc, upvotes_desc |
limit | number | 20 | Max items per page (1β100) |
lastKey | string | β | Cursor from previous page's nextKey |
Request:
GET /api/issues?city=bangalore&status=open&priority=high&limit=5
Response β 200 OK:
{
"success": true,
"data": {
"count": 5,
"items": [
{
"issueId": "iss_01HN5K...",
"title": "Broken streetlight on MG Road",
"description": "The streetlight near MG Road metro exit has been non-functional for 3 weeks.",
"city": "bangalore",
"category": "infrastructure",
"priority": "high",
"status": "open",
"upvotes": 34,
"mediaCount": 2,
"reportedBy": {
"userId": "usr_01HN...",
"displayName": "Priya S."
},
"location": {
"lat": 12.9754,
"lng": 77.6065,
"address": "MG Road, Bangalore"
},
"createdAt": "2025-01-15T08:00:00.000Z",
"updatedAt": "2025-01-15T08:00:00.000Z"
}
],
"nextKey": "eyJQSyI6Ikl...",
"_links": {
"self": "/api/issues?city=bangalore&status=open&priority=high&limit=5",
"next": "/api/issues?city=bangalore&status=open&priority=high&limit=5&lastKey=eyJQSyI6Ikl..."
}
}
}
POST /api/issuesβ
Create a new civic issue. Authentication required.
Request:
POST /api/issues
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"title": "Open drain causing waterlogging near Andheri station",
"description": "The drain cover on S.V. Road near Andheri West station is missing since Monday. During rain it causes 1β2 feet of waterlogging blocking traffic for hours.",
"city": "mumbai",
"category": "hygiene",
"priority": "high",
"location": {
"lat": 19.1197,
"lng": 72.8464,
"address": "S.V. Road, Andheri West, Mumbai"
}
}
Validation rules:
title: required, 10β200 charactersdescription: required, 20β2000 characterscity: required, must be a valid city slugcategory: required, must be a valid category slugpriority: required, one oflow,medium,highlocation: optional object withlat,lng,address
Response β 201 Created:
{
"success": true,
"data": {
"issueId": "iss_01HP3M...",
"title": "Open drain causing waterlogging near Andheri station",
"status": "open",
"createdAt": "2025-01-15T10:45:00.000Z"
}
}
GET /api/issues/:idβ
Retrieve a single issue by its ID, including full detail.
Request:
GET /api/issues/iss_01HN5K...
Response β 200 OK:
{
"success": true,
"data": {
"issueId": "iss_01HN5K...",
"title": "Broken streetlight on MG Road",
"description": "The streetlight near MG Road metro exit...",
"city": "bangalore",
"category": "infrastructure",
"priority": "high",
"status": "in_progress",
"upvotes": 42,
"hasUpvoted": true,
"assignedTo": {
"userId": "off_01HN...",
"displayName": "BBMP Ward Officer"
},
"media": [
{
"mediaId": "med_01HN...",
"type": "image",
"url": "https://civicpulse-media.s3.ap-south-1.amazonaws.com/issues/iss_01HN5K.../img1.jpg",
"addedAt": "2025-01-15T08:05:00.000Z"
}
],
"location": { "lat": 12.9754, "lng": 77.6065, "address": "MG Road, Bangalore" },
"reportedBy": { "userId": "usr_01HN...", "displayName": "Priya S." },
"messageCount": 7,
"createdAt": "2025-01-15T08:00:00.000Z",
"updatedAt": "2025-01-16T09:30:00.000Z"
}
}
The hasUpvoted field is only populated when the request includes a valid Authorization header.
PATCH /api/issues/:idβ
Update an issue's status, priority, or description. Authentication required. The requesting user must be the issue reporter, an official, or an admin.
Request:
PATCH /api/issues/iss_01HN5K...
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"status": "in_progress",
"priority": "high"
}
Updatable fields: title, description, status, priority
Response β 200 OK:
{
"success": true,
"data": {
"issueId": "iss_01HN5K...",
"status": "in_progress",
"updatedAt": "2025-01-16T09:30:00.000Z"
}
}
POST /api/issues/:id/upvoteβ
Upvote an issue. Each user can upvote an issue once. Upvoting again removes the upvote (toggle). Authentication required.
Request:
POST /api/issues/iss_01HN5K.../upvote
Authorization: Bearer <accessToken>
Response β 200 OK:
{
"success": true,
"data": {
"issueId": "iss_01HN5K...",
"upvotes": 43,
"hasUpvoted": true
}
}
POST /api/issues/:id/assignβ
Assign an issue to a government official. Role required: official or admin.
Request:
POST /api/issues/iss_01HN5K.../assign
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"officialId": "off_01HN...",
"department": "BBMP β Roads & Infrastructure",
"note": "Escalated due to 40+ upvotes and high priority."
}
Response β 200 OK:
{
"success": true,
"data": {
"issueId": "iss_01HN5K...",
"assignedTo": {
"userId": "off_01HN...",
"displayName": "BBMP Ward Officer",
"department": "BBMP β Roads & Infrastructure"
},
"assignedAt": "2025-01-16T10:00:00.000Z",
"assignedBy": "usr_admin_01..."
}
}
An immutable assignment record is written to DynamoDB as part of the audit trail.
POST /api/issues/bulk/statusβ
Update the status of multiple issues at once. Role required: admin.
Request:
POST /api/issues/bulk/status
Authorization: Bearer <accessToken>
Content-Type: application/json
{
"issueIds": ["iss_01HN...", "iss_01HP...", "iss_01HQ..."],
"status": "resolved",
"note": "All three resolved in the Jan 2025 ward maintenance drive."
}
Response β 200 OK:
{
"success": true,
"data": {
"updated": 3,
"failed": 0,
"results": [
{ "issueId": "iss_01HN...", "success": true },
{ "issueId": "iss_01HP...", "success": true },
{ "issueId": "iss_01HQ...", "success": true }
]
}
}
GET /api/issues/statsβ
Aggregated counts grouped by status, priority, city, and category. No authentication required.
Request:
GET /api/issues/stats
Response β 200 OK:
{
"success": true,
"data": {
"total": 1842,
"byStatus": {
"open": 1204,
"in_progress": 388,
"resolved": 250
},
"byPriority": {
"high": 421,
"medium": 893,
"low": 528
},
"byCity": {
"mumbai": 482,
"bangalore": 371,
"delhi": 314
},
"byCategory": {
"road": 523,
"infrastructure": 418,
"hygiene": 289
},
"generatedAt": "2025-01-15T10:30:00.000Z"
}
}
GET /api/issues/by-city/:cityβ
Shorthand for GET /api/issues?city=<city>. Accepts the same query parameters for filtering and pagination.
GET /api/issues/by-city/mumbai?status=open&limit=10
GET /api/issues/by-category/:categoryβ
Shorthand for GET /api/issues?category=<category>.
GET /api/issues/by-category/road?priority=high