Updated: November 26, 2025
Purpose: Document all API endpoints in the alumni_lookup application.
The alumni_lookup application provides a set of internal JSON APIs primarily used by JavaScript components for dynamic UI features like autocomplete, filtering, and data loading.
Base URL: /api/
Current Status: These APIs are internal-only and not intended for external consumption.
| Endpoint | Method | Purpose |
|---|---|---|
/api/affinities |
GET | Fetch affinities by category |
/api/alumni |
GET | Search alumni by name |
/api/majors |
GET | Fetch majors by college |
/api/activity_descriptions |
GET | Fetch activity descriptions |
Fetch affinity options filtered by category for dropdown population.
Endpoint: GET /api/affinities
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
category |
string | Yes | Affinity category filter |
Valid Categories:
AthleticsCampus LifeGeographicGreek LifeInstrumental EnsemblesPost GraduationSpiritual LifeVocal EnsemblesExample Request:
GET /api/affinities?category=Athletics
Example Response:
[
{
"affinity_code": "BASEBALL",
"name": "Baseball"
},
{
"affinity_code": "BBALL",
"name": "Basketball"
}
]
Controller: Api::AffinitiesController
class Api::AffinitiesController < ApplicationController
def index
category = params[:category]
affinities = Affinity.where(category: category).order(:name)
render json: affinities.select(:affinity_code, :name)
end
end
Search alumni by name for autocomplete/typeahead functionality.
Endpoint: GET /api/alumni
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Name search query |
Example Request:
GET /api/alumni?name=John
Example Response:
[
{
"buid": "B00123456",
"contact_id": "C-123456789",
"last_name": "Doe",
"display_name": "John Doe",
"recent_degree": {
"major_desc": "Accounting",
"college_name": "Jack C. Massey College of Business",
"degree_code": "BS",
"degree_date": "2020-05-09"
}
}
]
Response Fields:
| Field | Type | Description |
|---|---|---|
buid |
string | Unique alumni identifier |
contact_id |
string | CRM contact ID (format: C-000000000) |
last_name |
string | Alumni last name |
display_name |
string | Full formatted name (via display_name method) |
recent_degree |
object | Most recent degree information |
Error Response (missing parameter):
{
"error": "Name parameter is required"
}
HTTP Status: 400 Bad Request
Controller: Api::AlumniController
class Api::AlumniController < ApplicationController
def index
if params[:name].present?
alumni = Alumni.filter_by_name(params[:name])
.order(:last_name, :first_name)
.limit(10)
render json: alumni.as_json(
only: [:buid, :contact_id, :last_name],
methods: [:display_name],
include: {
recent_degree: { only: [:major_desc, :college_name, :degree_code, :degree_date] }
}
)
else
render json: { error: "Name parameter is required" }, status: :bad_request
end
end
end
Notes:
filter_by_name scope for searchingrecent_degree associationFetch majors filtered by college code for cascading dropdown population.
Endpoint: GET /api/majors
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
college |
string | Yes | College code filter |
Example Request:
GET /api/majors?college=BUS
Example Response:
[
{
"dept": "ACCT",
"dept_desc": "Accounting",
"major_code": "ACCT",
"major_desc": "Accounting",
"active": true
},
{
"dept": "FIN",
"dept_desc": "Finance",
"major_code": "FIN",
"major_desc": "Finance",
"active": true
}
]
Response Fields:
| Field | Type | Description |
|---|---|---|
dept |
string | Department code |
dept_desc |
string | Department description |
major_code |
string | Unique major identifier |
major_desc |
string | Major description |
active |
boolean | Whether major is currently active |
Controller: Api::MajorsController
class Api::MajorsController < ApplicationController
def index
college = params[:college]
majors = Major.where(college_code: college).order(:dept, :major_desc)
render json: majors.select(:dept, :dept_desc, :major_code, :major_desc, :active)
end
end
Fetch distinct activity descriptions for filtering engagement activities.
Endpoint: GET /api/activity_descriptions
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
activity_code |
string | Yes | Activity type code |
start_date |
date | No | Filter start date |
end_date |
date | No | Filter end date |
college |
string | No | College code filter |
year |
integer | No | Fiscal year filter |
Example Request:
GET /api/activity_descriptions?activity_code=event_attended&start_date=2024-01-01&end_date=2024-12-31
Example Response:
[
"Homecoming 2024",
"Alumni Awards Gala",
"Career Fair",
"Reunion Weekend"
]
Response: Array of distinct description strings, sorted alphabetically.
Controller: Api::ActivityDescriptionsController
class Api::ActivityDescriptionsController < ApplicationController
def index
activity_code = params[:activity_code]
start_date = params[:start_date]
end_date = params[:end_date]
college = params[:college]
year = params[:year]
alumni_scope = Alumni.all
alumni_scope = alumni_scope.filter_by_college(college)
alumni_scope = alumni_scope.filter_by_fiscal_year(year)
buids = alumni_scope.pluck(:buid)
descriptions = EngagementActivity
.where(buid: buids)
.where(activity_code: activity_code)
.where(engagement_date: start_date..end_date)
.where.not(description: [nil, ""])
.distinct
.order(:description)
.pluck(:description)
render json: descriptions
end
end
Notes:
None of the API endpoints currently require authentication.
These endpoints are intended for internal JavaScript consumption and are accessed from authenticated pages. The assumption is that the user has already authenticated to access the parent page.
| Risk | Mitigation |
|---|---|
| Data exposure | APIs return limited fields, no sensitive data |
| Abuse potential | Low - data is publicly available alumni info |
| Rate limiting | None currently (consider adding) |
# Recommended pattern for authenticated APIs
class Api::BaseController < ApplicationController
before_action :authenticate_user!
# or for token-based auth:
# before_action :authenticate_api_token!
end
All endpoints return JSON with appropriate HTTP status codes:
| Status | Meaning |
|---|---|
200 OK |
Request successful |
400 Bad Request |
Missing required parameters |
{
"error": "Error message description"
}
| Type | Format | Example |
|---|---|---|
| Date | ISO 8601 | "2024-05-09" |
| Boolean | JSON boolean | true, false |
| ID (buid) | String | "B00123456" |
| Contact ID | String | "C-123456789" |
If these APIs are exposed externally in the future, consider:
/api/v1/alumni
/api/v1/affinities
rack-attack)POST /api/v1/champion_signups # External signup submission
GET /api/v1/champions/:id # Champion profile (authenticated)
PUT /api/v1/champions/:id # Update champion (authenticated)
If a native mobile app is developed in the future, the API should support:
| Approach | Description | Pros/Cons | |———-|————-|———–| | OAuth 2.0 + JWT | Industry standard for mobile | ✅ Secure, refresh tokens, widely supported | | API Keys | Simple token-based | ⚠️ Less secure, no expiration handling | | Device Tokens | Per-device authentication | ✅ Good for push notifications integration |
Recommended: OAuth 2.0 with JWT tokens and refresh token flow:
POST /api/v1/auth/token # Exchange credentials for tokens
POST /api/v1/auth/refresh # Refresh expired access token
DELETE /api/v1/auth/revoke # Revoke tokens (logout)
# Device registration for push notifications
POST /api/v1/devices
DELETE /api/v1/devices/:id
# Offline-friendly data sync
GET /api/v1/sync?since=<timestamp> # Delta updates since last sync
GET /api/v1/champions/:id/offline # Bundled data for offline access
# App metadata
GET /api/v1/app/config # Feature flags, min version, etc.
GET /api/v1/app/version # Check for required updates
Push notifications are a primary driver for building a native mobile app. They enable direct, timely communication with champions about events, opportunities, and engagement.
| Type | Trigger | Priority | Example | |——|———|———-|———| | Event Reminder | Upcoming RSVP’d event | High | “Homecoming is tomorrow! See you at 2pm.” | | New Event | Event published in champion’s area | Medium | “New volunteer opportunity in Nashville” | | Engagement Milestone | Champion reaches achievement | Low | “You’ve attended 5 events this year! 🎉” | | Direct Message | Staff sends targeted message | High | “Quick question about your availability…” | | Campaign Update | Major initiative announcement | Medium | “Campaign goal reached! Thank you!” |
# Register device for push notifications
POST /api/v1/devices
{
"device_token": "abc123...", # APNs token (iOS) or FCM token (Android)
"platform": "ios", # "ios" or "android"
"app_version": "1.2.0",
"os_version": "17.1",
"device_model": "iPhone 15 Pro"
}
# Update notification preferences
PUT /api/v1/devices/:id/preferences
{
"events": true,
"reminders": true,
"messages": true,
"marketing": false
}
# Remove device (logout/uninstall)
DELETE /api/v1/devices/:id
# Get notification history (for in-app notification center)
GET /api/v1/notifications
GET /api/v1/notifications/unread_count
# Mark notifications as read
POST /api/v1/notifications/:id/read
POST /api/v1/notifications/mark_all_read
| Component | Purpose | Options |
|———–|———|———|
| APNs Integration | iOS push delivery | Direct APNs, or service like Firebase/OneSignal |
| FCM Integration | Android push delivery | Firebase Cloud Messaging |
| Job Queue | Async notification sending | Sidekiq, GoodJob |
| Notification Model | Track sent/read status | New Notification model |
| Preferences | User opt-in/out settings | New NotificationPreference model |
# iOS badge count management
GET /api/v1/notifications/badge_count
POST /api/v1/notifications/clear_badge
Support for rich notifications with images, action buttons:
{
"aps": {
"alert": {
"title": "New Event Near You",
"body": "Nashville Alumni Mixer - Dec 15"
},
"badge": 3,
"sound": "default",
"mutable-content": 1
},
"data": {
"type": "event",
"event_id": "123",
"image_url": "https://..."
}
}
include parameterupdated_at timestamps for sync logic// Example mobile-friendly response
{
"data": {
"id": "B00123456",
"type": "champion",
"attributes": { ... },
"relationships": { ... }
},
"meta": {
"updated_at": "2025-11-26T12:00:00Z",
"sync_token": "abc123"
}
}
| Feature | API Requirement | |———|—————–| | Push Notifications | APNs device token registration endpoint | | Background Refresh | Efficient delta sync endpoint | | Sign in with Apple | OAuth integration with Apple ID | | App Clips | Lightweight authentication flow | | Widgets | Minimal data endpoints for widget refresh |
Future authenticated endpoints for the champion portal:
| Endpoint | Method | Purpose |
|---|---|---|
/api/v1/profile |
GET | Get current champion profile |
/api/v1/profile |
PUT | Update champion profile |
/api/v1/events |
GET | List upcoming events |
/api/v1/events/:id/rsvp |
POST | RSVP to an event |
/api/v1/activities |
GET | Champion’s activity history |
Last updated: November 26, 2025