Skip to main content

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 -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"
}'

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 -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​

SituationError codeRecovery
Plan generation before intakeINTAKE_REQUIREDSubmit intake, then retry
Financial profile before planPLAN_REQUIREDGenerate plan, then retry
Duplicate external_user_idCONFLICTUse GET /v1/users/external:your_id to retrieve the existing user
Too many requestsRATE_LIMIT_EXCEEDEDRespect 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."
}
}