Money Moves
Money Moves são ciclos de ação financeira estruturados e com prazo definido, entregues aos usuários na cadência escolhida (semanal, quinzenal, etc.). Cada ciclo contém um conjunto de tarefas em três categorias:
| Tipo de tarefa | Descrição |
|---|---|
"do" | Uma ação financeira concreta com um valor associado (ex.: transferir R$150 para poupança) |
"learn" | Uma tarefa curta de educação financeira adaptada à situação do usuário |
"mind" | Um exercício de mentalidade ou reflexão para construir hábitos financeiros saudáveis |
Money Moves requerem que um plano financeiro exista primeiro. Use POST /v1/users/{user_id}/plan antes de chamar /money-moves/generate.
Referência do objeto
Objeto Cycle
| Campo | Tipo | Descrição |
|---|---|---|
id | string | Identificador único do ciclo |
user_id | string | O usuário Ozzie a quem este ciclo pertence |
due_date | string (ISO 8601) | A data até a qual as tarefas deste ciclo devem ser concluídas |
cadence | "weekly" | "biweekly" | "twice_monthly" | "monthly" | A frequência da qual este ciclo faz parte |
status | "scheduled" | "available" | "completed" | "skipped" | Estado atual do ciclo |
tasks | Task[] | A lista de tarefas neste ciclo |
created_at | string (ISO 8601) | Quando o ciclo foi gerado |
Objeto Task
| Campo | Tipo | Descrição |
|---|---|---|
id | string | Identificador único da tarefa |
task_type | "do" | "learn" | "mind" | A categoria da tarefa |
title | string | Descrição legível da tarefa |
amount_cents | integer | null | Valor em centavos (apenas presente para tarefas "do") |
status | "pending" | "done" | "skipped" | Se a tarefa foi concluída |
completed_at | string (ISO 8601) | null | Quando a tarefa foi marcada como concluída (null se pendente/pulada) |
GET /v1/users/{user_id}/money-moves
Lista todos os ciclos de money move de um usuário. Suporta filtragem por status e paginação baseada em cursor.
Parâmetros de caminho
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
user_id | string | Sim | O ID do usuário Ozzie |
Parâmetros de query
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
status | "scheduled" | "available" | "completed" | "skipped" | Não | Filtrar ciclos por status |
limit | integer | Não | Número de ciclos a retornar. Padrão: 10. Máx: 50. |
cursor | string | Não | Cursor de paginação de uma resposta anterior next_cursor |
Requisição
- curl
- Node.js
- Python
curl "https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/money-moves?status=available&limit=5" \
-H "Authorization: Bearer ozp_Y2xpZW50X2ExYjJjM2Q0OnNrX2xpdmVfeEs5bVAycVI3dEwu"
const token = Buffer.from(
`${process.env.OZZIE_CLIENT_ID}:${process.env.OZZIE_CLIENT_SECRET}`
).toString('base64');
const params = new URLSearchParams({ status: 'available', limit: '5' });
const response = await fetch(
`https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/money-moves?${params}`,
{
headers: { 'Authorization': `Bearer ${token}` },
}
);
const { data, pagination } = 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.get(
"https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/money-moves",
params={"status": "available", "limit": 5},
headers={"Authorization": f"Bearer {token}"},
)
result = response.json()
print(result["data"])
Resposta
{
"object": "list",
"data": [
{
"id": "mmv_3a7c9e1b2d",
"user_id": "usr_4f8a1b2c3d",
"due_date": "2025-05-19T23:59:59Z",
"cadence": "biweekly",
"status": "available",
"created_at": "2025-05-05T14:40:00Z",
"tasks": [
{
"id": "tsk_1a2b3c4d5e",
"task_type": "do",
"title": "Transfira R$150 para sua conta poupança de Fundo de Emergência",
"amount_cents": 15000,
"status": "pending",
"completed_at": null
},
{
"id": "tsk_2b3c4d5e6f",
"task_type": "learn",
"title": "Leia: Por que R$3.000 é o primeiro marco certo para um fundo de emergência",
"amount_cents": null,
"status": "pending",
"completed_at": null
},
{
"id": "tsk_3c4d5e6f7g",
"task_type": "mind",
"title": "Escreva uma coisa com que você se sentiria menos estressado tendo R$10.000 em poupança",
"amount_cents": null,
"status": "pending",
"completed_at": null
}
]
}
],
"pagination": {
"has_more": false,
"next_cursor": null
}
}
Erros
| Código | Status HTTP | Quando ocorre |
|---|---|---|
UNAUTHORIZED | 401 | Credenciais ausentes ou inválidas |
NOT_FOUND | 404 | O usuário não existe |
VALIDATION_ERROR | 422 | Valor de status inválido ou limit fora do intervalo |
POST /v1/users/{user_id}/money-moves/generate
Aciona a geração do próximo ciclo de money move para o usuário. A IA do Ozzie analisa o plano atual, meta e histórico de transações do usuário para produzir um novo conjunto de tarefas personalizadas.
Este endpoint requer que um plano financeiro já exista para o usuário. Chame POST /v1/users/{user_id}/plan primeiro. Se nenhum plano existir, você receberá um erro PLAN_REQUIRED.
Cada chamada gera exatamente um novo ciclo. O ciclo é colocado em status "scheduled" e se torna "available" na sua due_date.
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.
Requisição
- curl
- Node.js
- Python
curl -X POST https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/money-moves/generate \
-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/money-moves/generate',
{
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/money-moves/generate",
headers={"Authorization": f"Bearer {token}"},
)
print(response.json()["data"])
Resposta
Retorna o ciclo recém-gerado com todas as suas tarefas.
{
"object": "money_move",
"data": {
"id": "mmv_5d8f2a4b9c",
"user_id": "usr_4f8a1b2c3d",
"due_date": "2025-06-02T23:59:59Z",
"cadence": "biweekly",
"status": "scheduled",
"created_at": "2025-05-05T14:45:00Z",
"tasks": [
{
"id": "tsk_4d5e6f7g8h",
"task_type": "do",
"title": "Transfira R$150 para seu Fundo de Emergência — você já está 12% do caminho!",
"amount_cents": 15000,
"status": "pending",
"completed_at": null
},
{
"id": "tsk_5e6f7g8h9i",
"task_type": "learn",
"title": "Leia: Como automatizar sua poupança para nunca esquecer uma transferência",
"amount_cents": null,
"status": "pending",
"completed_at": null
},
{
"id": "tsk_6f7g8h9i0j",
"task_type": "mind",
"title": "Reflita: Qual é uma assinatura que você manteve mas mal usou este mês?",
"amount_cents": null,
"status": "pending",
"completed_at": null
}
]
}
}
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 financeiro existe para o usuário |
INTERNAL_ERROR | 500 | Falha na geração de IA — seguro para tentar novamente |
GET /v1/users/{user_id}/money-moves/{move_id}
Recupera um único ciclo de money move por ID, incluindo todas as suas tarefas.
Parâmetros de caminho
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
user_id | string | Sim | O ID do usuário Ozzie |
move_id | string | Sim | O ID do ciclo de money move |
Requisição
- curl
- Node.js
- Python
curl https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/money-moves/mmv_3a7c9e1b2d \
-H "Authorization: Bearer ozp_Y2xpZW50X2ExYjJjM2Q0OnNrX2xpdmVfeEs5bVAycVI3dEwu"
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/money-moves/mmv_3a7c9e1b2d',
{
headers: { 'Authorization': `Bearer ${token}` },
}
);
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.get(
"https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/money-moves/mmv_3a7c9e1b2d",
headers={"Authorization": f"Bearer {token}"},
)
print(response.json()["data"])
Erros
| Código | Status HTTP | Quando ocorre |
|---|---|---|
UNAUTHORIZED | 401 | Credenciais ausentes ou inválidas |
NOT_FOUND | 404 | Usuário ou ciclo de money move não encontrado |
PATCH /v1/users/{user_id}/money-moves/{move_id}
Atualiza o status de um ciclo de money move. Use isso para marcar um ciclo como concluído ou pulado quando o usuário termina suas tarefas ou opta por não fazer o ciclo atual.
Parâmetros de caminho
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
user_id | string | Sim | O ID do usuário Ozzie |
move_id | string | Sim | O ID do ciclo de money move |
Corpo da requisição
| Campo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
status | "completed" | "skipped" | Sim | O novo status do ciclo |
Requisição
- curl
- Node.js
- Python
curl -X PATCH https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/money-moves/mmv_3a7c9e1b2d \
-H "Authorization: Bearer ozp_Y2xpZW50X2ExYjJjM2Q0OnNrX2xpdmVfeEs5bVAycVI3dEwu" \
-H "Content-Type: application/json" \
-d '{
"status": "completed"
}'
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/money-moves/mmv_3a7c9e1b2d',
{
method: 'PATCH',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ status: 'completed' }),
}
);
const { data } = await response.json();
console.log(data.status); // "completed"
import base64, os, httpx
token = base64.b64encode(
f"{os.environ['OZZIE_CLIENT_ID']}:{os.environ['OZZIE_CLIENT_SECRET']}".encode()
).decode()
response = httpx.patch(
"https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/money-moves/mmv_3a7c9e1b2d",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
json={"status": "completed"},
)
print(response.json()["data"]["status"]) # "completed"
Resposta
Retorna o objeto de ciclo atualizado.
{
"object": "money_move",
"data": {
"id": "mmv_3a7c9e1b2d",
"user_id": "usr_4f8a1b2c3d",
"due_date": "2025-05-19T23:59:59Z",
"cadence": "biweekly",
"status": "completed",
"created_at": "2025-05-05T14:40:00Z",
"tasks": [
{
"id": "tsk_1a2b3c4d5e",
"task_type": "do",
"title": "Transfira R$150 para sua conta poupança de Fundo de Emergência",
"amount_cents": 15000,
"status": "done",
"completed_at": "2025-05-06T09:15:00Z"
},
{
"id": "tsk_2b3c4d5e6f",
"task_type": "learn",
"title": "Leia: Por que R$3.000 é o primeiro marco certo para um fundo de emergência",
"amount_cents": null,
"status": "done",
"completed_at": "2025-05-07T20:30:00Z"
},
{
"id": "tsk_3c4d5e6f7g",
"task_type": "mind",
"title": "Escreva uma coisa com que você se sentiria menos estressado tendo R$10.000 em poupança",
"amount_cents": null,
"status": "done",
"completed_at": "2025-05-07T20:35:00Z"
}
]
}
}
Erros
| Código | Status HTTP | Quando ocorre |
|---|---|---|
UNAUTHORIZED | 401 | Credenciais ausentes ou inválidas |
NOT_FOUND | 404 | Usuário ou ciclo de money move não encontrado |
VALIDATION_ERROR | 422 | Valor de status inválido, ou ciclo já está em estado terminal |
INVALID_JSON | 400 | Corpo da requisição não é JSON válido |
Após marcar um ciclo como "completed" ou "skipped", você pode imediatamente chamar POST /money-moves/generate para enfileirar o próximo ciclo. Isso mantém as listas de tarefas dos seus usuários atualizadas sem lacunas.