Skip to main content

Overview

Your Bible integrates with multiple external services to provide its full functionality. This page documents each integration, including setup, configuration, API usage, and best practices.

API.Bible

Bible content, translations, and search

Google Gemini AI

AI-powered story generation

Convex

Real-time backend and database

Better Auth

Authentication and user management

Upstash Redis

Rate limiting and caching

PostgreSQL (Neon)

User and session data storage

API.Bible

API.Bible provides access to multiple Bible translations, chapters, verses, and search functionality.

Configuration

Configured in src/lib/axios.ts:1:
import axios from 'axios'

const API_KEY = process.env.API_KEY
const API_BASE_URL = process.env.API_BASE_URL

export const axiosInstance = axios.create({
    baseURL: API_BASE_URL,
    headers: {
        'api-key': API_KEY,
        'Content-Type': 'application/json'
    }
})

Environment Variables

API_BASE_URL
string
required
Value: https://api.scripture.api.bible/v1Base URL for all API.Bible requests.
API_KEY
string
required
Your API.Bible API key from scripture.api.bible.How to get:
  1. Sign up at API.Bible
  2. Create an API key
  3. Add to .env file

Key Features

Endpoint: GET /biblesRetrieves list of available Bible translations.Response:
{
  "data": [
    {
      "id": "de4e12af7f28f599-02",
      "name": "King James Version",
      "abbreviation": "KJV",
      "language": { "id": "eng", "name": "English" }
    }
  ]
}
Usage: Translation selector dropdown
Endpoint: GET /bibles/{bibleId}/chapters/{chapterId}Retrieves full chapter content with verses.Parameters:
  • bibleId: Translation ID (e.g., "de4e12af7f28f599-02")
  • chapterId: Chapter ID (e.g., "GEN.1", "JHN.3")
  • include-verse-numbers: true (optional)
Response:
{
  "data": {
    "id": "GEN.1",
    "bibleId": "de4e12af7f28f599-02",
    "number": "1",
    "bookId": "GEN",
    "content": "<p>In the beginning...</p>"
  }
}
Usage: Bible reader component
Endpoint: GET /bibles/{bibleId}/books/{bookId}/chaptersList all chapters in a book.Usage: Chapter navigation

Rate Limits

Free tier rate limits:
  • 500 requests per day
  • 10 requests per second

Best Practices

  • Cache translation lists (rarely change)
  • Cache chapter content (use TanStack Query)
  • Implement exponential backoff for retries
  • Handle rate limit errors gracefully
  • Use include-verse-numbers parameter for better verse identification

Error Handling

try {
  const response = await axiosInstance.get(`/bibles/${bibleId}/chapters/${chapterId}`);
  return response.data;
} catch (error) {
  if (error.response?.status === 429) {
    // Rate limit exceeded
    throw new Error('Too many requests. Please try again later.');
  } else if (error.response?.status === 404) {
    // Chapter not found
    throw new Error('Chapter not found.');
  }
  throw error;
}

Google Gemini AI

Google Gemini AI generates creative stories based on biblical passages.

Configuration

Configured in src/lib/gemini.ts:1:
import { GoogleGenAI } from "@google/genai"

function createAIClient() {
    const apiKey = process.env.GEMINI_API_KEY
    if (!apiKey) {
        throw new Error('Missing Gemini API key')
    }
    return new GoogleGenAI({ apiKey })
}

let aiInstance: GoogleGenAI | null = null

export function getAI() {
    if (!aiInstance) {
        aiInstance = createAIClient()
    }
    return aiInstance
}

Environment Variables

GEMINI_MODEL
string
required
Recommended: gemini-1.5-flashAlternatives:
  • gemini-1.5-pro - Higher quality, slower, more expensive
  • gemini-1.5-flash - Balanced speed and quality
Model Comparison:
  • Flash: ~0.1s response time, lower cost
  • Pro: ~1-2s response time, better quality, higher cost
GEMINI_API_KEY
string
required
Your Google AI API key from Google AI Studio.How to get:
  1. Visit Google AI Studio
  2. Sign in with Google account
  3. Create API key
  4. Add to .env file

Story Generation

Usage Example:
import { getAI } from '@/lib/gemini';

const ai = getAI();
const model = ai.getGenerativeModel({ model: process.env.GEMINI_MODEL });

const prompt = `
Generate a ${storyLength} story based on the following biblical passage:

${bibleText}

Parameters:
- Perspective: ${perspective}
- Setting: ${setting}
- Tone: ${tone}

Guidelines:
- Stay true to biblical themes and messages
- Be respectful and theologically appropriate
- Make it engaging and well-written
- Include descriptive details
`;

const result = await model.generateContent(prompt);
const story = result.response.text();

Story Parameters

perspective
string
required
Narrative viewpoint for the story.Examples:
  • “first-person from David’s perspective”
  • “third-person omniscient”
  • “second-person narrative”
setting
string
required
Context or world for the story.Examples:
  • “ancient Israel”
  • “modern day”
  • “alternate historical timeline”
tone
string
required
Emotional quality of the story.Examples:
  • “contemplative and reflective”
  • “adventurous and exciting”
  • “solemn and reverent”
storyLength
string
required
Desired story length.Options:
  • short - 200-400 words
  • medium - 400-800 words
  • long - 800-1500 words

Rate Limits

Free Tier:
  • 60 requests per minute
  • 1,500 requests per day
Application Rate Limiting:
  • 5 stories per user per day (enforced via Redis)
  • Prevents excessive API costs

Best Practices

  • Provide clear context from the biblical passage
  • Specify all parameters explicitly
  • Include theological guidelines
  • Request specific tone and style
  • Set word count expectations
try {
  const result = await model.generateContent(prompt);
  return result.response.text();
} catch (error) {
  if (error.message?.includes('quota')) {
    throw new Error('API quota exceeded');
  }
  throw new Error('Failed to generate story');
}
  • Gemini has built-in safety filters
  • Handles inappropriate requests automatically
  • Returns filtered responses for sensitive topics
  • May refuse to generate certain content

Convex

Convex provides real-time database and backend functionality.

Configuration

Schema: convex/schema.ts Functions: convex/*.ts files Client: Initialized in app

Environment Variables

CONVEX_DEPLOYMENT
string
required
Convex deployment identifier (auto-generated).
VITE_CONVEX_URL
string
required
Convex backend URL for client connections.Example: https://your-project.convex.cloud

Key Features

Queries automatically update when data changes:
const collections = useQuery(api.collections.list, {
  userId: user.id,
});
// Automatically re-renders on data changes
Write operations with optimistic updates:
const createCollection = useMutation(api.collections.create);

await createCollection({
  name: "My Collection",
  userId: user.id,
});
Backend logic runs on Convex servers:
export const create = mutation({
  args: { name: v.string(), userId: v.string() },
  handler: async (ctx, args) => {
    return await ctx.db.insert("collections", args);
  },
});

Best Practices

  • Use indexes for frequently queried fields
  • Validate all inputs in mutations
  • Implement proper access control
  • Keep functions small and focused
  • Use TypeScript types generated by Convex
See Database Schema for detailed documentation.

Better Auth

Better Auth handles user authentication with email/password and OAuth providers.

Configuration

Configured in src/lib/auth.ts:1:
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { reactStartCookies } from "better-auth/react-start";

export const auth = betterAuth({
    database: drizzleAdapter(db, {
        provider: 'pg'
    }),
    emailAndPassword: {
        enabled: true,
        autoSignIn: true,
        requireEmailVerification: false,
    },
    socialProviders: {
        github: {
            clientId: process.env.GITHUB_CLIENT_ID as string,
            clientSecret: process.env.GITHUB_CLIENT_SECRET as string,
        }
    },
    plugins: [reactStartCookies()]
})

Environment Variables

BETTER_AUTH_SECRET
string
required
Secret key for encrypting sessions and tokens.Generate: openssl rand -base64 32
BETTER_AUTH_URL
string
required
Application base URL for auth callbacks.Development: http://localhost:5173Production: Your domain URL
DATABASE_URL
string
required
PostgreSQL connection string for user data.
GITHUB_CLIENT_ID
string
GitHub OAuth client ID (optional).
GITHUB_CLIENT_SECRET
string
GitHub OAuth client secret (optional).

Features

  • User registration with email and password
  • Secure password hashing
  • Automatic sign-in after registration
  • No email verification required (configurable)
Usage:
const { signIn, signUp } = useAuth();

await signUp({
  email: 'user@example.com',
  password: 'secure-password',
});
  • Sign in with GitHub
  • Automatic account linking
  • Profile data import
Setup:
  1. Create GitHub OAuth App
  2. Set callback URL: {BETTER_AUTH_URL}/api/auth/callback/github
  3. Add client ID and secret to .env
  • Cookie-based sessions
  • Automatic session refresh
  • Secure, httpOnly cookies
  • Cross-tab session sync

Best Practices

  • Use strong, unique BETTER_AUTH_SECRET
  • Enable email verification in production
  • Implement password strength requirements
  • Use HTTPS in production
  • Regularly rotate secrets

Upstash Redis

Redis provides rate limiting for story generation to manage API costs.

Configuration

Configured in src/lib/redis.ts:1:
import { Redis } from '@upstash/redis';
import { Ratelimit } from "@upstash/ratelimit";

export const ratelimit = new Ratelimit({
    redis: Redis.fromEnv(),
    limiter: Ratelimit.fixedWindow(5, "86400 s"),
    analytics: true,
    prefix: "@upstash/ratelimit",
});

Environment Variables

REDIS_URL
string
required
Redis connection URL.
KV_URL
string
required
Upstash KV connection URL.
KV_REST_API_URL
string
required
REST API URL for Redis operations.
KV_REST_API_TOKEN
string
required
Authentication token for REST API.
KV_REST_API_READ_ONLY_TOKEN
string
required
Read-only token for security.

Rate Limiting

Configuration:
  • Algorithm: Fixed window
  • Limit: 5 requests per window
  • Window: 86,400 seconds (24 hours)
  • Per: User ID
Usage:
import { ratelimit } from '@/lib/redis';

const { success, reset } = await ratelimit.limit(userId);

if (!success) {
  const resetDate = new Date(reset);
  throw new Error(`Rate limit exceeded. Try again at ${resetDate.toLocaleString()}`);
}

// Proceed with story generation

Best Practices

  • Use user ID as rate limit key
  • Provide clear error messages with reset time
  • Display remaining attempts to users
  • Consider different limits for paid tiers
  • Monitor analytics in Upstash dashboard

PostgreSQL (Neon)

PostgreSQL stores user accounts, sessions, and authentication data via Better Auth.

Environment Variables

DATABASE_URL
string
required
PostgreSQL connection string.Format: postgresql://user:password@host:port/database?sslmode=requireNeon: Automatically includes SSLLocal: postgresql://localhost/yourbible

Schema

Managed by Better Auth via Drizzle ORM:
  • users - User accounts
  • sessions - Active sessions
  • accounts - OAuth account links
  • verificationTokens - Email verification (if enabled)

Best Practices

  • Use SSL in production (?sslmode=require)
  • Regular backups (automatic with Neon)
  • Monitor connection pool usage
  • Use connection pooling for serverless
  • Keep schema migrations tracked

Integration Testing

Testing Each Service

curl -H "api-key: YOUR_KEY" \
  https://api.scripture.api.bible/v1/bibles

Monitoring and Analytics

  • Monitor usage in API.Bible dashboard
  • Track rate limit usage
  • Set up alerts for quota warnings
  • Monitor usage in Google Cloud Console
  • Track token usage and costs
  • Set up billing alerts
  • View function logs in Convex dashboard
  • Monitor query performance
  • Track database size
  • View rate limit analytics
  • Monitor Redis operations
  • Track API usage

Cost Optimization

API.Bible

Free Tier: 500 requests/dayOptimization:
  • Cache translation lists
  • Cache chapter content
  • Use CDN for static content

Gemini AI

Free Tier: 60 RPM, 1.5K RPDOptimization:
  • Rate limit (5/day per user)
  • Use Flash model over Pro
  • Optimize prompt length

Convex

Free Tier: Generous limitsOptimization:
  • Use indexes efficiently
  • Paginate large queries
  • Clean up old data

Neon

Free Tier: 0.5 GB storageOptimization:
  • Archive old sessions
  • Monitor database size
  • Use appropriate data types

Environment Variables

Complete environment variable reference

Local Setup

Setting up all integrations locally

Database Schema

Convex database schema documentation

Deployment

Deploying with all integrations