Skip to main content

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:

ParameterTypeDefaultDescription
citystringβ€”Filter by city slug (e.g. mumbai)
categorystringβ€”Filter by category slug
statusstringβ€”open, in_progress, or resolved
prioritystringβ€”low, medium, or high
sortstringcreatedAt_desccreatedAt_desc, createdAt_asc, upvotes_desc
limitnumber20Max items per page (1–100)
lastKeystringβ€”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 characters
  • description: required, 20–2000 characters
  • city: required, must be a valid city slug
  • category: required, must be a valid category slug
  • priority: required, one of low, medium, high
  • location: optional object with lat, 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