Book of Mormon 365 API Documentation

Build mobile apps and integrations using our REST API. Track daily scripture reading habits, manage goals, and access community features programmatically.

Getting Started

Base URL

https://bookofmormon365.com/api

Authentication

Most API endpoints require authentication using Bearer tokens. For mobile apps, obtain tokens through the authentication endpoints below. Web users can also generate tokens from their profile page.

Header:
Authorization: Bearer your_api_token_here

Response Format

All responses are JSON with a status field matching the HTTP status code:

Success Response:
{
  "status": 200,
  "data": { ... }
}
Error Response:
{
  "status": 400,
  "error": "Description of what went wrong"
}

Rate Limiting

API requests are subject to reasonable rate limits to ensure service quality. If you exceed limits, you'll receive a 429 Too Many Requests response.

HTTP Status Codes

  • 200 - Success
  • 201 - Created (successful POST)
  • 400 - Bad Request (invalid input)
  • 401 - Unauthorized (missing/invalid token)
  • 403 - Forbidden (valid token, insufficient permissions)
  • 404 - Not Found (endpoint or resource doesn't exist)
  • 405 - Method Not Allowed (wrong HTTP method)
  • 409 - Conflict (duplicate resource)
  • 422 - Unprocessable Entity (validation failed)
  • 429 - Too Many Requests (rate limited)
  • 500 - Internal Server Error

Public Endpoints

These endpoints don't require authentication.

GET /api/status

Check API health and get basic information.

Response:
{
  "status": 200,
  "app": "Book of Mormon 365 API",
  "version": 1,
  "time": "2024-01-15T10:30:00+00:00"
}

GET /api/leaderboard

Get community leaderboards for motivation and competition.

Query Parameters:

  • type - Leaderboard type: longest_streak, current_streak, total_days (default: longest_streak)
  • limit - Number of results (1-50, default: 10)
Example Request:
GET /api/leaderboard?type=current_streak&limit=5
Response:
{
  "status": 200,
  "leaderboard": [
    {
      "display_name": "john_doe",
      "metric": 45
    },
    ...
  ]
}

Privacy Note:

The leaderboard uses display names (usernames when available, otherwise email) to protect user privacy while maintaining community features.

Authentication Endpoints

These endpoints handle user authentication for mobile apps. No Bearer token required.

POST /api/auth/register

Create a new user account.

Request Body:
{
  "email": "user@example.com",
  "username": "john_doe",
  "password": "securepassword123"
}
Response (201):
{
  "status": 201,
  "message": "Account created successfully.",
  "user": {
    "id": 123,
    "username": "john_doe",
    "email": "user@example.com",
    "created_at": "2024-01-15T10:30:00+00:00",
    "passkey_set_at": null
  },
  "token": "api_token_here",
  "token_id": 456,
  "expires_at": null
}

Validation Rules:

  • Email must be valid format
  • Username: letters, numbers, hyphens, underscores only
  • Password: minimum 8 characters
  • Email and username must be unique

POST /api/auth/login

Login with username/email and password.

Request Body:
{
  "identifier": "john_doe", // email or username
  "password": "securepassword123"
}
Response (200):
{
  "status": 200,
  "message": "Login successful.",
  "user": {
    "id": 123,
    "username": "john_doe",
    "email": "user@example.com",
    "created_at": "2024-01-15T10:30:00+00:00",
    "passkey_set_at": "2024-01-10T15:20:00+00:00"
  },
  "token": "api_token_here",
  "token_id": 456,
  "expires_at": null
}

POST /api/auth/passkey-login-options

Get WebAuthn options for passkey login.

Request Body:
{
  "identifier": "john_doe" // email or username
}
Response (200):
{
  "status": 200,
  "options": {
    "challenge": "base64_challenge",
    "timeout": 60000,
    "rpId": "bookofmormon365.com",
    // ... other WebAuthn options
  },
  "user_id": 123
}

POST /api/auth/passkey-login

Complete passkey login with WebAuthn credential.

Request Body:
{
  "user_id": 123,
  "credential": {
    "id": "credential_id",
    "rawId": "base64_raw_id",
    "response": {
      "authenticatorData": "base64_data",
      "clientDataJSON": "base64_json",
      "signature": "base64_signature"
    },
    "type": "public-key"
  }
}
Response (200):
{
  "status": 200,
  "message": "Passkey login successful.",
  "user": { /* same as login */ },
  "token": "api_token_here",
  "token_id": 456,
  "expires_at": null
}

POST /api/auth/refresh-token

Refresh API token (requires current valid token).

Headers:
Authorization: Bearer current_token
Request Body:
{
  "token_id": 456 // optional: ID of token to revoke
}
Response (200):
{
  "status": 200,
  "message": "Token refreshed successfully.",
  "token": "new_api_token_here",
  "token_id": 789,
  "expires_at": null
}

POST /api/auth/logout

Logout and revoke API token.

Headers:
Authorization: Bearer token_to_revoke
Request Body:
{
  "token_id": 456 // optional: specific token ID to revoke
}
Response (200):
{
  "status": 200,
  "message": "Logged out successfully."
}

馃摫 Mobile Implementation Notes:

  • Token Storage: Store tokens securely (iOS Keychain, Android Keystore)
  • Passkey Support: Use platform WebAuthn APIs (iOS: ASAuthorization, Android: FIDO2)
  • Offline Handling: Cache user data and sync when connection restored
  • Token Lifecycle: Tokens don't expire but can be revoked; implement refresh logic

Authenticated Endpoints

These endpoints require a valid API token in the Authorization header.

GET /api/profile

Get current user's profile information.

Response:
{
  "status": 200,
  "user": {
    "id": 123,
    "username": "john_doe",
    "created_at": "2024-01-01T00:00:00+00:00",
    "passkey_set_at": "2024-01-15T12:00:00+00:00"
  }
}

Privacy Note:

User emails are not exposed through the API to protect privacy. Use the username field for display purposes.

GET /api/stats

Get comprehensive reading statistics for the authenticated user.

Response:
{
  "status": 200,
  "stats": {
    "total_days": 156,
    "first_day": "2023-06-01",
    "last_day": "2024-01-15",
    "longest_streak": 45,
    "current_streak": 7,
    "longest_break": 3
  }
}

GET /api/logs

Retrieve recent reading logs with optional notes.

Query Parameters:

  • limit - Number of logs to return (1-100, default: 30)
Response:
{
  "status": 200,
  "logs": [
    {
      "reading_date": "2024-01-15",
      "notes": "Read 1 Nephi 1-3. Great insights about faith.",
      "created_at": "2024-01-15T08:00:00+00:00"
    },
    ...
  ]
}

POST /api/logs

Log a day of scripture reading. This is the core action for tracking daily habits.

Request Body:
{
  "reading_date": "2024-01-15",
  "notes": "Optional notes about today's reading"
}

Validation:

  • Date must be in YYYY-MM-DD format
  • Notes are optional and limited to 1000 characters
  • Logging the same date twice will update the notes
  • This automatically updates streak calculations and goal progress
Response:
{
  "status": 201,
  "message": "Reading logged.",
  "reading_date": "2024-01-15"
}

DELETE /api/logs/{date}

Remove a reading log entry.

Example:
DELETE /api/logs/2024-01-15
Response:
{
  "status": 200,
  "message": "Reading removed.",
  "reading_date": "2024-01-15"
}

GET /api/goals

Get both active streak and completion goals for the authenticated user.

Response:
{
  "status": 200,
  "streak_goal": {
    "id": 456,
    "user_id": 123,
    "target_days": 30,
    "start_date": "2024-01-01",
    "goal_type": "streak",
    "active": true,
    "created_at": "2024-01-01T00:00:00+00:00",
    "achieved_at": null,
    "completed_days": 14,
    "percentage": 46,
    "achieved": false
  },
  "completion_goal": {
    "id": 457,
    "user_id": 123,
    "goal_type": "completion",
    "completion_target_date": "2024-12-31",
    "start_date": "2024-01-15",
    "active": true,
    "created_at": "2024-01-15T00:00:00+00:00",
    "achieved_at": null,
    "total_verses_completed": 1177,
    "total_verses": 6609,
    "completion_percentage": 17.81,
    "section_progress": [...],
    "chapters_remaining": 194,
    "days_remaining": 95,
    "chapters_per_day": 2.04,
    "verses_remaining": 5432,
    "verses_per_day": 57.18,
    "achieved": false
  }
}

Returns null for either goal type if no active goal exists.

POST /api/goals

Create a new reading goal. Supports both streak goals and completion goals.

Create Streak Goal:

Request Body:
{
  "goal_type": "streak",
  "target_days": 30
}

Create Completion Goal:

Request Body:
{
  "goal_type": "completion",
  "target_date": "2024-12-31"
}
Response (Streak Goal):
{
  "status": 201,
  "goal": {
    "id": 458,
    "user_id": 123,
    "target_days": 30,
    "start_date": "2024-01-15",
    "goal_type": "streak",
    "active": true,
    "created_at": "2024-01-15T10:00:00+00:00",
    "achieved_at": null,
    "completed_days": 0,
    "percentage": 0,
    "achieved": false
  }
}

Validation:

  • Streak Goals: target_days must be between 7 and 1000
  • Completion Goals: target_date must be in YYYY-MM-DD format and in the future
  • goal_type must be either "streak" or "completion"

GET /api/books

Get all Book of Mormon books with chapter counts. Useful for building reading progress interfaces.

Response:
{
  "status": 200,
  "books": [
    {
      "id": 1,
      "book_name": "1-nephi",
      "display_name": "1 Nephi",
      "chapter_count": 22,
      "book_order": 1
    },
    {
      "id": 2,
      "book_name": "2-nephi", 
      "display_name": "2 Nephi",
      "chapter_count": 33,
      "book_order": 2
    },
    ...
  ]
}

GET /api/progress

Get detailed Book of Mormon reading progress for the authenticated user.

Response:
{
  "status": 200,
  "progress": [
    {
      "book_name": "1-nephi",
      "display_name": "1 Nephi",
      "chapter_count": 22,
      "chapters_completed": 15,
      "completed_chapters": [1, 2, 3, 4, 5, 7, 8, 9, 12, 13, 14, 15, 18, 20, 22]
    },
    {
      "book_name": "2-nephi",
      "display_name": "2 Nephi", 
      "chapter_count": 33,
      "chapters_completed": 8,
      "completed_chapters": [1, 2, 3, 5, 9, 11, 25, 31]
    },
    ...
  ]
}

POST /api/progress

Log reading progress for a specific book, chapter, and optionally verse. Also creates a daily reading log entry for streak tracking.

Request Body:
{
  "book_name": "1-nephi",
  "chapter": 3,
  "verse": 7,
  "notes": "Great insights about following the Lord's commandments"
}
Response:
{
  "status": 201,
  "message": "Reading progress logged.",
  "book_name": "1-nephi",
  "chapter": 3,
  "verse": 7
}

Parameters:

  • book_name - Required. Use the book_name from /api/books (e.g., "1-nephi", "alma")
  • chapter - Required. Chapter number (must be >= 1)
  • verse - Optional. Specific verse number (must be >= 1 if provided)
  • notes - Optional. Reading notes (max 1000 characters)

Behavior:

  • Automatically creates a daily reading log entry for streak tracking
  • Updates completion goal progress if user has an active completion goal
  • Prevents duplicate entries for the same book/chapter/verse on the same day

Bulk Progress Update:

Request Body (Bulk Update):
{
  "bulk_update": true,
  "progress_data": {
    "1-nephi": 22,
    "2-nephi": 15,
    "jacob": 7,
    "alma": 30
  }
}
Response (Bulk Update):
{
  "status": 201,
  "message": "Bulk reading progress updated.",
  "books_updated": 4
}

Bulk Update Notes: Use the bulk_update: true flag with progress_data object where keys are book names and values are chapter counts completed. This efficiently updates multiple books at once.

POST /api/mark-all-read

Mark all chapters in the Book of Mormon as read. This is a shortcut for users who have already completed the book.

Request Body:
{}
Response:
{
  "status": 201,
  "message": "All chapters marked as read. Congratulations on completing the Book of Mormon!",
  "total_chapters": 239
}

Behavior:

  • Marks all 239 chapters across all 15 books as completed
  • Creates a daily reading log entry for streak tracking
  • Updates completion goal progress to 100%
  • Useful for users migrating from other tracking systems

Mobile App Implementation Guide

Core Features to Implement

  1. Authentication Flow - Direct users to the web app for login/registration and API token generation
  2. Daily Reading Tracker - Simple interface to log today's reading with optional notes
  3. Detailed Progress Tracking - Book/chapter/verse specific reading progress with Book of Mormon completion tracking
  4. Progress Dashboard - Display current streak, total days, and both goal types with progress
  5. Dual Goal Management - Allow users to set and track both streak goals and completion goals
  6. Book of Mormon Interface - Navigate through all 15 books with chapter selection for detailed progress logging
  7. Reading History - Show recent reading logs and detailed chapter progress
  8. Community Features - Display leaderboards for motivation

Recommended App Flow

  1. Onboarding - Explain the dual goal system (streaks + completion) and direct to web registration
  2. Token Setup - Guide users to get their API token from their profile
  3. Goal Creation - Help users set up both streak and completion goals
  4. Daily Check-in - Choose between simple reading log or detailed book/chapter progress
  5. Progress View - Visual streak counter, completion percentage, and daily targets
  6. Book Navigation - Browse through Book of Mormon books with chapter-by-chapter progress
  7. Motivation - Show leaderboards and personal stats

Data Sync Strategy

  • Cache API responses for offline viewing
  • Sync both simple reading logs and detailed progress when connectivity is available
  • Cache Book of Mormon structure (/api/books) for offline book/chapter selection
  • Handle conflicts by preferring server data
  • Refresh leaderboards, stats, and goal progress periodically
  • Sync completion goal targets and daily reading calculations

Push Notifications

Consider implementing daily reminders to encourage consistent reading habits. The API doesn't currently support push notifications, but you can implement local notifications for:

  • Daily reading reminders with suggested chapters based on completion goals
  • Streak milestone celebrations
  • Completion goal progress milestones (25%, 50%, 75%)
  • Daily target reminders ("Read 2.5 chapters today to stay on track")
  • Goal completion notifications for both streak and completion achievements

Security & Privacy

Data Privacy

  • No Email Exposure - User emails are never exposed through the API to protect privacy
  • Display Names - Leaderboards and profiles use usernames when available
  • User Isolation - Users can only access their own data through authenticated endpoints
  • Input Validation - All inputs are validated and sanitized

Best Practices

  • Secure Token Storage - Store API tokens securely in your app (keychain/secure storage)
  • Rate Limiting - Be respectful with API usage and implement client-side rate limiting
  • Data Validation - Always validate data on the client side before sending to API
  • Error Handling - Implement proper error handling for all API responses

Mobile App Integration Examples

iOS Swift Example

Login with Password:
struct LoginRequest: Codable {
    let identifier: String
    let password: String
}

struct User: Codable {
    let id: Int
    let username: String
    let email: String
    let created_at: String
    let passkey_set_at: String?
}

struct LoginResponse: Codable {
    let status: Int
    let message: String
    let user: User
    let token: String
    let token_id: Int
}

func login(identifier: String, password: String) async throws -> LoginResponse {
    let url = URL(string: "https://bookofmormon365.com/api/auth/login")!
    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.setValue("application/json", forHTTPHeaderField: "Content-Type")
    
    let loginData = LoginRequest(identifier: identifier, password: password)
    request.httpBody = try JSONEncoder().encode(loginData)
    
    let (data, _) = try await URLSession.shared.data(for: request)
    return try JSONDecoder().decode(LoginResponse.self, from: data)
}

Android Kotlin Example

API Service with Retrofit:
data class LoginRequest(
    val identifier: String,
    val password: String
)

data class LoginResponse(
    val status: Int,
    val message: String,
    val user: User,
    val token: String,
    val token_id: Int
)

interface BookOfMormonApi {
    @POST("auth/login")
    suspend fun login(@Body request: LoginRequest): Response<LoginResponse>
    
    @GET("profile")
    suspend fun getProfile(@Header("Authorization") token: String): Response<ProfileResponse>
    
    @POST("logs")
    suspend fun logReading(@Header("Authorization") token: String, @Body request: LogRequest): Response<LogResponse>
}

class ApiClient {
    private val api = Retrofit.Builder()
        .baseUrl("https://bookofmormon365.com/api/")
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(BookOfMormonApi::class.java)
    
    suspend fun login(identifier: String, password: String): LoginResponse? {
        val response = api.login(LoginRequest(identifier, password))
        return if (response.isSuccessful) response.body() else null
    }
}

React Native Example

API Client:
class BookOfMormonClient {
  constructor(baseUrl = 'https://bookofmormon365.com/api') {
    this.baseUrl = baseUrl;
    this.token = null;
  }

  async login(identifier, password) {
    const response = await fetch(`${this.baseUrl}/auth/login`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ identifier, password }),
    });
    
    const data = await response.json();
    if (data.status === 200) {
      this.token = data.token;
      // Store token securely
      await AsyncStorage.setItem('bom365_token', data.token);
    }
    return data;
  }

  async logReading(date, notes = null) {
    const response = await fetch(`${this.baseUrl}/logs`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'Authorization': `Bearer ${this.token}`,
      },
      body: JSON.stringify({ reading_date: date, notes }),
    });
    
    return await response.json();
  }
}

Support and Feedback

Questions or need help building your integration? Contact us or open an issue in our repository.

Useful Links