Transacciones
Las transacciones son el flujo de datos central que alimenta el análisis de gastos, seguimiento de planes y recomendaciones personalizadas de Ozzie. Ozzie usa GPT-4o para analizar descripciones en lenguaje natural, imágenes de recibos (OCR), extractos bancarios en PDF y hojas de cálculo CSV en registros de transacciones estructurados y categorizados.
Un solo envío puede producir múltiples transacciones — por ejemplo, un mensaje de texto que diga "café $5 y almuerzo $15" producirá dos objetos de transacción separados.
El Objeto Transaction
{
"id": "ozz_txn_01HX9Q5NRWBF3KMZP4VC7YDLA",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"amount_cents": 4500,
"currency": "USD",
"category": "food",
"description": "Compras en el supermercado",
"transaction_date": "2025-05-05",
"source": "api_text",
"ai_confidence": 0.97,
"created_at": "2025-05-05T14:34:00Z"
}
Campos del Objeto Transaction
| Campo | Tipo | Descripción |
|---|---|---|
id | string | UUID generado por Ozzie para esta transacción |
user_id | string | El usuario Ozzie al que pertenece esta transacción |
amount_cents | integer | Monto de la transacción en centavos (ej.: 4500 = $45.00) |
currency | string | Código de moneda ISO 4217 (ej.: "USD", "BRL", "EUR") |
category | string | Categoría de gasto (ver tabla abajo) |
description | string | Descripción legible generada por IA de la transacción |
transaction_date | string | Fecha de la transacción en formato YYYY-MM-DD |
source | string | Cómo se envió la transacción (ver tabla abajo) |
ai_confidence | float | Puntuación de confianza del parsing de IA de 0.0 a 1.0 |
created_at | string | Timestamp UTC ISO 8601 de cuando se creó el registro en Ozzie |
Valores de category
| Valor | Descripción |
|---|---|
food | Supermercado, restaurantes, cafés, delivery de comida |
transport | Gasolina, transporte público, aplicaciones de transporte, estacionamiento, peajes |
housing | Alquiler, hipoteca, seguro de hogar, reparaciones |
utilities | Electricidad, agua, internet, factura de teléfono |
health | Farmacia, consultas médicas, gimnasio, seguro médico |
entertainment | Streaming, cine, juegos, eventos |
education | Matrícula, libros, cursos, suscripciones educativas |
clothing | Ropa, calzado, accesorios |
income | Salario, pago freelance, ingreso adicional, reembolso |
other | Cualquier cosa que no encaje en las categorías anteriores |
Valores de source
| Valor | Descripción |
|---|---|
whatsapp_text | Mensaje de texto recibido via WhatsApp |
whatsapp_image | Imagen (recibo/captura) recibida via WhatsApp |
api_text | Texto enviado via API REST |
api_image | Imagen enviada via API REST (base64) |
api_pdf | Texto extraído de PDF enviado via API REST |
api_spreadsheet | Datos CSV enviados via API REST |
POST /v1/users/{user_id}/transactions
Envía una o más transacciones para parsing. Ozzie usa GPT-4o para extraer datos estructurados de transacciones del contenido proporcionado. El campo type determina cómo se interpreta el contenido.
Parámetros de Ruta
| Parámetro | Descripción |
|---|---|
user_id | El UUID Ozzie del usuario o external:{external_user_id} |
Cuerpo de la Solicitud — Unión Discriminada por type
La forma del cuerpo de la solicitud depende del campo type. Todos los tipos comparten el campo language.
type: "text"
Envía una descripción en lenguaje natural de una o más transacciones.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
type | string | Sí | Debe ser "text" |
content | string | Sí | Descripción de transacción en lenguaje natural |
language | string | No | Sugerencia de idioma para parsing: "en" | "pt" | "es". Predeterminado: idioma del usuario. |
{
"type": "text",
"content": "Gasté $45 en el supermercado y $12 en el metro",
"language": "es"
}
type: "image"
Envía un recibo, captura de pantalla o foto de una compra como imagen codificada en base64. Ozzie realiza OCR y analiza el resultado.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
type | string | Sí | Debe ser "image" |
content | string | Sí | Datos de imagen codificados en base64 |
mime_type | string | Sí | Tipo MIME de la imagen: "image/jpeg" | "image/png" | "image/webp" |
language | string | No | Sugerencia de idioma para OCR y parsing |
{
"type": "image",
"content": "/9j/4AAQSkZJRgABAQEASABIAAD...",
"mime_type": "image/jpeg",
"language": "es"
}
type: "pdf"
Envía el contenido de texto extraído de un extracto bancario o recibo en PDF. Extrae el texto del PDF de tu lado antes de enviar.
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
type | string | Sí | Debe ser "pdf" |
content | string | Sí | Texto simple extraído del PDF |
language | string | No | Sugerencia de idioma para parsing |
{
"type": "pdf",
"content": "EXTRACTO BANCARIO\nFecha: 2025-05-01\nComercio: Amazon.com\nMonto: -$89.99\nFecha: 2025-05-02\nComercio: Netflix\nMonto: -$15.99",
"language": "es"
}
type: "spreadsheet"
Envía datos de transacción en formato CSV. Incluye una fila de encabezado. Ozzie normaliza nombres de columnas de forma flexible (ej.: Fecha / date / transaction_date son todos reconocidos).
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
type | string | Sí | Debe ser "spreadsheet" |
content | string | Sí | String CSV con fila de encabezado |
language | string | No | Sugerencia de idioma para parsing |
{
"type": "spreadsheet",
"content": "fecha,descripcion,monto\n2025-05-01,Supermercado,45.00\n2025-05-02,Metro,12.00\n2025-05-03,Netflix,15.99",
"language": "es"
}
Respuesta
Devuelve un objeto transaction_list que contiene todas las transacciones analizadas del envío.
{
"object": "transaction_list",
"data": {
"transactions": [ ... ]
}
}
Errores
| Código | HTTP | Cuándo |
|---|---|---|
NOT_FOUND | 404 | El user_id no existe |
VALIDATION_ERROR | 400 | Campos requeridos faltantes, type inválido o mime_type no soportado |
UNAUTHORIZED | 401 | Credenciales ausentes o inválidas |
Ejemplos — Entrada de Texto
- curl
- Node.js
- Python
curl -X POST \
https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/transactions \
-H "Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ=" \
-H "Content-Type: application/json" \
-d '{
"type": "text",
"content": "Gasté $45 en el supermercado y $12 en el metro",
"language": "es"
}'
import fetch from 'node-fetch';
const token = Buffer.from('tu_client_id:tu_client_secret').toString('base64');
const userId = 'ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE';
const response = await fetch(
`https://api.ozzieapp.com/v1/users/${userId}/transactions`,
{
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
type: 'text',
content: 'Gasté $45 en el supermercado y $12 en el metro',
language: 'es',
}),
}
);
const { data } = await response.json();
console.log(`Analizadas ${data.transactions.length} transacciones:`);
data.transactions.forEach(t => {
console.log(` • ${t.description}: $${(t.amount_cents / 100).toFixed(2)} [${t.category}]`);
});
import requests
import base64
token = base64.b64encode(b'tu_client_id:tu_client_secret').decode()
user_id = 'ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE'
response = requests.post(
f'https://api.ozzieapp.com/v1/users/{user_id}/transactions',
headers={
'Authorization': f'Bearer {token}',
'Content-Type': 'application/json',
},
json={
'type': 'text',
'content': 'Gasté $45 en el supermercado y $12 en el metro',
'language': 'es',
}
)
data = response.json()['data']
print(f"Analizadas {len(data['transactions'])} transacciones:")
for t in data['transactions']:
print(f" • {t['description']}: ${t['amount_cents'] / 100:.2f} [{t['category']}]")
Ejemplo de Respuesta — 2 transacciones analizadas de un mensaje de texto (201 Created):
{
"object": "transaction_list",
"data": {
"transactions": [
{
"id": "ozz_txn_01HX9Q5NRWBF3KMZP4VC7YDLA",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"amount_cents": 4500,
"currency": "USD",
"category": "food",
"description": "Compras en el supermercado",
"transaction_date": "2025-05-05",
"source": "api_text",
"ai_confidence": 0.97,
"created_at": "2025-05-05T14:34:00Z"
},
{
"id": "ozz_txn_01HX9Q5NRWBF3KMZP4VC7YDLB",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"amount_cents": 1200,
"currency": "USD",
"category": "transport",
"description": "Billete de metro",
"transaction_date": "2025-05-05",
"source": "api_text",
"ai_confidence": 0.95,
"created_at": "2025-05-05T14:34:00Z"
}
]
}
}
Ozzie analiza intencionalmente todas las transacciones distintas de una sola entrada. Una visita al supermercado más una parada en el café en el mismo mensaje producirá dos registros de transacción separados. Esto coincide con el uso real donde los usuarios describen su día en un solo mensaje.
Para imágenes de recibo, JPEG y PNG funcionan bien. Asegúrate de que la imagen sea menor de 10MB antes de la codificación base64. Las imágenes muy borrosas o rotadas pueden resultar en puntuaciones de ai_confidence más bajas (por debajo de 0.7). Considera pedir al usuario que tome otra foto si la confianza es baja.
GET /v1/users/{user_id}/transactions
Devuelve una lista paginada de transacciones de un usuario, ordenada por transaction_date descendente (más reciente primero).
Parámetros de Ruta
| Parámetro | Descripción |
|---|---|
user_id | El UUID Ozzie del usuario o external:{external_user_id} |
Parámetros de Query
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
limit | integer | 50 | Número de transacciones por página. Máximo 200. |
cursor | string | — | Cursor datetime ISO 8601 para paginación. Devuelve transacciones más antiguas que este timestamp. |
from | string | — | Filtro: incluir transacciones a partir de esta fecha (YYYY-MM-DD). |
to | string | — | Filtro: incluir transacciones hasta esta fecha (YYYY-MM-DD). |
category | string | — | Filtrar por categoría (ej.: food, transport). Separa con coma para múltiples: food,transport. |
Respuesta
{
"object": "list",
"data": {
"transactions": [ ... ],
"has_more": true,
"next_cursor": "2025-04-28T09:15:00Z",
"total_count": 142
}
}
Errores
| Código | HTTP | Cuándo |
|---|---|---|
NOT_FOUND | 404 | El user_id no existe |
VALIDATION_ERROR | 400 | Formato de fecha from/to inválido, o limit fuera de rango |
UNAUTHORIZED | 401 | Credenciales ausentes o inválidas |
amount_cents es siempre un entero en la unidad monetaria más pequeña (centavos para USD, etc.). Divide entre 100 para mostrar montos en dólares. Esto evita problemas de precisión de punto flotante.
ai_confidencePuntuaciones superiores a 0.85 indican alta confianza en la categoría y monto analizados. Puntuaciones entre 0.6 y 0.85 pueden beneficiarse de confirmación del usuario. Puntuaciones por debajo de 0.6 sugieren que la entrada era ambigua — considera pedir al usuario que aclare. Ozzie nunca descarta silenciosamente transacciones de baja confianza; siempre se devuelven.