Chat
The Chat endpoint lets users send messages to Ozzie's AI financial coach. The coach maintains full awareness of the user's financial context — including their intake, transaction history, current plan, goals, and money moves — and responds with personalized, actionable guidance.
Every response includes structured metadata alongside the reply text, making it easy to build rich UI experiences on top of the conversation.
How the coach works
The AI coach is not a generic chatbot. For each message it receives, it:
- Loads the user's complete financial profile (intake, transactions, plan, goals)
- Identifies the intent and topic of the message
- Responds in the user's configured language
- Returns metadata (
emotion,topic,intent) that your UI can use to adapt the experience
The coach adapts its tone based on the user's personality_type if one has been set via POST /plan/personalize.
Object reference
Request
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | The user's message to the coach. Max 2000 characters. |
Response
| Field | Type | Description |
|---|---|---|
reply | string | The coach's response in the user's configured language |
emotion | string | The emotional tone of the reply (e.g., "encouraging", "neutral", "cautious", "celebratory") |
topic | string | The financial topic the message relates to (e.g., "savings", "spending", "goals", "debt", "general") |
intent | string | Classified intent of the user's message (e.g., "progress_check", "advice_request", "transaction_log", "goal_update", "emotional_support") |
POST /v1/users/{user_id}/chat/messages
Sends a message to the AI financial coach on behalf of a user and returns the coach's response.
Path parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
user_id | string | Yes | The Ozzie user ID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | The text message from the user |
Request
- curl
- Node.js
- Python
curl -X POST https://api.ozzieapp.com/v1/users/usr_4f8a1b2c3d/chat/messages \
-H "Authorization: Bearer ozp_Y2xpZW50X2ExYjJjM2Q0OnNrX2xpdmVfeEs5bVAycVI3dEwu" \
-H "Content-Type: application/json" \
-d '{
"message": "How am I doing with my savings goal?"
}'
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/chat/messages',
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
message: 'How am I doing with my savings goal?',
}),
}
);
const { data } = await response.json();
console.log(data.reply);
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/chat/messages",
headers={
"Authorization": f"Bearer {token}",
"Content-Type": "application/json",
},
json={"message": "How am I doing with my savings goal?"},
)
print(response.json()["data"]["reply"])
Response
{
"object": "chat_message",
"data": {
"reply": "You're making real progress! You've saved $1,200 toward your $10,000 Emergency Fund — that's 12% of your goal. At your current biweekly contribution of $150, you're on track to hit $3,000 within about 9 months. Your next scheduled transfer is May 19th. Want me to show you a few ways to accelerate this?",
"emotion": "encouraging",
"topic": "savings",
"intent": "progress_check"
}
}
Example conversations
Asking for spending advice
Request:
{
"message": "I feel like I'm spending too much on food. What should I do?"
}
Response:
{
"object": "chat_message",
"data": {
"reply": "You're right to notice this — food is your largest discretionary category this month at $680, which is about 18% of your net income. A reasonable target for someone with your income and goals is around $400–450/month. The biggest gap seems to be dining out ($310) versus groceries ($370). Meal prepping two or three dinners per week could realistically save you $80–100/month without feeling like a major sacrifice. Want me to add a specific food spending target to your plan?",
"emotion": "neutral",
"topic": "spending",
"intent": "advice_request"
}
}
Logging a transaction via chat
Request:
{
"message": "Just spent $45 on groceries at Whole Foods"
}
Response:
{
"object": "chat_message",
"data": {
"reply": "Got it — logged $45 at Whole Foods under Groceries. Your grocery total for May is now $215. You're on pace to stay within your food budget this month, which is great. Keep it up!",
"emotion": "encouraging",
"topic": "spending",
"intent": "transaction_log"
}
}
Requesting emotional support
Request:
{
"message": "I feel like I'm never going to get out of debt. It's overwhelming."
}
Response:
{
"object": "chat_message",
"data": {
"reply": "That feeling is completely valid — carrying debt is genuinely stressful. But here's what your numbers actually say: at your current $200/month repayment rate, you'll be debt-free in about 26 months. That's not forever — it's a finish line. And every payment you make shrinks that timeline. You've already paid down $850 since you started. Want to look at one small thing you could adjust to shave a few months off?",
"emotion": "cautious",
"topic": "debt",
"intent": "emotional_support"
}
}
Goal update via chat
Request:
{
"message": "I want to change my goal. I'd rather save for a vacation than pay off my credit card."
}
Response:
{
"object": "chat_message",
"data": {
"reply": "Totally reasonable — you get to decide what matters. Just so you have the full picture: your credit card balance is $2,100 and you're paying 19.9% APR, which means it's costing you about $35/month in interest. A vacation fund would grow faster if you cleared the card first. That said, if the vacation is a near-term priority that keeps you motivated, we can absolutely build a plan around that. Would you like me to run both scenarios so you can compare?",
"emotion": "neutral",
"topic": "goals",
"intent": "goal_update"
}
}
Response in Portuguese (for a pt-configured user)
Request:
{
"message": "Quanto economizei esse mês?"
}
Response:
{
"object": "chat_message",
"data": {
"reply": "Em maio você economizou R$680 até agora — isso é 14% da sua renda líquida, acima da sua meta de 12%. Ótimo ritmo! Se mantiver isso até o fim do mês, vai adicionar mais de R$800 ao seu fundo de emergência. Quer ver como isso afeta a data prevista para atingir sua meta?",
"emotion": "celebratory",
"topic": "savings",
"intent": "progress_check"
}
}
Errors
| Code | HTTP Status | When it occurs |
|---|---|---|
UNAUTHORIZED | 401 | Missing or invalid credentials |
NOT_FOUND | 404 | The user does not exist |
VALIDATION_ERROR | 422 | message field is missing or exceeds 2000 characters |
INVALID_JSON | 400 | Request body is not valid JSON |
INTAKE_REQUIRED | 422 | The user has no financial intake — the coach needs context to respond meaningfully |
RATE_LIMIT_EXCEEDED | 429 | Too many chat requests in the current window |
INTERNAL_ERROR | 500 | AI generation failed — safe to retry |
Use the topic and intent fields to enrich your UI. For example: show a savings chart widget when topic is "savings", play a subtle animation when emotion is "celebratory", or prompt the user to update their goal when intent is "goal_update".
The coach does not store conversation history between calls in the current API version. Each message is processed with the user's full financial context but without memory of previous chat turns. If your application needs a persistent conversation UI, maintain the message history on your side and optionally include relevant prior context in the message text.