API Flow and Sequence
This page describes the exact sequence of API calls to integrate ozzie-openapi from scratch. All calls go to https://api.ozzieapp.com/v1.
Onboarding sequenceβ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β OZZIE ONBOARDING SEQUENCE (ozzie-openapi) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[1] POST /v1/users
β Creates user identity
βΌ
[2] POST /v1/users/{user_id}/financial-intake
β Stores monthly income, expenses, goal
βΌ
[3] GET /v1/personality/questions
β Fetches quiz catalog
βΌ
POST /v1/personality/score
β Scores answers β personality_type
β Your app stores the result
βΌ
[4] POST /v1/users/{user_id}/plan/generate
β body: { personality_type }
β Returns plan with envelopes + plan_tier
β Your app stores plan_tier
βΌ
ACTIVE USER β proceed to ongoing usage
Ongoing usageβ
[5] GET /v1/users/{user_id}/financial-profile?personality_type=X
β Envelope allocations (percentages only)
βΌ
[6] POST /v1/users/{user_id}/chat/completion
β body: { message, personality_type, history }
β Your app stores message + reply
βΌ
[7] POST /v1/transactions/parse
β body: { type, content }
β Returns parsed transactions β your app stores them
βΌ
[8] POST /v1/money-moves/generate
β body: { user_id, personality_type, plan_tier }
β Returns weekly tasks β your app stores + tracks them
βΌ
Repeat steps 6β8 each week
Step-by-step referenceβ
Step 1 β Create userβ
Endpoint: POST /v1/users
| Field | Type | Required | Description |
|---|---|---|---|
external_user_id | string | Yes | Your internal user ID |
name | string | No | Display name |
email | string | No | Email address |
language | string | No | "en" | "pt" | "es" |
POST https://api.ozzieapp.com/v1/users
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Content-Type: application/json
{
"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-15T14:30:00Z"
}
}
Save the id field. Use it in all subsequent API paths for this user.
Step 2 β Send financial intakeβ
Endpoint: POST /v1/users/{user_id}/financial-intake
POST https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/financial-intake
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Content-Type: application/json
{
"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-15T14:31:00Z"
}
}
Step 3 β Score personalityβ
Get questions:
GET https://api.ozzieapp.com/v1/personality/questions
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Score answers:
POST https://api.ozzieapp.com/v1/personality/score
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Content-Type: application/json
{
"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 planβ
Endpoint: POST /v1/users/{user_id}/plan/generate
Requires: Financial intake submitted. Pass personality_type in the request body.
POST https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/plan/generate
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Content-Type: application/json
{
"personality_type": "STOCKPILER"
}
Response:
{
"object": "plan",
"data": {
"id": "ozz_plan_01HX9N7C",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"personality_type": "STOCKPILER",
"plan_tier": "30/70",
"envelopes": {
"bills": { "allocated_pct": 40.0, "allocated_amount": 2000.00 },
"future": { "allocated_pct": 30.0, "allocated_amount": 1500.00 },
"daily_living": { "allocated_pct": 10.5, "allocated_amount": 525.00 },
"health_wellness": { "allocated_pct": 6.0, "allocated_amount": 300.00 },
"lifestyle": { "allocated_pct": 6.0, "allocated_amount": 300.00 },
"people": { "allocated_pct": 7.5, "allocated_amount": 375.00 }
},
"action_items": [
"Automate a $1,500 transfer to savings on payday.",
"Your STOCKPILER profile means building security before all else."
],
"created_at": "2026-05-15T14:33:00Z"
}
}
Store plan_tier β you'll use it when generating money moves.
Step 5 β Financial profileβ
GET https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/financial-profile?personality_type=STOCKPILER
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Returns envelope allocation percentages.
Step 6 β Chatβ
POST https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/chat/completion
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Content-Type: application/json
{
"message": "Am I on track to build my emergency fund?",
"personality_type": "STOCKPILER",
"language": "en"
}
Response:
{
"object": "chat_completion",
"data": {
"role": "assistant",
"content": "Maria, your STOCKPILER profile means consistent, automated saving is your edge. Keep that transfer running and you'll hit your monthly target.",
"created_at": "2026-05-15T14:35:00Z"
}
}
Store the message and reply in your database. Pass history on subsequent calls.
Step 7 β Parse transactionsβ
POST https://api.ozzieapp.com/v1/transactions/parse
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Content-Type: application/json
{
"type": "text",
"content": "Groceries $45 at Whole Foods",
"language": "en"
}
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"
}
]
}
}
Store the returned records in your database.
Step 8 β Generate weekly money movesβ
POST https://api.ozzieapp.com/v1/money-moves/generate
Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=
Content-Type: application/json
{
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"personality_type": "STOCKPILER",
"plan_tier": "30/70",
"week_start": "2026-05-13"
}
Store the returned tasks and track completion status in your database.
Error states and recoveryβ
| Situation | Error code | Recovery |
|---|---|---|
| Plan generation before intake | INTAKE_REQUIRED | Submit POST /financial-intake first, then retry |
| Financial profile before plan | PLAN_REQUIRED | Generate plan first, 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:
{
"error": {
"code": "INTAKE_REQUIRED",
"message": "Financial intake must be submitted before generating a plan."
}
}
Node.js end-to-end exampleβ
import fetch from 'node-fetch';
const BASE = 'https://api.ozzieapp.com/v1';
const TOKEN = Buffer.from('your_client_id:your_client_secret').toString('base64');
const h = {
'Authorization': `Bearer ${TOKEN}`,
'Content-Type': 'application/json',
};
async function req(method, path, body) {
const res = await fetch(`${BASE}${path}`, {
method,
headers: h,
body: body ? JSON.stringify(body) : undefined,
});
const json = await res.json();
if (!res.ok) throw new Error(`[${json.error?.code}] ${json.error?.message}`);
return json.data;
}
async function main() {
// 1. Create user
const user = await req('POST', '/users', {
external_user_id: 'usr_8821',
name: 'Maria Santos',
language: 'en',
});
const uid = user.id;
console.log('User created:', uid);
// 2. Financial intake
const intake = await req('POST', `/users/${uid}/financial-intake`, {
monthly_income: 5000,
monthly_expenses: 3200,
financial_goal: 'savings',
});
console.log('Intake submitted | surplus:', intake.monthly_surplus);
// 3. Personality quiz
const { questions } = await req('GET', '/personality/questions');
console.log('Quiz questions:', questions.length);
const score = await req('POST', '/personality/score', {
answers: [
{ question_id: questions[0].id, option_id: questions[0].options[1].id },
],
});
const personalityType = score.personality_type;
console.log('Personality:', personalityType);
// Store personalityType in your database
// 4. Generate plan
const plan = await req('POST', `/users/${uid}/plan/generate`, {
personality_type: personalityType,
});
const planTier = plan.plan_tier;
console.log('Plan tier:', planTier);
// 5. Financial profile
const profile = await req('GET', `/users/${uid}/financial-profile?personality_type=${personalityType}`);
console.log('Daily living envelope:', profile.envelopes.daily_living);
// 6. Chat
const reply = await req('POST', `/users/${uid}/chat/completion`, {
message: 'Am I on track?',
personality_type: personalityType,
});
console.log('Chat reply:', reply.content.slice(0, 80) + '...');
// 7. Parse a transaction
const txResult = await req('POST', '/transactions/parse', {
type: 'text',
content: 'Coffee $5.50',
});
console.log('Transactions parsed:', txResult.transactions.length);
// 8. Generate money moves
const moves = await req('POST', '/money-moves/generate', {
user_id: uid,
personality_type: personalityType,
plan_tier: planTier,
});
console.log('Money move tasks:', moves.tasks.length);
}
main().catch(err => {
console.error('Integration failed:', err.message);
process.exit(1);
});