Technical Appendix
Under the hood. API endpoints, authentication, data models, and technical reference for CTOs and developers.
API Overview
All Campaign Brain services expose RESTful APIs with consistent patterns:
Base URL: https://[service].nominate.ai/api/v1
Authentication: Bearer token (JWT)
Content-Type: application/json
Common Endpoints
| Method | Endpoint | Description |
|---|---|---|
GET | /health | Service health check |
GET | /me | Current user info |
GET | /[resource] | List resources |
GET | /[resource]/[id] | Get single resource |
POST | /[resource] | Create resource |
PUT | /[resource]/[id] | Update resource |
DELETE | /[resource]/[id] | Delete resource |
Authentication
Campaign Brain uses JWT-based authentication with refresh tokens.
Token Flow
- Login:
POST /auth/loginwith credentials - Receive: Access token (15 min) + Refresh token (7 days)
- Use: Include
Authorization: Bearer [access_token]in requests - Refresh:
POST /auth/refreshwith refresh token when expired
Scopes
| Scope | Access Level |
|---|---|
read:voters | View voter records |
write:voters | Modify voter records |
read:campaigns | View campaign data |
admin:campaigns | Manage campaigns |
read:analytics | View dashboards and reports |
Data Models
Voter Record
{
"id": "uuid",
"voter_file_id": "state-assigned-id",
"first_name": "string",
"last_name": "string",
"address": {
"street": "string",
"city": "string",
"state": "string",
"zip": "string"
},
"demographics": {
"age": "number",
"gender": "string",
"party": "string"
},
"scores": {
"turnout": "number (0-100)",
"support": "number (0-100)",
"persuadable": "number (0-100)"
},
"contact_history": ["ContactEvent"],
"tags": ["string"],
"created_at": "timestamp",
"updated_at": "timestamp"
}
Contact Event
{
"id": "uuid",
"voter_id": "uuid",
"type": "door|phone|sms|email|mail",
"outcome": "contact|not_home|refused|wrong_number|moved",
"notes": "string",
"survey_responses": {},
"created_by": "uuid",
"created_at": "timestamp"
}
Workflow Definition
{
"id": "uuid",
"name": "string",
"status": "draft|active|paused|archived",
"trigger": {
"type": "segment|event|schedule",
"config": {}
},
"nodes": ["WorkflowNode"],
"created_at": "timestamp",
"updated_at": "timestamp"
}
Service Ports
Development and internal routing reference:
| Service | Port | Subdomain |
|---|---|---|
| cbpublic | 3000 | nominate.ai |
| cbtenant | 3001 | tenant.nominate.ai |
| cbapp | 3002 | {tenant}.nominate.ai |
| cbworkflow | 3003 | workflow.nominate.ai |
| cbsurveys | 3004 | surveys.nominate.ai |
| cbdistricts | 3005 | districts.nominate.ai |
| cbmodels | 3006 | models.nominate.ai |
| cbradio | 3007 | ruralamfm.nominate.ai |
| cbfiles | 3008 | files.nominate.ai |
| cbinfra | 3009 | — (internal) |
| cbai | 3010 | — (internal) |
| cbetl | 3011 | — (internal) |
GitHub Repositories
Nominate-AI/cbpublic — Public website
Nominate-AI/cbtenant — Tenant manager
Nominate-AI/cbapp — Campaign app
Nominate-AI/cbworkflow — Workflow engine
Nominate-AI/cbsurveys — Survey platform
Nominate-AI/cbdistricts — District service
Nominate-AI/cbmodels — Analytics
Nominate-AI/cbradio — Radio advertising
Nominate-AI/cbfiles — File storage
Nominate-AI/cbinfra — Infrastructure
Nominate-AI/cbai — AI service
Nominate-AI/cbetl — ETL pipeline
Rate Limits
| Tier | Requests/min | Burst |
|---|---|---|
| Free | 60 | 10 |
| Standard | 300 | 50 |
| Pro | 1000 | 100 |
| Enterprise | Custom | Custom |
Rate limit headers included in all responses:
X-RateLimit-Limit: Max requests per windowX-RateLimit-Remaining: Requests left in windowX-RateLimit-Reset: Unix timestamp when window resets
Error Codes
| Code | Description |
|---|---|
400 | Bad request - validation error |
401 | Unauthorized - invalid or expired token |
403 | Forbidden - insufficient permissions |
404 | Not found - resource doesn't exist |
409 | Conflict - duplicate or state conflict |
429 | Too many requests - rate limited |
500 | Internal error - please retry |
Error response format:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Human-readable description",
"details": {}
}
}
Full API Documentation
Complete API documentation with interactive examples is available at docs.nominate.ai.