Skip to main content

Chat

POST /v1/users/:user_id/chat/completion is a stateless AI chat inference endpoint. The caller provides the user's message, conversation history, and personality type. The intelligence layer returns a reply without storing anything.

Your application is responsible for storing conversation history and passing it in history on each call.


How it works​

  1. Your app loads the user's conversation history from your database
  2. Your app calls POST /v1/users/{user_id}/chat/completion with message, history, and personality type
  3. The intelligence layer returns an AI reply
  4. Your app stores both the user message and the reply
  5. On the next call, include the updated history

POST /v1/users/:user_id/chat/completion​

Send a message and receive a stateless AI reply.

Request body​

FieldTypeRequiredDescription
messagestringYesUser's message. Max 2000 characters.
historyarrayNoPrior conversation turns [{ role, content }]
personality_typestringNoHOTSHOT | STOCKPILER | GIVER | INDEPENDENT — shapes tone
languagestringNoOverride response language for this request
contextstringNoConversation context hint, e.g. "financial_planning"
user_contextobjectNoRich user snapshot — see user_context fields below

user_context fields​

All fields inside user_context are optional. Pass as many as you have available — richer context produces more personalized responses.

FieldTypeDescription
namestringUser's display name
languagestringUser's preferred language ("en" | "pt" | "es")
personality_typestringHOTSHOT | STOCKPILER | GIVER | INDEPENDENT
plan_tierstringPlan tier from the last plan generation, e.g. "20/80"
plan_speedstringPlan speed from the last plan generation: "conservative" | "moderate" | "aggressive"
monthly_incomenumberUser's gross monthly income
goal_progressobjectGoal snapshot — see below
goal_progress.target_amount_centsnumberGoal target in cents
goal_progress.total_contributed_centsnumberTotal contributed so far in cents
goal_progress.percentagenumberContribution percentage (0–100)
next_moveobjectUpcoming passo details
next_move.datestringISO date of the next money move, e.g. "2026-05-20"
next_move.amount_centsnumberNext move amount in cents
completed_moves_countnumberTotal passos completed by the user
total_saved_centsnumberTotal amount saved across all passos in cents
last_confirmation_notestringFree-text note the user left on their last passo confirmation
entry_pointstringWhere the user arrived from — shapes Ozzie's opening message. See entry_point values
spending_alert_envelopestringEnvelope name for a spending alert, e.g. "lifestyle" (used with entry_point: "spending_alert")
spending_alert_rationumberRatio of actual to allocated spending, e.g. 1.25 means 25% over budget
rag_contextstringFree-text retrieval context injected into the AI prompt, e.g. behavioral patterns from your database

entry_point values​

entry_point tells Ozzie where the user arrived from. Ozzie uses it to generate a context-aware opening message returned as entry_point_opener in the response.

entry_pointWhen to useOzzie opens with
weekly_expenseUser arrives from a WhatsApp weekly expense promptAsks for expenses with input options
spending_alertUser arrives from a push notification about overspendingReferences the specific envelope (spending_alert_envelope) and asks about recalibration
monthly_reviewUser arrives from a WhatsApp monthly review linkSummarizes last month and asks about this month
move_reminderUser arrives from a WhatsApp money move reminderReturns entry_point_opener: null — the channel renders the passo confirmation card instead
unpromptedUser opens the app directly (default when no entry_point is provided)Personalized greeting referencing last passo and total saved

When no entry_point is provided, entry_point_opener is null in the response.

curl -X POST https://channel.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/chat/completion \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"message": "How am I doing with my savings goal?",
"personality_type": "STOCKPILER",
"language": "en"
}'

Response​

FieldTypeDescription
objectstringAlways "chat_completion"
data.contentstringAI reply text
data.entry_point_openerstring | nullPre-built opening message for the session. Not null when entry_point was provided and is not move_reminder. Null for move_reminder (channel renders the passo card) and when no entry_point was sent.
data.contextstringActive conversation context
{
"object": "chat_completion",
"data": {
"role": "assistant",
"content": "You're on track. Your STOCKPILER profile means consistent, automated saving is your edge — keep that monthly transfer running and you'll hit your monthly target comfortably.",
"entry_point_opener": null,
"context": "general",
"created_at": "2026-05-15T10:10:00Z"
}
}

entry_point examples​

unprompted — app opened directly​

Request:

{
"message": "oi",
"user_context": {
"name": "Ramon",
"language": "pt",
"personality_type": "STOCKPILER",
"completed_moves_count": 8,
"total_saved_cents": 125000,
"next_move": {
"date": "2026-05-20",
"amount_cents": 20000
},
"entry_point": "unprompted"
}
}

Response:

{
"object": "chat_completion",
"data": {
"content": "Oi Ramon! 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 Ramon! 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"
}
}

weekly_expense — arrived from WhatsApp prompt​

Request:

{
"message": "",
"user_context": {
"name": "Ramon",
"language": "pt",
"entry_point": "weekly_expense"
}
}

Response:

{
"object": "chat_completion",
"data": {
"content": "Ramon, vamos registrar seus gastos da semana! Me conta o que você gastou — pode ser no formato livre ou escolha uma categoria para começar.",
"entry_point_opener": "Ramon, vamos registrar seus gastos da semana! Me conta o que você gastou — pode ser no formato livre ou escolha uma categoria para começar.",
"context": "weekly_expense"
}
}

spending_alert — arrived from overspending push notification​

Request:

{
"message": "",
"user_context": {
"name": "Ramon",
"language": "pt",
"entry_point": "spending_alert",
"spending_alert_envelope": "lifestyle",
"spending_alert_ratio": 1.25
}
}

Response:

{
"object": "chat_completion",
"data": {
"content": "Ramon, seu envelope lifestyle está 25% acima do planejado este mês. Quer recalibrar ou conversar sobre o que aconteceu?",
"entry_point_opener": "Ramon, seu envelope lifestyle está 25% acima do planejado este mês. Quer recalibrar ou conversar sobre o que aconteceu?",
"context": "spending_alert"
}
}

Request:

{
"message": "",
"user_context": {
"name": "Ramon",
"language": "pt",
"entry_point": "monthly_review",
"goal_progress": {
"target_amount_cents": 500000,
"total_contributed_cents": 125000,
"percentage": 25
}
}
}

Response:

{
"object": "chat_completion",
"data": {
"content": "Ramon, o mês passou! Você contribuiu $1,250 e está 25% do caminho para sua meta. O que você quer priorizar no próximo mês?",
"entry_point_opener": "Ramon, o mês passou! Você contribuiu $1,250 e está 25% do caminho para sua meta. O que você quer priorizar no próximo mês?",
"context": "monthly_review"
}
}

move_reminder — arrived from WhatsApp passo reminder​

Request:

{
"message": "",
"user_context": {
"name": "Ramon",
"language": "pt",
"entry_point": "move_reminder",
"next_move": {
"date": "2026-05-20",
"amount_cents": 20000
}
}
}

Response:

{
"object": "chat_completion",
"data": {
"content": null,
"entry_point_opener": null,
"context": "move_reminder"
}
}

entry_point_opener is null for move_reminder because the channel (WhatsApp or the app) is responsible for rendering the passo confirmation card. Ozzie does not generate an opening text for this flow.

Errors​

CodeHTTPWhen
UNAUTHORIZED401Missing or invalid credentials
NOT_FOUND404User does not exist
VALIDATION_ERROR400message missing or exceeds 2000 characters
RATE_LIMIT_EXCEEDED429Too many chat requests

Personality-aware coaching​

The AI coach adapts its responses based on the personality_type you pass. Examples:

STOCKPILER asking about savings progress:

"You've built $750 of your $1,500 monthly target — exactly on pace. Your STOCKPILER profile means this consistency compounds. Keep the automation running and you'll hit your emergency fund milestone in 8 months."

HOTSHOT asking about the same:

"You're at 50% of your monthly savings target. That's solid, but if you redirect your $300 lifestyle envelope surplus this month, you'd hit 70% — which puts your investment timeline 3 weeks ahead of schedule."

GIVER asking about spending on family:

"Your people envelope has $285 left this month — well within your $375 allocation. Spending on family is part of your GIVER profile, not a deviation from your plan."


GET /v1/users/:user_id/chat/messages​

Returns the full conversation history for a user. This is an alias for the channel-stored chat log — the same messages the channel injects into history on each POST /chat/completion call.

curl https://channel.ozzieapp.com/v1/users/external:usr_8821/chat/messages \
-H "Authorization: Bearer YOUR_TOKEN"

Response (200 OK):

{
"object": "chat_history",
"data": {
"messages": [
{
"role": "user",
"content": "Como estou indo?",
"created_at": "2026-05-16T10:00:00Z"
},
{
"role": "assistant",
"content": "Você está no caminho certo.",
"created_at": "2026-05-16T10:00:01Z"
}
]
}
}

Errors:

CodeHTTPWhen
UNAUTHORIZED401Missing or invalid credentials
NOT_FOUND404User does not exist