Integration Guide
This guide walks through the complete user journey from account creation to active usage, with example payloads for each step. All calls go to https://api.ozzieapp.com/v1.
Full user journeyβ
1. POST /v1/users β user created
2. POST /v1/users/{id}/financial-intake β intake stored
3. GET /v1/personality/questions β quiz catalog
POST /v1/personality/score β personality_type (store it)
4. POST /v1/users/{id}/plan/generate β plan with envelopes + plan_tier
ββ Active usage βββββββββββββββββββββββββββββββββββββββββββββββββββββ
5. GET /v1/users/{id}/financial-profile?personality_type=X
6. POST /v1/users/{id}/chat/completion β stateless AI reply (store it)
7. POST /v1/transactions/parse β parsed spending records (store them)
8. POST /v1/money-moves/generate β weekly tasks (store + track)
Step 1 β Create userβ
- curl
- Node.js
curl -X POST https://api.ozzieapp.com/v1/users \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"external_user_id": "usr_8821",
"name": "Maria Santos",
"email": "maria@example.com",
"language": "en"
}'
const res = await fetch('https://api.ozzieapp.com/v1/users', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
external_user_id: 'usr_8821',
name: 'Maria Santos',
email: 'maria@example.com',
language: 'en',
}),
});
const { data: user } = await res.json();
const userId = user.id; // "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE"
Response:
{
"object": "user",
"data": {
"id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"name": "Maria Santos",
"language": "en",
"created_at": "2026-05-15T10:00:00Z"
}
}
Save the id β use it in all subsequent calls for this user.
Step 2 β Submit financial intakeβ
- curl
curl -X POST https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/financial-intake \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"monthly_income": 5000,
"monthly_expenses": 3200,
"financial_goal": "savings",
"next_pay_date": "2026-05-20"
}'
Response:
{
"object": "financial_intake",
"data": {
"id": "ozz_intake_01HX9M3F",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"monthly_income": 5000,
"monthly_expenses": 3200,
"monthly_surplus": 1800,
"financial_goal": "savings",
"created_at": "2026-05-15T10:01:00Z"
}
}
Step 3 β Score personalityβ
Get questionsβ
curl https://api.ozzieapp.com/v1/personality/questions \
-H "Authorization: Bearer YOUR_TOKEN"
Submit answersβ
curl -X POST https://api.ozzieapp.com/v1/personality/score \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"answers": [
{ "question_id": "q_001", "option_id": "q_001_b" },
{ "question_id": "q_002", "option_id": "q_002_b" }
]
}'
Response:
{
"object": "personality_score",
"data": {
"personality_type": "STOCKPILER",
"score_breakdown": {
"HOTSHOT": 1,
"STOCKPILER": 7,
"GIVER": 1,
"INDEPENDENT": 1
}
}
}
Store personality_type in your database. You will pass it explicitly on every subsequent intelligence call.
Step 4 β Generate the planβ
Pass personality_type and optionally plan_speed (conservative | moderate | aggressive). plan_speed shifts goal allocation by Β±5 percentage points. Defaults to moderate.
curl -X POST https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/plan/generate \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "personality_type": "STOCKPILER", "plan_speed": "aggressive" }'
Response:
{
"object": "plan",
"data": {
"id": "ozz_plan_01HX9N7C",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"personality_type": "STOCKPILER",
"plan_tier": "20/80",
"envelopes": {
"bills": { "allocated_pct": 38.0, "allocated_amount": 1900.00 },
"future": { "allocated_pct": 35.0, "allocated_amount": 1750.00 },
"daily_living": { "allocated_pct": 9.5, "allocated_amount": 475.00 },
"health_wellness": { "allocated_pct": 6.0, "allocated_amount": 300.00 },
"lifestyle": { "allocated_pct": 5.0, "allocated_amount": 250.00 },
"people": { "allocated_pct": 6.5, "allocated_amount": 325.00 }
},
"action_items": [
"Your STOCKPILER profile means you're built for saving β lean into it.",
"Aggressive speed means 5% more going to your goal every month."
],
"created_at": "2026-05-15T10:03:00Z"
}
}
Store both plan_tier and plan_speed β you'll use plan_tier when generating money moves and pass both in user_context when calling the chat endpoint.
Active usageβ
Step 5 β View financial profileβ
curl "https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/financial-profile?personality_type=STOCKPILER" \
-H "Authorization: Bearer YOUR_TOKEN"
Response:
{
"object": "financial_profile",
"data": {
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"personality_type": "STOCKPILER",
"envelopes": {
"bills": { "allocated_pct": 40.0 },
"future": { "allocated_pct": 30.0 },
"daily_living": { "allocated_pct": 10.5 },
"health_wellness": { "allocated_pct": 6.0 },
"lifestyle": { "allocated_pct": 6.0 },
"people": { "allocated_pct": 7.5 }
}
}
}
Step 6 β Chat with the AI coachβ
Before calling the chat endpoint, assemble a user_context snapshot from your database. The more context you provide, the more personalized the response. Use entry_point to tell Ozzie where the user arrived from β Ozzie will return a ready-to-display entry_point_opener your app can show before the user types anything.
Assembling the context snapshot:
// Build user_context from your database before each chat call
const userContext = {
name: user.name, // from your users table
language: user.language, // user's preferred language
personality_type: user.personality_type, // stored after quiz
plan_tier: user.plan_tier, // stored after plan generation
plan_speed: user.plan_speed, // stored after plan generation
monthly_income: user.monthly_income, // from intake
goal_progress: {
target_amount_cents: goal.target_amount_cents,
total_contributed_cents: goal.total_contributed_cents,
percentage: goal.percentage,
},
next_move: {
date: nextMove.date,
amount_cents: nextMove.amount_cents,
},
completed_moves_count: user.completed_moves_count,
total_saved_cents: user.total_saved_cents,
last_confirmation_note: lastMove.confirmation_note, // optional
entry_point: resolveEntryPoint(session), // e.g. "unprompted", "weekly_expense", etc.
// Only set for spending_alert entry_point:
spending_alert_envelope: alert?.envelope,
spending_alert_ratio: alert?.ratio,
rag_context: await loadRagContext(user.id), // optional behavioral patterns
};
Example request with full context (unprompted entry):
curl -X POST https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/chat/completion \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "oi",
"user_context": {
"name": "Maria",
"language": "pt",
"personality_type": "STOCKPILER",
"plan_tier": "20/80",
"plan_speed": "aggressive",
"monthly_income": 5000,
"goal_progress": {
"target_amount_cents": 500000,
"total_contributed_cents": 125000,
"percentage": 25
},
"next_move": { "date": "2026-05-20", "amount_cents": 20000 },
"completed_moves_count": 8,
"total_saved_cents": 125000,
"entry_point": "unprompted"
}
}'
Response:
{
"object": "chat_completion",
"data": {
"role": "assistant",
"content": "Oi Maria! VocΓͺ completou 8 passos e jΓ‘ guardou $1,250. Seu prΓ³ximo passo Γ© dia 2026-05-20. Sobre o que vocΓͺ quer falar hoje?",
"entry_point_opener": "Oi Maria! VocΓͺ completou 8 passos e jΓ‘ guardou $1,250. Seu prΓ³ximo passo Γ© dia 2026-05-20. Sobre o que vocΓͺ quer falar hoje?",
"context": "general",
"created_at": "2026-05-15T10:10:00Z"
}
}
Display entry_point_opener immediately when the chat screen opens (before the user types). It will be null for move_reminder entry points (render the passo card instead) and when no entry_point was sent.
Store the message and reply in your database. Pass them in history on subsequent calls for a continuous conversation experience.
Step 7 β Parse transactionsβ
curl -X POST https://api.ozzieapp.com/v1/transactions/parse \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"type": "text",
"content": "Spent $45 on groceries at Whole Foods and $12 on the subway"
}'
Response:
{
"object": "transaction_list",
"data": {
"transactions": [
{
"amount_cents": 4500,
"currency": "USD",
"category": "food",
"envelope": "daily_living",
"description": "Groceries at Whole Foods",
"transaction_date": "2026-05-15"
},
{
"amount_cents": 1200,
"currency": "USD",
"category": "transport",
"envelope": "daily_living",
"description": "Subway fare",
"transaction_date": "2026-05-15"
}
]
}
}
Store the returned records in your database. Use envelope and amount_cents to compute spending against the user's plan allocations.
Step 8 β Generate weekly money movesβ
curl -X POST https://api.ozzieapp.com/v1/money-moves/generate \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"personality_type": "STOCKPILER",
"plan_tier": "30/70",
"week_start": "2026-05-13"
}'
Response:
{
"object": "money_move_set",
"data": {
"week_start": "2026-05-13",
"week_end": "2026-05-19",
"personality_type": "STOCKPILER",
"tasks": [
{
"type": "do",
"title": "Transfer $375 to your savings account",
"amount_cents": 37500
},
{
"type": "learn",
"title": "Read: Why high-yield savings accounts compound your STOCKPILER advantage"
},
{
"type": "mind",
"title": "Write down one financial buffer that would make you feel more secure"
}
]
}
}
Store the tasks in your database. Track completion status and record amount_cents from do task completions as goal contributions.
Error states and recoveryβ
| Situation | Error code | Recovery |
|---|---|---|
| Plan generation before intake | INTAKE_REQUIRED | Submit intake, then retry |
| Financial profile before plan | PLAN_REQUIRED | Generate plan, then retry |
Duplicate external_user_id | CONFLICT | Use GET /v1/users/external:your_id to retrieve the existing user |
| Too many requests | RATE_LIMIT_EXCEEDED | Respect Retry-After header, use exponential backoff |
Error shape (all errors follow this format):
{
"error": {
"code": "INTAKE_REQUIRED",
"message": "Financial intake must be submitted before generating a plan."
}
}