Complete API reference for jijiv2's backend endpoints and AI integration.
jijiv2 uses Better Auth with Google OAuth for authentication.
Initiates Google OAuth flow.
Response: Redirects to Google OAuth consent screen
OAuth callback endpoint.
Response: Redirects to /wallet on success
Signs out the current user.
Response: Redirects to /
Sessions are managed via HTTP-only cookies. The session includes:
{
user: {
id: string;
email: string;
name: string;
image?: string;
}
}Streams AI responses for financial queries and transaction extraction.
Content-Type: application/json
Cookie: better-auth.session_token=<session_token>
{
messages: UIMessage[]; // Conversation history
apiKey: string; // User's AI provider API key
modelId: string; // Model identifier
apiProvider?: 'openrouter' | 'gemini'; // Default: 'openrouter'
currency?: string; // Default: 'USD'
}Server-Sent Events (SSE) stream with AI responses.
Stream format: text/event-stream
const response = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages: [{ role: 'user', content: 'coffee for $5' }],
apiKey: 'sk-or-...',
modelId: 'openai/gpt-4o-mini',
apiProvider: 'openrouter',
currency: 'USD',
}),
});| Status | Description |
|---|---|
| 401 | Unauthorized (not logged in) |
| 400 | Missing API key or model ID |
| 500 | AI provider error |
Stores user transactions.
CREATE TABLE transaction (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id TEXT NOT NULL,
type TEXT NOT NULL, -- 'income' or 'expense'
category TEXT NOT NULL,
amount TEXT NOT NULL, -- Stored as text, cast to DECIMAL for calculations
description TEXT NOT NULL,
date TEXT NOT NULL, -- ISO 8601 format (YYYY-MM-DD)
payment_method TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);Managed by Better Auth. Includes Google OAuth data.
The AI has access to two tools for transaction management:
Extracts transaction details from natural language.
{
type: 'income' | 'expense',
category: string,
amount: number, // Positive number
description: string,
date: string, // YYYY-MM-DD
paymentMethod: string
}User: "coffee for $5"
AI extracts:
{
"type": "expense",
"category": "Food & Dining",
"amount": 5,
"description": "coffee",
"date": "2026-01-14",
"paymentMethod": "Cash"
}- Food & Dining
- Groceries
- Transportation
- Entertainment
- Shopping
- Bills & Utilities
- Healthcare
- Travel
- Education
- Salary
- Freelance
- Investment
- Other
- Cash
- Credit Card
- Debit Card
- Bank Transfer
- Digital Wallet
- Other
Executes read-only SQL queries on transactions.
{
sqlQuery: string; // SELECT statement only
}- User isolation: Query MUST include
WHERE user_id = '<user_id>' - Read-only: Only SELECT statements allowed
- Result limit: Maximum 10 rows (enforced by AI)
- Amount casting: Use
CAST(amount AS DECIMAL)for calculations
Total food expenses this month:
SELECT SUM(CAST(amount AS DECIMAL)) as total
FROM transaction
WHERE user_id = 'user_123'
AND type = 'expense'
AND category = 'Food & Dining'
AND date >= '2026-01-01'
AND date < '2026-02-01'Average transportation cost:
SELECT AVG(CAST(amount AS DECIMAL)) as avg_cost
FROM transaction
WHERE user_id = 'user_123'
AND category = 'Transportation'# Database
DATABASE_URL="postgresql://user:password@localhost:5432/jijiv2"
# Authentication
BETTER_AUTH_SECRET="your-secret-key-here"
BETTER_AUTH_URL="http://localhost:3000"
# Google OAuth
GOOGLE_CLIENT_ID="your-google-client-id"
GOOGLE_CLIENT_SECRET="your-google-client-secret"# Node environment
NODE_ENV="development" # or "production"The AI uses a token-optimized system prompt (~300 tokens) that includes:
- Transaction extraction guidelines
- Query rules (redirect broad queries to UI)
- Database schema
- SQL security requirements
- UI feature awareness (Quick Info, Transactions Tab)
- Message History Limit: Last 5 messages only (~300-400 tokens)
- Simplified Tools: Minimal descriptions (~200 tokens)
- Concise Prompts: No redundant examples
- Smart Redirects: Prevents expensive queries
Average request: ~1,200 tokens (system + tools + history + message)
When available, repeated system prompts are cached:
- OpenAI: Automatic caching (90% discount on repeated tokens)
- Anthropic: Automatic caching
- Gemini: Natural caching behavior
Current implementation: None (relies on AI provider's rate limits)
Recommendation for production:
- Implement per-user rate limiting (e.g., 60 requests/minute)
- Add request cooldown for expensive queries
- Monitor token usage per user
| Error Type | User Message |
|---|---|
RATE_LIMITED |
"You've been rate limited. Please wait a moment..." |
INVALID_API_KEY |
"Your API key appears to be invalid..." |
INSUFFICIENT_CREDITS |
"Insufficient credits or quota exceeded..." |
MODEL_UNAVAILABLE |
"The selected model is currently unavailable..." |
UNKNOWN |
"Oops! Something went wrong..." |
Errors are parsed from AI provider responses and displayed in-chat.
- Always validate user input before sending to AI
- Use TypeScript types for all API requests/responses
- Test with different AI models (some behave differently)
- Monitor token usage in production
- Implement proper error boundaries
- Use specific queries ("food expenses last month" vs "show everything")
- Check Quick Info before asking for balance/totals
- Use Transactions Tab for viewing all transactions
- Keep API keys secure (stored in browser only)
- Webhook support for real-time updates
- Batch transaction import API
- Export transactions to CSV/JSON
- Analytics API endpoints
- Custom category management
- Recurring transactions
Version: 2.0
Last Updated: January 2026
Maintained by: gian-gg