Skip to main content

Transactions

Transactions are the core data stream that powers Ozzie's spending analysis, plan tracking, and personalized recommendations. Ozzie uses GPT-4o to parse natural language descriptions, receipt images (OCR), PDF bank statements, and CSV spreadsheets into structured, categorized transaction records.

A single submission can yield multiple transactions β€” for example, a text message saying "coffee $5 and lunch $15" will produce two separate transaction objects.


The Transaction Object​

{
"id": "ozz_txn_01HX9Q5NRWBF3KMZP4VC7YDLA",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"amount_cents": 4500,
"currency": "USD",
"category": "food",
"description": "Groceries at Whole Foods",
"transaction_date": "2025-05-05",
"source": "api_text",
"ai_confidence": 0.97,
"created_at": "2025-05-05T14:34:00Z"
}

Transaction Object Fields​

FieldTypeDescription
idstringOzzie-generated UUID for this transaction
user_idstringThe Ozzie user this transaction belongs to
amount_centsintegerTransaction amount in cents (e.g., 4500 = $45.00)
currencystringISO 4217 currency code (e.g., "USD", "BRL", "EUR")
categorystringSpending category (see table below)
descriptionstringAI-generated human-readable description of the transaction
transaction_datestringDate of the transaction in YYYY-MM-DD format
sourcestringHow the transaction was submitted (see table below)
ai_confidencefloatAI parsing confidence score from 0.0 to 1.0
created_atstringISO 8601 UTC timestamp of when the record was created in Ozzie

category Values​

ValueDescription
foodGroceries, restaurants, cafes, food delivery
transportGas, public transit, rideshare, parking, tolls
housingRent, mortgage, home insurance, repairs
utilitiesElectricity, water, internet, phone bill
healthPharmacy, doctor visits, gym, health insurance
entertainmentStreaming services, movies, games, events
educationTuition, books, courses, subscriptions for learning
clothingApparel, shoes, accessories
incomeSalary, freelance payment, side income, refund
otherAnything that doesn't fit the above categories

source Values​

ValueDescription
whatsapp_textText message received via WhatsApp
whatsapp_imageImage (receipt/screenshot) received via WhatsApp
api_textText submitted via the REST API
api_imageImage submitted via the REST API (base64)
api_pdfExtracted PDF text submitted via the REST API
api_spreadsheetCSV data submitted via the REST API

POST /v1/users/{user_id}/transactions​

Submit one or more transactions for parsing. Ozzie uses GPT-4o to extract structured transaction data from the provided content. The type field determines how the content is interpreted.

Path Parameters​

ParameterDescription
user_idThe Ozzie user UUID or external:{external_user_id}

Request Body β€” Discriminated Union on type​

The request body shape depends on the type field. All types share the language field.

type: "text"​

Submit a natural language description of one or more transactions.

FieldTypeRequiredDescription
typestringYesMust be "text"
contentstringYesNatural language transaction description
languagestringNoLanguage hint for parsing: "en" | "pt" | "es". Defaults to the user's language.
{
"type": "text",
"content": "Spent $45 on groceries at Whole Foods and $12 on the subway",
"language": "en"
}

type: "image"​

Submit a receipt, screenshot, or photo of a purchase as a base64-encoded image. Ozzie performs OCR and parses the result.

FieldTypeRequiredDescription
typestringYesMust be "image"
contentstringYesBase64-encoded image data
mime_typestringYesMIME type of the image: "image/jpeg" | "image/png" | "image/webp"
languagestringNoLanguage hint for OCR and parsing
{
"type": "image",
"content": "/9j/4AAQSkZJRgABAQEASABIAAD...",
"mime_type": "image/jpeg",
"language": "en"
}

type: "pdf"​

Submit the extracted text content from a PDF bank statement or receipt. Extract text from the PDF on your end before sending.

FieldTypeRequiredDescription
typestringYesMust be "pdf"
contentstringYesPlain text extracted from the PDF
languagestringNoLanguage hint for parsing
{
"type": "pdf",
"content": "BANK STATEMENT\nDate: 2025-05-01\nMerchant: Amazon.com\nAmount: -$89.99\nDate: 2025-05-02\nMerchant: Netflix\nAmount: -$15.99",
"language": "en"
}

type: "spreadsheet"​

Submit CSV-formatted transaction data. Include a header row. Ozzie normalizes column names flexibly (e.g., Date / date / transaction_date are all recognized).

FieldTypeRequiredDescription
typestringYesMust be "spreadsheet"
contentstringYesCSV string with header row
languagestringNoLanguage hint for parsing
{
"type": "spreadsheet",
"content": "date,description,amount\n2025-05-01,Whole Foods,45.00\n2025-05-02,Subway fare,12.00\n2025-05-03,Netflix,15.99",
"language": "en"
}

Response​

Returns a transaction_list object containing all transactions parsed from the submission. A single submission may produce one or many transactions.

{
"object": "transaction_list",
"data": {
"transactions": [ ... ]
}
}

Errors​

CodeHTTPWhen
NOT_FOUND404The user_id does not exist
VALIDATION_ERROR400Missing required fields, invalid type, or unsupported mime_type
UNAUTHORIZED401Missing or invalid credentials

Examples β€” Text Input​

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": "Spent $45 on groceries at Whole Foods and $12 on the subway",
"language": "en"
}'

Example Response β€” 2 transactions parsed from one text message (201 Created):

{
"object": "transaction_list",
"data": {
"transactions": [
{
"id": "ozz_txn_01HX9Q5NRWBF3KMZP4VC7YDLA",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"amount_cents": 4500,
"currency": "USD",
"category": "food",
"description": "Groceries at Whole Foods",
"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": "Subway fare",
"transaction_date": "2025-05-05",
"source": "api_text",
"ai_confidence": 0.95,
"created_at": "2025-05-05T14:34:00Z"
}
]
}
}
Multiple transactions per submission

Ozzie intentionally parses all distinct transactions from a single input. A grocery run plus a coffee stop in the same message will produce two separate transaction records. This matches real-world usage where users describe their day in one message.

Image submission tip

For receipt images, JPEG and PNG both work well. Make sure the image is under 10MB before base64 encoding. Very blurry or rotated images may result in lower ai_confidence scores (below 0.7). Consider prompting the user to retake the photo if confidence is low.


GET /v1/users/{user_id}/transactions​

Returns a paginated list of transactions for a user, ordered by transaction_date descending (most recent first).

Path Parameters​

ParameterDescription
user_idThe Ozzie user UUID or external:{external_user_id}

Query Parameters​

ParameterTypeDefaultDescription
limitinteger50Number of transactions per page. Maximum 200.
cursorstringβ€”ISO 8601 datetime cursor for pagination. Returns transactions older than this timestamp.
fromstringβ€”Filter: include transactions on or after this date (YYYY-MM-DD).
tostringβ€”Filter: include transactions on or before this date (YYYY-MM-DD).
categorystringβ€”Filter by category (e.g., food, transport). Comma-separate for multiple: food,transport.

Response​

{
"object": "list",
"data": {
"transactions": [ ... ],
"has_more": true,
"next_cursor": "2025-04-28T09:15:00Z",
"total_count": 142
}
}

Errors​

CodeHTTPWhen
NOT_FOUND404The user_id does not exist
VALIDATION_ERROR400Invalid from/to date format, or limit out of range
UNAUTHORIZED401Missing or invalid credentials

Examples​

# Transactions for May 2025
curl "https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/transactions?from=2025-05-01&to=2025-05-31&limit=100" \
-H "Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ="

# Next page using cursor
curl "https://api.ozzieapp.com/v1/users/ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE/transactions?from=2025-05-01&to=2025-05-31&limit=100&cursor=2025-05-20T10:00:00Z" \
-H "Authorization: Bearer czJjbGllbnQ6czJzZWNyZXQ="

Example Response (200 OK) β€” with date range filter:

{
"object": "list",
"data": {
"transactions": [
{
"id": "ozz_txn_01HX9Q5NRWBF3KMZP4VC7YDLA",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"amount_cents": 4500,
"currency": "USD",
"category": "food",
"description": "Groceries at Whole Foods",
"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": "Subway fare",
"transaction_date": "2025-05-05",
"source": "api_text",
"ai_confidence": 0.95,
"created_at": "2025-05-05T14:34:00Z"
},
{
"id": "ozz_txn_01HX9R2KVQPF4LNYB5WD8ZCMG",
"user_id": "ozz_usr_01HX9KZMR4P5JQNBVT7YCW3DE",
"amount_cents": 1599,
"currency": "USD",
"category": "entertainment",
"description": "Netflix subscription",
"transaction_date": "2025-05-03",
"source": "api_pdf",
"ai_confidence": 0.99,
"created_at": "2025-05-04T09:20:00Z"
}
],
"has_more": true,
"next_cursor": "2025-05-03T00:00:00Z",
"total_count": 47
}
}
Amount is always in cents

amount_cents is always an integer in the smallest currency unit (cents for USD, pence for GBP, etc.). Divide by 100 to display dollar amounts. This avoids floating-point precision issues.

ai_confidence interpretation

Scores above 0.85 indicate high confidence in the parsed category and amount. Scores between 0.6 and 0.85 may benefit from user confirmation. Scores below 0.6 suggest the input was ambiguous β€” consider prompting the user to clarify. Ozzie never silently discards low-confidence transactions; they are always returned.