Usuarios
El objeto User es la entidad raíz en Ozzie. Todos los demás recursos — intakes financieros, planes, metas, transacciones, mensajes de chat — tienen alcance para un usuario. Creas un usuario por persona en tu sistema, identificado por tu propio external_user_id.
El Objeto User
{
"object": "user",
"data": {
"id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"name": "Carlos García",
"email": "carlos@ejemplo.com",
"phone": "+5491187654321",
"language": "es",
"onboarding_stage": "active",
"created_at": "2025-05-05T14:30:00Z"
}
}
Campos del Objeto User
| Campo | Tipo | Descripción |
|---|---|---|
id | string | UUID generado por Ozzie para este usuario. Úsalo en todas las rutas de API subsiguientes. |
external_user_id | string | Tu ID de usuario interno. Único por cliente de API. |
name | string | null | Nombre de visualización del usuario. |
email | string | null | Dirección de correo electrónico del usuario. |
phone | string | null | Número de teléfono del usuario en formato E.164. Requerido para integración con WhatsApp. |
language | string | Preferencia de idioma: "en", "pt" o "es". |
onboarding_stage | string | Estado actual del onboarding (ver tabla abajo). |
created_at | string | Timestamp UTC ISO 8601 de cuando se creó el usuario. |
Valores de onboarding_stage
| Valor | Significado |
|---|---|
intake_pending | Usuario creado, ningún intake financiero enviado aún |
plan_pending | Intake enviado, plan aún no generado |
active | Plan generado — acceso completo a la plataforma disponible |
POST /v1/users
Crea un nuevo usuario bajo tu cliente de API. Cada usuario debe tener un external_user_id único dentro de tu cuenta de cliente.
Cuerpo de la Solicitud
| Campo | Tipo | Requerido | Restricciones | Descripción |
|---|---|---|---|---|
external_user_id | string | Sí | Máx 100 chars | Tu ID de usuario interno (ej.: clave primaria de base de datos o UUID) |
name | string | No | Máx 200 chars | Nombre de visualización del usuario |
email | string | No | Formato de email válido | Dirección de correo electrónico del usuario |
phone | string | No | Formato E.164 | Número de teléfono, ej.: +5491187654321. Requerido para WhatsApp. |
language | string | No | "en" | "pt" | "es" | Idioma del chat y notificaciones. Predeterminado "en". |
Respuesta
Devuelve el objeto user creado con HTTP 201 Created.
Errores
| Código | HTTP | Cuándo |
|---|---|---|
CONFLICT | 409 | Ya existe un usuario con este external_user_id bajo tu cliente |
VALIDATION_ERROR | 400 | Un campo falló en la validación (ej.: formato de email inválido, teléfono no en E.164) |
UNAUTHORIZED | 401 | Credenciales ausentes o inválidas |
Ejemplos
- curl
- Node.js
- Python
curl -X POST https://api.ozzieapp.com/v1/users \
-H "Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=" \
-H "Content-Type: application/json" \
-d '{
"external_user_id": "usr_8821",
"name": "Carlos García",
"email": "carlos@ejemplo.com",
"phone": "+5491187654321",
"language": "es"
}'
import fetch from 'node-fetch';
const token = Buffer.from('tu_client_id:tu_client_secret').toString('base64');
const response = await fetch('https://api.ozzieapp.com/v1/users', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
external_user_id: 'usr_8821',
name: 'Carlos García',
email: 'carlos@ejemplo.com',
phone: '+5491187654321',
language: 'es',
}),
});
const { data: user } = await response.json();
console.log('Usuario creado:', user.id);
import requests
import base64
token = base64.b64encode(b'tu_client_id:tu_client_secret').decode()
response = requests.post(
'https://api.ozzieapp.com/v1/users',
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json',
},
json={
'external_user_id': 'usr_8821',
'name': 'Carlos García',
'email': 'carlos@ejemplo.com',
'phone': '+5491187654321',
'language': 'es',
}
)
user = response.json()['data']
print(f"Usuario creado: {user['id']}")
Ejemplo de Respuesta (201 Created):
{
"object": "user",
"data": {
"id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"name": "Carlos García",
"email": "carlos@ejemplo.com",
"phone": "+5491187654321",
"language": "es",
"onboarding_stage": "intake_pending",
"created_at": "2025-05-05T14:30:00Z"
}
}
Respuesta de Error — Usuario duplicado (409 Conflict):
{
"error": {
"code": "CONFLICT",
"message": "A user with external_user_id 'usr_8821' already exists under your API client. Use GET /v1/users/{user_id} to retrieve them."
}
}
Respuesta de Error — Email inválido (400 Validation Error):
{
"error": {
"code": "VALIDATION_ERROR",
"message": "Field 'email' must be a valid email address. Received: 'not-an-email'."
}
}
Si no estás seguro de si un usuario ya existe, captura el error CONFLICT e inmediatamente llama a GET /v1/users/external:{external_user_id} para recuperar el registro existente. Esto es seguro de hacer en un flujo estilo upsert.
GET /v1/users/{user_id}
Recupera un usuario por su UUID de Ozzie o por su external_user_id.
Parámetro de Ruta
| Parámetro | Descripción |
|---|---|
user_id | El UUID de Ozzie (ej.: ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE) o un ID externo con prefijo (ej.: external:usr_8821) |
Búsqueda por external_user_id
Para buscar un usuario por tu propio ID en lugar del UUID de Ozzie, prefija el valor con external::
GET /v1/users/external:usr_8821
Esto es equivalente a consultar por external_user_id y evita la necesidad de almacenar el UUID de Ozzie en tu base de datos en el momento de la creación.
Respuesta
Devuelve el objeto user con HTTP 200 OK.
Errores
| Código | HTTP | Cuándo |
|---|---|---|
NOT_FOUND | 404 | No existe ningún usuario con este ID bajo tu cliente |
UNAUTHORIZED | 401 | Credenciales ausentes o inválidas |
FORBIDDEN | 403 | El usuario existe pero pertenece a un cliente de API diferente |
Ejemplos
- curl
- Node.js
- Python
# Por UUID de Ozzie
curl https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE \
-H "Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ="
# Por external_user_id
curl "https://api.ozzieapp.com/v1/users/external:usr_8821" \
-H "Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ="
import fetch from 'node-fetch';
const token = Buffer.from('tu_client_id:tu_client_secret').toString('base64');
// Por UUID de Ozzie
const res = await fetch(
'https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE',
{ headers: { 'Authorization': `Bearer ${token}` } }
);
// Por external_user_id
const res2 = await fetch(
'https://api.ozzieapp.com/v1/users/external:usr_8821',
{ headers: { 'Authorization': `Bearer ${token}` } }
);
const { data: user } = await res.json();
console.log('Etapa de onboarding:', user.onboarding_stage);
import requests
import base64
token = base64.b64encode(b'tu_client_id:tu_client_secret').decode()
headers = {'Authorization': f'Bearer {token}'}
# Por UUID de Ozzie
response = requests.get(
'https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE',
headers=headers
)
# Por external_user_id
response2 = requests.get(
'https://api.ozzieapp.com/v1/users/external:usr_8821',
headers=headers
)
user = response.json()['data']
print(f"Etapa de onboarding: {user['onboarding_stage']}")
Ejemplo de Respuesta (200 OK):
{
"object": "user",
"data": {
"id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"external_user_id": "usr_8821",
"name": "Carlos García",
"email": "carlos@ejemplo.com",
"phone": "+5491187654321",
"language": "es",
"onboarding_stage": "active",
"created_at": "2025-05-05T14:30:00Z"
}
}
Respuesta de Error — No encontrado (404):
{
"error": {
"code": "NOT_FOUND",
"message": "No user found with id 'ozz_usr_NOTEXIST' under your API client."
}
}
Usa GET /v1/users/{user_id} para verificar el onboarding_stage de un usuario antes de decidir qué UI mostrar. Si el estado es intake_pending, solicita al usuario sus detalles financieros. Si plan_pending, muestra un estado de carga mientras activas la generación del plan.