CitizenAI provides a comprehensive REST API that allows developers to integrate citizen engagement capabilities into their applications and services.
The CitizenAI API is designed with the following principles:
!!! info “Design Principles” - RESTful: Following REST architectural principles - JSON-first: All data exchange in JSON format - Versioned: API versioning for backward compatibility - Consistent: Uniform response patterns and error handling - Documented: Comprehensive documentation and examples
All API endpoints are relative to the base URL:
https://your-domain.com/api/v1
For development environments:
http://localhost:5000/api/v1
CitizenAI uses session-based authentication for web applications and API key authentication for programmatic access.
For web applications, authentication is handled through login sessions:
# Login endpoint
POST /api/v1/auth/login
{
"username": "admin",
"password": "password"
}
# Response
{
"success": true,
"user": {
"id": "admin",
"role": "administrator"
},
"session_id": "abc123..."
}
For programmatic access, include your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
All POST and PUT requests should include:
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY
{
"data": {
// Request payload
},
"metadata": {
"timestamp": "2025-01-01T00:00:00Z",
"request_id": "req_12345"
}
}
All API responses follow this format:
{
"success": true,
"data": {
// Response payload
},
"metadata": {
"timestamp": "2025-01-01T00:00:00Z",
"request_id": "req_12345",
"version": "v1"
},
"pagination": {
"page": 1,
"per_page": 20,
"total": 100,
"pages": 5
}
}
{
"success": false,
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid request parameters",
"details": {
"field": "email",
"message": "Invalid email format"
}
},
"metadata": {
"timestamp": "2025-01-01T00:00:00Z",
"request_id": "req_12345"
}
}
| Status Code | Meaning | Description |
|---|---|---|
200 |
OK | Request successful |
201 |
Created | Resource created successfully |
400 |
Bad Request | Invalid request parameters |
401 |
Unauthorized | Authentication required |
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 Code | Description |
|---|---|
AUTHENTICATION_REQUIRED |
API key or session required |
INVALID_API_KEY |
API key is invalid or expired |
VALIDATION_ERROR |
Request validation failed |
RESOURCE_NOT_FOUND |
Requested resource does not exist |
RATE_LIMIT_EXCEEDED |
Too many requests |
INTERNAL_ERROR |
Server-side error |
API requests are rate-limited to ensure fair usage:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1609459200
Default Limits:
| Endpoint | Description |
|---|---|
/auth/* |
Authentication and session management |
/chat/* |
AI chat interactions |
/analytics/* |
Analytics and reporting |
/concerns/* |
Concern management |
/users/* |
User management |
POST /api/v1/chat/message
GET /api/v1/chat/history
POST /api/v1/chat/session
GET /api/v1/analytics/dashboard
GET /api/v1/analytics/metrics
GET /api/v1/analytics/export
POST /api/v1/analytics/query
GET /api/v1/concerns
POST /api/v1/concerns
GET /api/v1/concerns/{id}
PUT /api/v1/concerns/{id}
DELETE /api/v1/concerns/{id}
import requests
# Send a chat message
response = requests.post(
'http://localhost:5000/api/v1/chat/message',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'message': 'What services are available for new residents?',
'session_id': 'session_123'
}
)
# Response
{
"success": true,
"data": {
"response": "New residents can access the following services...",
"confidence": 0.95,
"intent": "services_inquiry",
"session_id": "session_123"
}
}
# Get dashboard metrics
response = requests.get(
'http://localhost:5000/api/v1/analytics/dashboard',
headers={'Authorization': 'Bearer YOUR_API_KEY'},
params={
'date_range': '7d',
'metrics': 'conversations,sentiment,concerns'
}
)
# Response
{
"success": true,
"data": {
"conversations": {
"total": 1250,
"trend": "+15%"
},
"sentiment": {
"positive": 78,
"neutral": 15,
"negative": 7
},
"concerns": {
"total": 45,
"resolved": 38,
"pending": 7
}
}
}
# Create a new concern
response = requests.post(
'http://localhost:5000/api/v1/concerns',
headers={
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
},
json={
'title': 'Broken street light',
'description': 'Street light on Main St is not working',
'category': 'infrastructure',
'priority': 'medium',
'location': '123 Main Street'
}
)
# Response
{
"success": true,
"data": {
"id": "concern_12345",
"title": "Broken street light",
"status": "submitted",
"created_at": "2025-01-01T10:00:00Z",
"tracking_number": "TRK-2025-001"
}
}
CitizenAI supports webhooks for real-time notifications:
| Event | Description |
|---|---|
concern.created |
New concern submitted |
concern.updated |
Concern status changed |
chat.escalated |
Chat escalated to human agent |
analytics.threshold |
Metric threshold exceeded |
# Configure webhook endpoint
POST /api/v1/webhooks
{
"url": "https://your-app.com/webhooks/citizenai",
"events": ["concern.created", "concern.updated"],
"secret": "webhook_secret_key"
}
{
"event": "concern.created",
"data": {
"concern_id": "concern_12345",
"title": "Broken street light",
"status": "submitted"
},
"timestamp": "2025-01-01T10:00:00Z",
"signature": "sha256=..."
}
from citizenai import CitizenAI
# Initialize client
client = CitizenAI(api_key='YOUR_API_KEY')
# Send chat message
response = client.chat.send_message(
message="What are your office hours?",
session_id="session_123"
)
# Get analytics
metrics = client.analytics.get_dashboard_metrics(
date_range='7d'
)
# Create concern
concern = client.concerns.create(
title="Pothole on Oak Street",
category="infrastructure"
)
import { CitizenAI } from '@citizenai/sdk';
const client = new CitizenAI({
apiKey: 'YOUR_API_KEY',
baseUrl: 'http://localhost:5000/api/v1'
});
// Send chat message
const response = await client.chat.sendMessage({
message: 'How do I apply for a permit?',
sessionId: 'session_123'
});
// Get analytics
const metrics = await client.analytics.getDashboardMetrics({
dateRange: '7d'
});
# Test authentication
curl -X POST http://localhost:5000/api/v1/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "admin", "password": "password"}'
# Send chat message
curl -X POST http://localhost:5000/api/v1/chat/message \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "Hello", "session_id": "test_session"}'
base_url: http://localhost:5000/api/v1api_key: Your API keyCitizenAI uses URL-based versioning:
v1/api/v{version}/| Version | Release Date | Status | Notes |
|---|---|---|---|
v1 |
2025-01-01 | Current | Initial API release |
!!! tip “API Best Practices” - Pagination: Use pagination for large datasets - Caching: Implement client-side caching for static data - Compression: Enable gzip compression - Connection pooling: Reuse HTTP connections - Batch requests: Group multiple requests when possible
import requests
from requests.exceptions import RequestException
try:
response = requests.post(
'http://localhost:5000/api/v1/chat/message',
json={'message': 'Hello'},
timeout=30
)
response.raise_for_status()
data = response.json()
if not data.get('success'):
# Handle API error
error = data.get('error', {})
print(f"API Error: {error.get('message')}")
except RequestException as e:
# Handle network/HTTP errors
print(f"Request failed: {e}")
For specific endpoint documentation, see the detailed Endpoints reference.