Plano
O Plano é a saída central do mecanismo de análise financeira do Ozzie. Ele recebe os dados de intake financeiro do usuário (renda, despesas, dívidas, metas) e produz um roteiro estruturado com alocações orçamentárias, marcos projetados e itens de ação priorizados.
O plano é o pré-requisito para gerar money moves e molda todas as respostas do coach de IA no chat.
Referência do objeto
| Campo | Tipo | Descrição |
|---|---|---|
id | string | Identificador único do plano |
user_id | string | O usuário Ozzie a quem este plano pertence |
timeline_months | integer | Meses projetados para atingir o objetivo principal do usuário |
allocations | object | Divisão orçamentária JSONB por categoria (percentuais) |
allocations.needs | number | % da renda líquida alocada para necessidades essenciais |
allocations.wants | number | % da renda líquida alocada para gastos discricionários |
allocations.savings | number | % da renda líquida alocada para poupança |
allocations.debt | number | % da renda líquida alocada para pagamento de dívidas |
key_metrics | object | Principais indicadores financeiros projetados |
key_metrics.monthly_savings_amount | number | Valor em dinheiro economizado por mês sob este plano |
key_metrics.projected_goal_date | string (ISO 8601) | Data estimada em que o usuário atinge sua meta |
key_metrics.current_savings_rate | number | Taxa de poupança atual como percentual da renda |
key_metrics.target_savings_rate | number | Taxa de poupança recomendada para atingir a meta no prazo |
key_metrics.debt_payoff_date | string (ISO 8601) | null | Data projetada de quitação de dívida (se a meta for dívida) |
action_items | string[] | Lista ordenada de próximas ações recomendadas |
personality_type | string | null | Perfil de personalidade aplicado (se personalizado) |
created_at | string (ISO 8601) | Quando o plano foi gerado |
updated_at | string (ISO 8601) | Quando o plano foi atualizado pela última vez |
POST /v1/users/{user_id}/plan
Calcula um novo plano financeiro para o usuário, ou recupera e atualiza um existente. Se já existe um plano, chamar este endpoint o recalcula com base no intake e dados de transações mais recentes.
Este endpoint requer que um intake financeiro exista para o usuário. Se nenhum intake foi enviado, você receberá um erro INTAKE_REQUIRED.
A geração de plano é idempotente por usuário. Você pode chamar este endpoint com segurança várias vezes — o Ozzie retornará o plano mais atual, recalculando se novos dados de intake ou transações foram enviados desde a última geração.
Parâmetros de caminho
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
user_id | string | Sim | O ID do usuário Ozzie |
Corpo da requisição
Nenhum corpo de requisição necessário. O Ozzie lê todos os dados do intake e transações existentes do usuário.
Requisição
- curl
- Node.js
- Python
curl -X POST https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/plan \
-H "Authorization: Bearer ozp_Y2xpZW50X2ExYjJjM2Q0OnNrX2xpdmVfeEs5bVAycVI3dEwu" \
-H "Content-Type: application/json"
const token = Buffer.from(
`${process.env.OZZIE_CLIENT_ID}:${process.env.OZZIE_CLIENT_SECRET}`
).toString('base64');
const response = await fetch(
'https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/plan',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
}
);
const { data } = await response.json();
console.log(data);
import base64, os, httpx
token = base64.b64encode(
f"{os.environ['OZZIE_CLIENT_ID']}:{os.environ['OZZIE_CLIENT_SECRET']}".encode()
).decode()
response = httpx.post(
"https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/plan",
headers={"Authorization": f"Bearer {token}"},
)
print(response.json()["data"])
Resposta
{
"object": "plan",
"data": {
"id": "pln_8b3d1e9f2a",
"user_id": "usr_4f8a1b2c3d",
"timeline_months": 57,
"allocations": {
"needs": 60,
"wants": 20,
"savings": 15,
"debt": 5
},
"key_metrics": {
"monthly_savings_amount": 562.50,
"projected_goal_date": "2029-11-01T00:00:00Z",
"current_savings_rate": 8,
"target_savings_rate": 15,
"debt_payoff_date": null
},
"action_items": [
"Aumente sua contribuição de poupança de 8% para 15% da renda líquida — comece com R$562,50/mês",
"Reduza os gastos discricionários (atualmente 28%) para 20% cortando saídas para comer e assinaturas de streaming",
"Configure uma transferência automática no dia do pagamento para que a poupança aconteça antes de gastar",
"Revise seus gastos com alimentação — você está R$120/mês acima de uma linha de base razoável para sua renda",
"Quando seu fundo de emergência atingir R$3.000, considere abrir uma conta poupança de alto rendimento"
],
"personality_type": null,
"created_at": "2025-05-05T14:50:00Z",
"updated_at": "2025-05-05T14:50:00Z"
}
}
Erros
| Código | Status HTTP | Quando ocorre |
|---|---|---|
UNAUTHORIZED | 401 | Credenciais ausentes ou inválidas |
NOT_FOUND | 404 | O usuário não existe |
INTAKE_REQUIRED | 422 | Nenhum intake financeiro existe para o usuário |
INTERNAL_ERROR | 500 | Falha no cálculo do plano — seguro para tentar novamente |
POST /v1/users/{user_id}/plan/personalize
Ajusta o plano existente do usuário com base em um perfil de personalidade. Planos com consciência de personalidade ajustam a linguagem, ritmo e ênfase das recomendações para combinar com a forma como o usuário pensa sobre dinheiro.
A personalização requer que um plano já exista. Chame POST /plan primeiro, depois chame /plan/personalize para adicionar o perfil de personalidade.
Parâmetros de caminho
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
user_id | string | Sim | O ID do usuário Ozzie |
Corpo da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
personality_type | string | Sim | O identificador do perfil de personalidade (ex.: "optimizer", "avoider", "planner", "spender") |
Tipos de personalidade
| Tipo | Descrição |
|---|---|
"optimizer" | Orientado a dados, motivado por eficiência e retornos máximos |
"planner" | Metódico, prefere roteiros detalhados e previsibilidade |
"avoider" | Ansioso com finanças; precisa de reasseguramento e pequenas vitórias |
"spender" | Orientado ao estilo de vida; precisa de estratégias que não pareçam privação |
Requisição
- curl
- Node.js
- Python
curl -X POST https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/plan/personalize \
-H "Authorization: Bearer ozp_Y2xpZW50X2ExYjJjM2Q0OnNrX2xpdmVfeEs5bVAycVI3dEwu" \
-H "Content-Type: application/json" \
-d '{
"personality_type": "avoider"
}'
const token = Buffer.from(
`${process.env.OZZIE_CLIENT_ID}:${process.env.OZZIE_CLIENT_SECRET}`
).toString('base64');
const response = await fetch(
'https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/plan/personalize',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ personality_type: 'avoider' }),
}
);
const { data } = await response.json();
console.log(data.action_items);
import base64, os, httpx
token = base64.b64encode(
f"{os.environ['OZZIE_CLIENT_ID']}:{os.environ['OZZIE_CLIENT_SECRET']}".encode()
).decode()
response = httpx.post(
"https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/plan/personalize",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
json={"personality_type": "avoider"},
)
print(response.json()["data"]["action_items"])
Resposta
Retorna o plano atualizado com o perfil de personalidade aplicado. Observe como os action_items mudam para passos mais suaves e menores para um perfil "avoider".
{
"object": "plan",
"data": {
"id": "pln_8b3d1e9f2a",
"user_id": "usr_4f8a1b2c3d",
"timeline_months": 57,
"allocations": {
"needs": 60,
"wants": 20,
"savings": 15,
"debt": 5
},
"key_metrics": {
"monthly_savings_amount": 562.50,
"projected_goal_date": "2029-11-01T00:00:00Z",
"current_savings_rate": 8,
"target_savings_rate": 15,
"debt_payoff_date": null
},
"action_items": [
"Você já está poupando — isso é algo para se sentir bem. Vamos apenas crescer um pouco mais.",
"Tente transferir apenas R$50 a mais por pagamento para poupança este mês. Um pequeno passo.",
"Você não precisa cortar tudo. Escolha uma despesa esta semana que pareceu esquecível e pause.",
"Configure uma transferência automática de R$50 no dia do pagamento — você não vai notar, mas sua poupança vai.",
"Sua meta é alcançável. Neste ritmo você terá R$3.000 economizados em 6 meses."
],
"personality_type": "avoider",
"created_at": "2025-05-05T14:50:00Z",
"updated_at": "2025-05-05T15:10:00Z"
}
}
Erros
| Código | Status HTTP | Quando ocorre |
|---|---|---|
UNAUTHORIZED | 401 | Credenciais ausentes ou inválidas |
NOT_FOUND | 404 | O usuário não existe |
PLAN_REQUIRED | 422 | Nenhum plano existe ainda — chame POST /plan primeiro |
PERSONALITY_REQUIRED | 422 | Campo personality_type ausente no corpo da requisição |
VALIDATION_ERROR | 422 | Valor de personality_type desconhecido |
INVALID_JSON | 400 | Corpo da requisição não é JSON válido |
Você pode determinar o tipo de personalidade de um usuário realizando um quiz curto no seu fluxo de onboarding e depois passando o resultado aqui. O string personality_type é armazenado no plano e refletido em todas as respostas subsequentes do coach de IA para esse usuário.