{"components":{"schemas":{"AmendBody":{"description":"Body of an amendment over REST; the entry's id is in the path.","properties":{"reason":{"description":"Why the entry is being corrected, in the owner's words. Example: the category was wrong","type":"string"},"receipt":{"allOf":[{"description":"One receipt, as the assistant read it. Send exactly what is printed; the service validates and converts.","properties":{"category":{"description":"Category code from the categories list. Use unknown when the receipt does not make it clear. Example: groceries","type":"string"},"confirm_duplicate":{"description":"Set true only after the owner has confirmed that this is a separate purchase which happens to match an existing entry's merchant, date and total. Leave it out otherwise.","type":"boolean"},"confirm_unknown":{"description":"Set true only after the owner was offered the categories and chose to leave this entry unclassified. Without it, category unknown is refused so that the owner is asked first. Leave it out otherwise.","type":"boolean"},"currency":{"description":"ISO 4217 code of the currency printed on the receipt, three upper-case letters. Example: SEK","type":"string"},"label":{"description":"A short name grouping entries: a trip, a project, a client; the empty string when none. Set by the owner, never read from the receipt. Example: Stockholm trip","type":"string"},"lines":{"description":"The receipt's lines in printed order, including discount and rounding lines, so that they add up to the total. At least one; a receipt without items is one line equal to the total.","items":{"description":"One line of the receipt, as printed.","properties":{"amount":{"description":"Amount of the line as printed, in the expense's currency, negative for discounts and rounding. Example: 179.85 or -0.64","type":"string"},"category":{"description":"Category code for this line. Defaults to the expense's category; set it when a receipt mixes categories.","type":"string"},"description":{"description":"The item's name as printed, in every language the receipt prints it, separated by \" / \"; never translated, and without the quantity, price or barcode, which are data of their own. Example: T. Agritur Potato Bag / حقيبة بطاطس","type":"string"},"quantity":{"description":"Quantity as printed, up to three decimals. Defaults to 1. Example: 2 or 0.456","type":"string"},"unit_price":{"description":"Price of one printed unit as printed, decimal in the expense's currency; leave it out when the receipt prints none. With it, the service checks quantity times price against the amount. Example: 11.99","type":"string"}},"required":["description","amount"],"type":"object"},"type":"array"},"merchant":{"description":"Trader's name as printed on the receipt, trimmed; in the Latin script when the receipt prints more than one. Example: ICA Maxi","type":"string"},"merchant_tax_id":{"description":"The merchant's tax registration number as printed: a VAT number, TRN or organisation number; the empty string when none is printed. Example: 100123456700003","type":"string"},"note":{"description":"Anything the owner said about this purchase, or the empty string.","type":"string"},"payment_method":{"description":"How the receipt says it was paid: cash, card, transfer, other, or unknown when it does not say. Never the card's digits. Example: card","type":"string"},"purchased_on":{"description":"Date printed on the receipt as an ISO 8601 calendar date, no time, no zone. Not after today. Example: 2026-10-24","type":"string"},"purchased_time":{"description":"Time printed on the receipt as HH:MM in 24-hour form, or the empty string when none is printed. Example: 13:42","type":"string"},"receipt_text":{"description":"Verbatim transcription of the whole receipt, line by line, as the assistant read it. The only evidence kept.","type":"string"},"reference":{"description":"Receipt or invoice number as printed, or the empty string when none is printed. Example: 4711-0023","type":"string"},"reimbursement":{"description":"Reimbursement state of the entry: personal, claimable, claimed or paid; personal when the owner has not said it is for a claim. Example: claimable On an amendment the entry's current state is carried over and this field is ignored.","type":"string"},"total":{"description":"Amount paid, tax included, as the decimal printed on the receipt, in currency. Digits with an optional decimal point, no sign, no thousands separator. Example: 47.20","type":"string"},"vat":{"description":"VAT included in the total as printed, decimal in the expense's currency. 0 when the receipt prints none. Example: 119.36","type":"string"},"vat_lines":{"description":"The VAT summary as printed, one entry per rate, when the receipt prints one; their VAT adds up to vat, and vat may be left out when they are given. Leave it out when the receipt prints no summary.","items":{"description":"One rate of the VAT summary printed on the receipt.","properties":{"base":{"description":"Amount the rate applies to, before VAT, as printed, decimal in the expense's currency. Example: 37.76","type":"string"},"rate":{"description":"VAT rate as the percentage printed, up to two decimals. Example: 25 or 5 or 12.5","type":"string"},"vat":{"description":"VAT at this rate as printed, decimal in the expense's currency. Example: 9.44","type":"string"}},"required":["rate","base","vat"],"type":"object"},"type":"array"}},"required":["merchant","purchased_on","total","currency","receipt_text"],"type":"object"},{"description":"The complete corrected receipt, not a difference: every field and every line as they should have been.","type":"object"}]}},"required":["reason","receipt"],"type":"object"},"ApiError":{"description":"Why a request was refused, written so the assistant can correct it and retry.","properties":{"detail":{"description":"What was wrong, in one sentence.","type":"string"},"error":{"description":"Machine-readable reason: invalid_request, not_found, possible_duplicate, unauthorized, insufficient_scope, too_many_requests or internal.","type":"string"},"field":{"description":"The input field at fault, or the empty string when the problem is not with one field.","type":"string"},"valid_values":{"description":"Values that would have been accepted, when the set is small enough to list; otherwise empty.","items":{"type":"string"},"type":"array"}},"required":["error","field","detail","valid_values"],"type":"object"},"BudgetList":{"description":"Every budget the owner has set, with its standing in the month.","properties":{"budgets":{"description":"The budgets in category order, then currency.","items":{"description":"One budget with its standing in one calendar month, as of now.","properties":{"budget":{"description":"The monthly budget as a decimal in the currency; 0 once removed. Example: 2500.00","type":"string"},"budget_minor":{"description":"The monthly budget in minor units of the currency.","format":"int64","type":"integer"},"category":{"description":"Category code the budget applies to, one of the owner's active categories. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency the budget is in; spending in other currencies does not count against it. Example: SEK","type":"string"},"entries":{"description":"How many current entries contributed to the spend.","format":"int64","type":"integer"},"month":{"description":"The calendar month judged, as YYYY-MM. Example: 2026-10","type":"string"},"remaining":{"description":"Budget minus spent, as a signed decimal; negative once the budget is exceeded. Example: 449.50","type":"string"},"remaining_minor":{"description":"Budget minus spent, in minor units of the currency; negative once the budget is exceeded.","format":"int64","type":"integer"},"spent":{"description":"Spent in the month so far: the sum of the current entries' lines in this category and currency, as a decimal. Example: 2050.50","type":"string"},"spent_minor":{"description":"Spent in the month so far, in minor units of the currency.","format":"int64","type":"integer"},"used_percent":{"description":"Spent as a percentage of the budget, rounded to the nearest whole number; above 100 once exceeded, 0 when there is no budget. Example: 82","format":"int64","type":"integer"}},"required":["category","currency","month","budget","budget_minor","spent","spent_minor","remaining","remaining_minor","used_percent","entries"],"type":"object"},"type":"array"},"month":{"description":"The calendar month judged, as YYYY-MM.","type":"string"}},"required":["month","budgets"],"type":"object"},"BudgetStatus":{"description":"One budget with its standing in one calendar month, as of now.","properties":{"budget":{"description":"The monthly budget as a decimal in the currency; 0 once removed. Example: 2500.00","type":"string"},"budget_minor":{"description":"The monthly budget in minor units of the currency.","format":"int64","type":"integer"},"category":{"description":"Category code the budget applies to, one of the owner's active categories. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency the budget is in; spending in other currencies does not count against it. Example: SEK","type":"string"},"entries":{"description":"How many current entries contributed to the spend.","format":"int64","type":"integer"},"month":{"description":"The calendar month judged, as YYYY-MM. Example: 2026-10","type":"string"},"remaining":{"description":"Budget minus spent, as a signed decimal; negative once the budget is exceeded. Example: 449.50","type":"string"},"remaining_minor":{"description":"Budget minus spent, in minor units of the currency; negative once the budget is exceeded.","format":"int64","type":"integer"},"spent":{"description":"Spent in the month so far: the sum of the current entries' lines in this category and currency, as a decimal. Example: 2050.50","type":"string"},"spent_minor":{"description":"Spent in the month so far, in minor units of the currency.","format":"int64","type":"integer"},"used_percent":{"description":"Spent as a percentage of the budget, rounded to the nearest whole number; above 100 once exceeded, 0 when there is no budget. Example: 82","format":"int64","type":"integer"}},"required":["category","currency","month","budget","budget_minor","spent","spent_minor","remaining","remaining_minor","used_percent","entries"],"type":"object"},"CaptureReceipt":{"description":"One receipt, as the assistant read it. Send exactly what is printed; the service validates and converts.","properties":{"category":{"description":"Category code from the categories list. Use unknown when the receipt does not make it clear. Example: groceries","type":"string"},"confirm_duplicate":{"description":"Set true only after the owner has confirmed that this is a separate purchase which happens to match an existing entry's merchant, date and total. Leave it out otherwise.","type":"boolean"},"confirm_unknown":{"description":"Set true only after the owner was offered the categories and chose to leave this entry unclassified. Without it, category unknown is refused so that the owner is asked first. Leave it out otherwise.","type":"boolean"},"currency":{"description":"ISO 4217 code of the currency printed on the receipt, three upper-case letters. Example: SEK","type":"string"},"label":{"description":"A short name grouping entries: a trip, a project, a client; the empty string when none. Set by the owner, never read from the receipt. Example: Stockholm trip","type":"string"},"lines":{"description":"The receipt's lines in printed order, including discount and rounding lines, so that they add up to the total. At least one; a receipt without items is one line equal to the total.","items":{"description":"One line of the receipt, as printed.","properties":{"amount":{"description":"Amount of the line as printed, in the expense's currency, negative for discounts and rounding. Example: 179.85 or -0.64","type":"string"},"category":{"description":"Category code for this line. Defaults to the expense's category; set it when a receipt mixes categories.","type":"string"},"description":{"description":"The item's name as printed, in every language the receipt prints it, separated by \" / \"; never translated, and without the quantity, price or barcode, which are data of their own. Example: T. Agritur Potato Bag / حقيبة بطاطس","type":"string"},"quantity":{"description":"Quantity as printed, up to three decimals. Defaults to 1. Example: 2 or 0.456","type":"string"},"unit_price":{"description":"Price of one printed unit as printed, decimal in the expense's currency; leave it out when the receipt prints none. With it, the service checks quantity times price against the amount. Example: 11.99","type":"string"}},"required":["description","amount"],"type":"object"},"type":"array"},"merchant":{"description":"Trader's name as printed on the receipt, trimmed; in the Latin script when the receipt prints more than one. Example: ICA Maxi","type":"string"},"merchant_tax_id":{"description":"The merchant's tax registration number as printed: a VAT number, TRN or organisation number; the empty string when none is printed. Example: 100123456700003","type":"string"},"note":{"description":"Anything the owner said about this purchase, or the empty string.","type":"string"},"payment_method":{"description":"How the receipt says it was paid: cash, card, transfer, other, or unknown when it does not say. Never the card's digits. Example: card","type":"string"},"purchased_on":{"description":"Date printed on the receipt as an ISO 8601 calendar date, no time, no zone. Not after today. Example: 2026-10-24","type":"string"},"purchased_time":{"description":"Time printed on the receipt as HH:MM in 24-hour form, or the empty string when none is printed. Example: 13:42","type":"string"},"receipt_text":{"description":"Verbatim transcription of the whole receipt, line by line, as the assistant read it. The only evidence kept.","type":"string"},"reference":{"description":"Receipt or invoice number as printed, or the empty string when none is printed. Example: 4711-0023","type":"string"},"reimbursement":{"description":"Reimbursement state of the entry: personal, claimable, claimed or paid; personal when the owner has not said it is for a claim. Example: claimable On an amendment the entry's current state is carried over and this field is ignored.","type":"string"},"total":{"description":"Amount paid, tax included, as the decimal printed on the receipt, in currency. Digits with an optional decimal point, no sign, no thousands separator. Example: 47.20","type":"string"},"vat":{"description":"VAT included in the total as printed, decimal in the expense's currency. 0 when the receipt prints none. Example: 119.36","type":"string"},"vat_lines":{"description":"The VAT summary as printed, one entry per rate, when the receipt prints one; their VAT adds up to vat, and vat may be left out when they are given. Leave it out when the receipt prints no summary.","items":{"description":"One rate of the VAT summary printed on the receipt.","properties":{"base":{"description":"Amount the rate applies to, before VAT, as printed, decimal in the expense's currency. Example: 37.76","type":"string"},"rate":{"description":"VAT rate as the percentage printed, up to two decimals. Example: 25 or 5 or 12.5","type":"string"},"vat":{"description":"VAT at this rate as printed, decimal in the expense's currency. Example: 9.44","type":"string"}},"required":["rate","base","vat"],"type":"object"},"type":"array"}},"required":["merchant","purchased_on","total","currency","receipt_text"],"type":"object"},"Category":{"description":"A category as stored.","properties":{"active":{"description":"Whether the category may be used for new expenses. Inactive categories remain for the rows that already use them.","type":"boolean"},"code":{"description":"Category code, a short lower-case token used as the value of expenses.category. Example: groceries","type":"string"},"description":{"description":"What belongs in this category, written for the assistant choosing it.","type":"string"}},"required":["code","description","active"],"type":"object"},"CategoryBody":{"description":"Body of a category change over REST; the code is in the path.","properties":{"active":{"description":"Whether the category may be used for new expenses. Inactive categories remain for the rows that already use them.","type":"boolean"},"description":{"description":"What belongs in this category, written for the assistant choosing it.","type":"string"}},"required":["description"],"type":"object"},"CategoryList":{"description":"The owner's categories, active and retired.","properties":{"categories":{"description":"Every category, in code order, with its meaning and whether it is offered for new entries.","items":{"description":"A category as stored.","properties":{"active":{"description":"Whether the category may be used for new expenses. Inactive categories remain for the rows that already use them.","type":"boolean"},"code":{"description":"Category code, a short lower-case token used as the value of expenses.category. Example: groceries","type":"string"},"description":{"description":"What belongs in this category, written for the assistant choosing it.","type":"string"}},"required":["code","description","active"],"type":"object"},"type":"array"}},"required":["categories"],"type":"object"},"Connection":{"description":"One assistant connection: a live grant of the owner's.","properties":{"client_name":{"description":"The assistant application that holds it, as it named itself when it registered. Example: Claude","type":"string"},"current":{"description":"True for the connection making this very call.","type":"boolean"},"granted_at":{"description":"When the owner allowed it on the consent page, RFC 3339.","type":"string"},"id":{"description":"Identifier of the connection. Use it with end_connection.","format":"uuid","type":"string"},"last_used_at":{"description":"When it last made a call, RFC 3339; the grant time until the first call.","type":"string"},"scope":{"description":"What it may do: expenses:write, expenses:read, or both, space-separated.","type":"string"}},"required":["id","client_name","scope","granted_at","last_used_at","current"],"type":"object"},"ConnectionEnded":{"description":"Confirmation that a connection ended. Its tokens are gone; the entries it recorded stay.","properties":{"ended_at":{"description":"When it ended, RFC 3339.","type":"string"},"id":{"description":"Identifier of the connection that ended.","format":"uuid","type":"string"}},"required":["id","ended_at"],"type":"object"},"ConnectionList":{"description":"The owner's live connections, oldest first.","properties":{"connections":{"items":{"description":"One assistant connection: a live grant of the owner's.","properties":{"client_name":{"description":"The assistant application that holds it, as it named itself when it registered. Example: Claude","type":"string"},"current":{"description":"True for the connection making this very call.","type":"boolean"},"granted_at":{"description":"When the owner allowed it on the consent page, RFC 3339.","type":"string"},"id":{"description":"Identifier of the connection. Use it with end_connection.","format":"uuid","type":"string"},"last_used_at":{"description":"When it last made a call, RFC 3339; the grant time until the first call.","type":"string"},"scope":{"description":"What it may do: expenses:write, expenses:read, or both, space-separated.","type":"string"}},"required":["id","client_name","scope","granted_at","last_used_at","current"],"type":"object"},"type":"array"}},"required":["connections"],"type":"object"},"Dictionary":{"description":"The data dictionary: every table, view and column with its meaning, read from the catalog.","properties":{"objects":{"description":"Rows in table order, each table's own row first, then its columns in position order.","items":{"$ref":"#/components/schemas/DictionaryRow"},"type":"array"}},"required":["objects"],"type":"object"},"DictionaryRow":{"description":"One row of the data dictionary: a table, a view, or a column, with its meaning.","properties":{"column_name":{"description":"Column name, or the empty string for the row that describes the table itself.","type":"string"},"data_type":{"description":"SQL type of the column, or the empty string for a table row. Example: bigint","type":"string"},"default_value":{"description":"SQL default expression, or the empty string if none. Example: uuidv7()","type":"string"},"description":{"description":"The object's comment: a definition with format and example. Never empty.","type":"string"},"object_type":{"description":"table, view or column.","type":"string"},"required":{"description":"True when the column is NOT NULL. Every column is, by policy.","type":"boolean"},"table_name":{"description":"Name of the table or view this row describes or belongs to.","type":"string"}},"required":["object_type","table_name","column_name","data_type","required","default_value","description"],"type":"object"},"Expense":{"description":"A stored ledger entry, read back exactly as recorded.","properties":{"budgets":{"description":"The standing of each monthly budget this entry counts against, in the entry's month, as of now; empty when none applies, and always empty in an export.","items":{"description":"One budget with its standing in one calendar month, as of now.","properties":{"budget":{"description":"The monthly budget as a decimal in the currency; 0 once removed. Example: 2500.00","type":"string"},"budget_minor":{"description":"The monthly budget in minor units of the currency.","format":"int64","type":"integer"},"category":{"description":"Category code the budget applies to, one of the owner's active categories. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency the budget is in; spending in other currencies does not count against it. Example: SEK","type":"string"},"entries":{"description":"How many current entries contributed to the spend.","format":"int64","type":"integer"},"month":{"description":"The calendar month judged, as YYYY-MM. Example: 2026-10","type":"string"},"remaining":{"description":"Budget minus spent, as a signed decimal; negative once the budget is exceeded. Example: 449.50","type":"string"},"remaining_minor":{"description":"Budget minus spent, in minor units of the currency; negative once the budget is exceeded.","format":"int64","type":"integer"},"spent":{"description":"Spent in the month so far: the sum of the current entries' lines in this category and currency, as a decimal. Example: 2050.50","type":"string"},"spent_minor":{"description":"Spent in the month so far, in minor units of the currency.","format":"int64","type":"integer"},"used_percent":{"description":"Spent as a percentage of the budget, rounded to the nearest whole number; above 100 once exceeded, 0 when there is no budget. Example: 82","format":"int64","type":"integer"}},"required":["category","currency","month","budget","budget_minor","spent","spent_minor","remaining","remaining_minor","used_percent","entries"],"type":"object"},"type":"array"},"category":{"description":"Category code from the categories list. Use unknown when the receipt does not make it clear. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency printed on the receipt, three upper-case letters. Example: SEK","type":"string"},"current":{"description":"True while the entry is in the current ledger; false once amended or voided.","type":"boolean"},"id":{"description":"Identifier of the stored entry. Time-ordered UUID generated by the database.","format":"uuid","type":"string"},"label":{"description":"A short name grouping entries: a trip, a project, a client; the empty string when none. Set by the owner, never read from the receipt. Example: Stockholm trip","type":"string"},"lines":{"description":"The receipt's lines in printed order. They add up to the total.","items":{"description":"A stored receipt line.","properties":{"amount":{"description":"Amount of the line as printed, in the expense's currency, negative for discounts and rounding. Example: 179.85 or -0.64","type":"string"},"amount_minor":{"description":"Amount of the line in minor units of the expense's currency, negative for discounts and rounding.","format":"int64","type":"integer"},"category":{"description":"Category code for this line. Defaults to the expense's category; set it when a receipt mixes categories.","type":"string"},"description":{"description":"The item's name as printed, in every language the receipt prints it, separated by \" / \"; never translated, and without the quantity, price or barcode, which are data of their own. Example: T. Agritur Potato Bag / حقيبة بطاطس","type":"string"},"position":{"description":"Order of the line on the receipt, from 1 at the top.","format":"int32","type":"integer"},"quantity":{"description":"Quantity as printed, up to three decimals. Defaults to 1. Example: 2 or 0.456","type":"string"},"quantity_milli":{"description":"Quantity in thousandths of the printed unit: 15 is 15000, 0.456 kg is 456.","format":"int64","type":"integer"},"unit_price":{"description":"Price of one printed unit as printed, decimal in the expense's currency, or the empty string when the receipt prints none. Example: 11.99","type":"string"},"unit_price_minor":{"description":"Price of one printed unit in minor units of the expense's currency, as printed; 0 when the receipt prints no unit price.","format":"int64","type":"integer"}},"required":["position","description","quantity","quantity_milli","unit_price","unit_price_minor","amount","amount_minor","category"],"type":"object"},"type":"array"},"merchant":{"description":"Trader's name as printed on the receipt, trimmed; in the Latin script when the receipt prints more than one. Example: ICA Maxi","type":"string"},"merchant_tax_id":{"description":"The merchant's tax registration number as printed: a VAT number, TRN or organisation number; the empty string when none is printed. Example: 100123456700003","type":"string"},"note":{"description":"Anything the owner said about this purchase, or the empty string.","type":"string"},"payment_method":{"description":"How the receipt says it was paid: cash, card, transfer, other, or unknown when it does not say. Never the card's digits. Example: card","type":"string"},"purchased_on":{"description":"Date printed on the receipt as an ISO 8601 calendar date, no time, no zone. Not after today. Example: 2026-10-24","type":"string"},"purchased_time":{"description":"Time printed on the receipt as HH:MM in 24-hour form, or the empty string when none is printed. Example: 13:42","type":"string"},"receipt_text":{"description":"Verbatim transcription of the whole receipt, line by line, as the assistant read it. The only evidence kept.","type":"string"},"recorded_at":{"description":"When the service wrote the entry, RFC 3339 with time zone.","type":"string"},"reference":{"description":"Receipt or invoice number as printed, or the empty string when none is printed. Example: 4711-0023","type":"string"},"reimbursement":{"description":"Reimbursement state of the entry: personal, claimable, claimed or paid; personal when the owner has not said it is for a claim. Example: claimable","type":"string"},"total":{"description":"Amount paid, tax included, as the decimal printed on the receipt, in currency. Digits with an optional decimal point, no sign, no thousands separator. Example: 47.20","type":"string"},"total_minor":{"description":"Amount paid, tax included, in minor units of currency: the printed amount times ten to the currency's exponent. Example: 4720 for 47.20 EUR, 1200 for 1200 JPY","format":"int64","type":"integer"},"vat":{"description":"VAT included in the total as printed, decimal in the expense's currency. 0 when the receipt prints none. Example: 119.36","type":"string"},"vat_lines":{"description":"The VAT summary as printed, one row per rate; empty when the receipt prints none.","items":{"description":"A stored row of the VAT summary.","properties":{"base":{"description":"Amount the rate applies to, before VAT, as printed, decimal in the expense's currency. Example: 37.76","type":"string"},"base_minor":{"description":"Amount the rate applies to, before VAT, in minor units of the expense's currency, as printed.","format":"int64","type":"integer"},"rate":{"description":"VAT rate as the percentage printed, up to two decimals. Example: 25 or 5 or 12.5","type":"string"},"rate_bp":{"description":"VAT rate in basis points: 25% is 2500, 5% is 500, 0% is 0.","format":"int32","type":"integer"},"vat":{"description":"VAT at this rate as printed, decimal in the expense's currency. Example: 9.44","type":"string"},"vat_minor":{"description":"VAT at this rate, in minor units of the expense's currency, as printed.","format":"int64","type":"integer"}},"required":["rate","rate_bp","base","base_minor","vat","vat_minor"],"type":"object"},"type":"array"},"vat_minor":{"description":"VAT included in the total, in minor units of currency, as printed on the receipt; 0 when none is printed.","format":"int64","type":"integer"}},"required":["id","merchant","reference","merchant_tax_id","purchased_on","purchased_time","total","total_minor","currency","payment_method","category","note","label","reimbursement","receipt_text","recorded_at","vat","vat_minor","vat_lines","lines","current"],"type":"object"},"ExpenseList":{"description":"A page of entries, newest purchase first.","properties":{"expenses":{"description":"The entries on this page.","items":{"description":"One entry in a listing: everything but its lines and transcription, which get_expense returns.","properties":{"category":{"description":"Category code from the categories list. Use unknown when the receipt does not make it clear. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency printed on the receipt, three upper-case letters. Example: SEK","type":"string"},"id":{"description":"Identifier of the stored entry. Time-ordered UUID generated by the database.","format":"uuid","type":"string"},"label":{"description":"A short name grouping entries: a trip, a project, a client; the empty string when none. Set by the owner, never read from the receipt. Example: Stockholm trip","type":"string"},"line_count":{"description":"How many lines the receipt has.","format":"int64","type":"integer"},"merchant":{"description":"Trader's name as printed on the receipt, trimmed; in the Latin script when the receipt prints more than one. Example: ICA Maxi","type":"string"},"note":{"description":"Anything the owner said about this purchase, or the empty string.","type":"string"},"payment_method":{"description":"How the receipt says it was paid: cash, card, transfer, other, or unknown when it does not say. Never the card's digits. Example: card","type":"string"},"purchased_on":{"description":"Date printed on the receipt as an ISO 8601 calendar date, no time, no zone. Not after today. Example: 2026-10-24","type":"string"},"purchased_time":{"description":"Time printed on the receipt as HH:MM in 24-hour form, or the empty string when none is printed. Example: 13:42","type":"string"},"recorded_at":{"description":"When the service wrote the entry, RFC 3339 with time zone.","type":"string"},"reference":{"description":"Receipt or invoice number as printed, or the empty string when none is printed. Example: 4711-0023","type":"string"},"reimbursement":{"description":"Reimbursement state of the entry: personal, claimable, claimed or paid; personal when the owner has not said it is for a claim. Example: claimable","type":"string"},"total":{"description":"Amount paid, tax included, as the decimal printed on the receipt, in currency. Digits with an optional decimal point, no sign, no thousands separator. Example: 47.20","type":"string"},"total_minor":{"description":"Amount paid, tax included, in minor units of currency: the printed amount times ten to the currency's exponent. Example: 4720 for 47.20 EUR, 1200 for 1200 JPY","format":"int64","type":"integer"},"vat":{"description":"VAT included in the total as printed, decimal in the expense's currency. 0 when the receipt prints none. Example: 119.36","type":"string"}},"required":["id","merchant","purchased_on","total","total_minor","vat","currency","payment_method","reference","purchased_time","category","note","label","reimbursement","recorded_at","line_count"],"type":"object"},"type":"array"},"limit":{"description":"The page size that was applied.","format":"int32","minimum":0,"type":"integer"},"offset":{"description":"The offset that was applied.","format":"int32","minimum":0,"type":"integer"},"total_count":{"description":"How many entries match the filters in all, across pages.","format":"int64","type":"integer"}},"required":["expenses","total_count","limit","offset"],"type":"object"},"ExpenseSummary":{"description":"One entry in a listing: everything but its lines and transcription, which get_expense returns.","properties":{"category":{"description":"Category code from the categories list. Use unknown when the receipt does not make it clear. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency printed on the receipt, three upper-case letters. Example: SEK","type":"string"},"id":{"description":"Identifier of the stored entry. Time-ordered UUID generated by the database.","format":"uuid","type":"string"},"label":{"description":"A short name grouping entries: a trip, a project, a client; the empty string when none. Set by the owner, never read from the receipt. Example: Stockholm trip","type":"string"},"line_count":{"description":"How many lines the receipt has.","format":"int64","type":"integer"},"merchant":{"description":"Trader's name as printed on the receipt, trimmed; in the Latin script when the receipt prints more than one. Example: ICA Maxi","type":"string"},"note":{"description":"Anything the owner said about this purchase, or the empty string.","type":"string"},"payment_method":{"description":"How the receipt says it was paid: cash, card, transfer, other, or unknown when it does not say. Never the card's digits. Example: card","type":"string"},"purchased_on":{"description":"Date printed on the receipt as an ISO 8601 calendar date, no time, no zone. Not after today. Example: 2026-10-24","type":"string"},"purchased_time":{"description":"Time printed on the receipt as HH:MM in 24-hour form, or the empty string when none is printed. Example: 13:42","type":"string"},"recorded_at":{"description":"When the service wrote the entry, RFC 3339 with time zone.","type":"string"},"reference":{"description":"Receipt or invoice number as printed, or the empty string when none is printed. Example: 4711-0023","type":"string"},"reimbursement":{"description":"Reimbursement state of the entry: personal, claimable, claimed or paid; personal when the owner has not said it is for a claim. Example: claimable","type":"string"},"total":{"description":"Amount paid, tax included, as the decimal printed on the receipt, in currency. Digits with an optional decimal point, no sign, no thousands separator. Example: 47.20","type":"string"},"total_minor":{"description":"Amount paid, tax included, in minor units of currency: the printed amount times ten to the currency's exponent. Example: 4720 for 47.20 EUR, 1200 for 1200 JPY","format":"int64","type":"integer"},"vat":{"description":"VAT included in the total as printed, decimal in the expense's currency. 0 when the receipt prints none. Example: 119.36","type":"string"}},"required":["id","merchant","purchased_on","total","total_minor","vat","currency","payment_method","reference","purchased_time","category","note","label","reimbursement","recorded_at","line_count"],"type":"object"},"ExportBundle":{"description":"The owner's ledger as a whole, in plain structures: the escape hatch the business rules promise.","properties":{"categories":{"description":"Every category, active and retired, with its meaning.","items":{"description":"A category as stored.","properties":{"active":{"description":"Whether the category may be used for new expenses. Inactive categories remain for the rows that already use them.","type":"boolean"},"code":{"description":"Category code, a short lower-case token used as the value of expenses.category. Example: groceries","type":"string"},"description":{"description":"What belongs in this category, written for the assistant choosing it.","type":"string"}},"required":["code","description","active"],"type":"object"},"type":"array"},"expenses":{"description":"Entries in purchase order, oldest first, each with its lines and transcription.","items":{"description":"A stored ledger entry, read back exactly as recorded.","properties":{"budgets":{"description":"The standing of each monthly budget this entry counts against, in the entry's month, as of now; empty when none applies, and always empty in an export.","items":{"description":"One budget with its standing in one calendar month, as of now.","properties":{"budget":{"description":"The monthly budget as a decimal in the currency; 0 once removed. Example: 2500.00","type":"string"},"budget_minor":{"description":"The monthly budget in minor units of the currency.","format":"int64","type":"integer"},"category":{"description":"Category code the budget applies to, one of the owner's active categories. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency the budget is in; spending in other currencies does not count against it. Example: SEK","type":"string"},"entries":{"description":"How many current entries contributed to the spend.","format":"int64","type":"integer"},"month":{"description":"The calendar month judged, as YYYY-MM. Example: 2026-10","type":"string"},"remaining":{"description":"Budget minus spent, as a signed decimal; negative once the budget is exceeded. Example: 449.50","type":"string"},"remaining_minor":{"description":"Budget minus spent, in minor units of the currency; negative once the budget is exceeded.","format":"int64","type":"integer"},"spent":{"description":"Spent in the month so far: the sum of the current entries' lines in this category and currency, as a decimal. Example: 2050.50","type":"string"},"spent_minor":{"description":"Spent in the month so far, in minor units of the currency.","format":"int64","type":"integer"},"used_percent":{"description":"Spent as a percentage of the budget, rounded to the nearest whole number; above 100 once exceeded, 0 when there is no budget. Example: 82","format":"int64","type":"integer"}},"required":["category","currency","month","budget","budget_minor","spent","spent_minor","remaining","remaining_minor","used_percent","entries"],"type":"object"},"type":"array"},"category":{"description":"Category code from the categories list. Use unknown when the receipt does not make it clear. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency printed on the receipt, three upper-case letters. Example: SEK","type":"string"},"current":{"description":"True while the entry is in the current ledger; false once amended or voided.","type":"boolean"},"id":{"description":"Identifier of the stored entry. Time-ordered UUID generated by the database.","format":"uuid","type":"string"},"label":{"description":"A short name grouping entries: a trip, a project, a client; the empty string when none. Set by the owner, never read from the receipt. Example: Stockholm trip","type":"string"},"lines":{"description":"The receipt's lines in printed order. They add up to the total.","items":{"description":"A stored receipt line.","properties":{"amount":{"description":"Amount of the line as printed, in the expense's currency, negative for discounts and rounding. Example: 179.85 or -0.64","type":"string"},"amount_minor":{"description":"Amount of the line in minor units of the expense's currency, negative for discounts and rounding.","format":"int64","type":"integer"},"category":{"description":"Category code for this line. Defaults to the expense's category; set it when a receipt mixes categories.","type":"string"},"description":{"description":"The item's name as printed, in every language the receipt prints it, separated by \" / \"; never translated, and without the quantity, price or barcode, which are data of their own. Example: T. Agritur Potato Bag / حقيبة بطاطس","type":"string"},"position":{"description":"Order of the line on the receipt, from 1 at the top.","format":"int32","type":"integer"},"quantity":{"description":"Quantity as printed, up to three decimals. Defaults to 1. Example: 2 or 0.456","type":"string"},"quantity_milli":{"description":"Quantity in thousandths of the printed unit: 15 is 15000, 0.456 kg is 456.","format":"int64","type":"integer"},"unit_price":{"description":"Price of one printed unit as printed, decimal in the expense's currency, or the empty string when the receipt prints none. Example: 11.99","type":"string"},"unit_price_minor":{"description":"Price of one printed unit in minor units of the expense's currency, as printed; 0 when the receipt prints no unit price.","format":"int64","type":"integer"}},"required":["position","description","quantity","quantity_milli","unit_price","unit_price_minor","amount","amount_minor","category"],"type":"object"},"type":"array"},"merchant":{"description":"Trader's name as printed on the receipt, trimmed; in the Latin script when the receipt prints more than one. Example: ICA Maxi","type":"string"},"merchant_tax_id":{"description":"The merchant's tax registration number as printed: a VAT number, TRN or organisation number; the empty string when none is printed. Example: 100123456700003","type":"string"},"note":{"description":"Anything the owner said about this purchase, or the empty string.","type":"string"},"payment_method":{"description":"How the receipt says it was paid: cash, card, transfer, other, or unknown when it does not say. Never the card's digits. Example: card","type":"string"},"purchased_on":{"description":"Date printed on the receipt as an ISO 8601 calendar date, no time, no zone. Not after today. Example: 2026-10-24","type":"string"},"purchased_time":{"description":"Time printed on the receipt as HH:MM in 24-hour form, or the empty string when none is printed. Example: 13:42","type":"string"},"receipt_text":{"description":"Verbatim transcription of the whole receipt, line by line, as the assistant read it. The only evidence kept.","type":"string"},"recorded_at":{"description":"When the service wrote the entry, RFC 3339 with time zone.","type":"string"},"reference":{"description":"Receipt or invoice number as printed, or the empty string when none is printed. Example: 4711-0023","type":"string"},"reimbursement":{"description":"Reimbursement state of the entry: personal, claimable, claimed or paid; personal when the owner has not said it is for a claim. Example: claimable","type":"string"},"total":{"description":"Amount paid, tax included, as the decimal printed on the receipt, in currency. Digits with an optional decimal point, no sign, no thousands separator. Example: 47.20","type":"string"},"total_minor":{"description":"Amount paid, tax included, in minor units of currency: the printed amount times ten to the currency's exponent. Example: 4720 for 47.20 EUR, 1200 for 1200 JPY","format":"int64","type":"integer"},"vat":{"description":"VAT included in the total as printed, decimal in the expense's currency. 0 when the receipt prints none. Example: 119.36","type":"string"},"vat_lines":{"description":"The VAT summary as printed, one row per rate; empty when the receipt prints none.","items":{"description":"A stored row of the VAT summary.","properties":{"base":{"description":"Amount the rate applies to, before VAT, as printed, decimal in the expense's currency. Example: 37.76","type":"string"},"base_minor":{"description":"Amount the rate applies to, before VAT, in minor units of the expense's currency, as printed.","format":"int64","type":"integer"},"rate":{"description":"VAT rate as the percentage printed, up to two decimals. Example: 25 or 5 or 12.5","type":"string"},"rate_bp":{"description":"VAT rate in basis points: 25% is 2500, 5% is 500, 0% is 0.","format":"int32","type":"integer"},"vat":{"description":"VAT at this rate as printed, decimal in the expense's currency. Example: 9.44","type":"string"},"vat_minor":{"description":"VAT at this rate, in minor units of the expense's currency, as printed.","format":"int64","type":"integer"}},"required":["rate","rate_bp","base","base_minor","vat","vat_minor"],"type":"object"},"type":"array"},"vat_minor":{"description":"VAT included in the total, in minor units of currency, as printed on the receipt; 0 when none is printed.","format":"int64","type":"integer"}},"required":["id","merchant","reference","merchant_tax_id","purchased_on","purchased_time","total","total_minor","currency","payment_method","category","note","label","reimbursement","receipt_text","recorded_at","vat","vat_minor","vat_lines","lines","current"],"type":"object"},"type":"array"},"exported_at":{"description":"When the export was produced, RFC 3339 with time zone.","type":"string"}},"required":["exported_at","categories","expenses"],"type":"object"},"LineInput":{"description":"One line of the receipt, as printed.","properties":{"amount":{"description":"Amount of the line as printed, in the expense's currency, negative for discounts and rounding. Example: 179.85 or -0.64","type":"string"},"category":{"description":"Category code for this line. Defaults to the expense's category; set it when a receipt mixes categories.","type":"string"},"description":{"description":"The item's name as printed, in every language the receipt prints it, separated by \" / \"; never translated, and without the quantity, price or barcode, which are data of their own. Example: T. Agritur Potato Bag / حقيبة بطاطس","type":"string"},"quantity":{"description":"Quantity as printed, up to three decimals. Defaults to 1. Example: 2 or 0.456","type":"string"},"unit_price":{"description":"Price of one printed unit as printed, decimal in the expense's currency; leave it out when the receipt prints none. With it, the service checks quantity times price against the amount. Example: 11.99","type":"string"}},"required":["description","amount"],"type":"object"},"LineItem":{"description":"A stored receipt line.","properties":{"amount":{"description":"Amount of the line as printed, in the expense's currency, negative for discounts and rounding. Example: 179.85 or -0.64","type":"string"},"amount_minor":{"description":"Amount of the line in minor units of the expense's currency, negative for discounts and rounding.","format":"int64","type":"integer"},"category":{"description":"Category code for this line. Defaults to the expense's category; set it when a receipt mixes categories.","type":"string"},"description":{"description":"The item's name as printed, in every language the receipt prints it, separated by \" / \"; never translated, and without the quantity, price or barcode, which are data of their own. Example: T. Agritur Potato Bag / حقيبة بطاطس","type":"string"},"position":{"description":"Order of the line on the receipt, from 1 at the top.","format":"int32","type":"integer"},"quantity":{"description":"Quantity as printed, up to three decimals. Defaults to 1. Example: 2 or 0.456","type":"string"},"quantity_milli":{"description":"Quantity in thousandths of the printed unit: 15 is 15000, 0.456 kg is 456.","format":"int64","type":"integer"},"unit_price":{"description":"Price of one printed unit as printed, decimal in the expense's currency, or the empty string when the receipt prints none. Example: 11.99","type":"string"},"unit_price_minor":{"description":"Price of one printed unit in minor units of the expense's currency, as printed; 0 when the receipt prints no unit price.","format":"int64","type":"integer"}},"required":["position","description","quantity","quantity_milli","unit_price","unit_price_minor","amount","amount_minor","category"],"type":"object"},"NewCategory":{"description":"A new category for the owner's ledger.","properties":{"code":{"description":"Category code, a short lower-case token used as the value of expenses.category. Example: groceries","type":"string"},"description":{"description":"What belongs in this category, written for the assistant choosing it.","type":"string"}},"required":["code","description"],"type":"object"},"ReimbursementBody":{"description":"Body of a reimbursement change over REST; the entry's id is in the path.","properties":{"reimbursement":{"description":"The new state: personal, claimable, claimed or paid. Example: claimed","type":"string"}},"required":["reimbursement"],"type":"object"},"Report":{"description":"A report over the current ledger: sums per group and currency, computed by the service.","properties":{"from":{"description":"The lower date bound that was applied, or the empty string for none.","type":"string"},"group_by":{"description":"The grouping that was applied.","type":"string"},"rows":{"description":"The rows, largest sum first within each currency.","items":{"description":"One row of a report.","properties":{"currency":{"description":"ISO 4217 code of the currency the amounts are in. Rows never mix currencies.","type":"string"},"entries":{"description":"How many current entries contributed.","format":"int64","type":"integer"},"key":{"description":"The group: a category code, a merchant, a month as YYYY-MM, a label, or total.","type":"string"},"total":{"description":"Sum of the group as a decimal in the currency. Example: 2506.50","type":"string"},"total_minor":{"description":"Sum of the group in minor units of the currency.","format":"int64","type":"integer"}},"required":["key","currency","total","total_minor","entries"],"type":"object"},"type":"array"},"to":{"description":"The upper date bound that was applied, or the empty string for none.","type":"string"}},"required":["from","to","group_by","rows"],"type":"object"},"ReportRow":{"description":"One row of a report.","properties":{"currency":{"description":"ISO 4217 code of the currency the amounts are in. Rows never mix currencies.","type":"string"},"entries":{"description":"How many current entries contributed.","format":"int64","type":"integer"},"key":{"description":"The group: a category code, a merchant, a month as YYYY-MM, a label, or total.","type":"string"},"total":{"description":"Sum of the group as a decimal in the currency. Example: 2506.50","type":"string"},"total_minor":{"description":"Sum of the group in minor units of the currency.","format":"int64","type":"integer"}},"required":["key","currency","total","total_minor","entries"],"type":"object"},"RestoreBody":{"description":"Body of a restore over REST; the entry's id is in the path.","properties":{"reason":{"description":"Why the void is being undone, in the owner's words. Example: it was not a duplicate after all","type":"string"}},"required":["reason"],"type":"object"},"SetBudget":{"description":"A monthly budget for one of the owner's categories in one currency: created on the first setting, changed by a new amount, removed by zero.","properties":{"amount":{"description":"The monthly amount as a decimal in the currency, or 0 to remove the budget. Digits with an optional decimal point, no sign. Example: 2500.00","type":"string"},"category":{"description":"Category code the budget applies to, one of the owner's active categories. Example: groceries","type":"string"},"currency":{"description":"ISO 4217 code of the currency the budget is in; spending in other currencies does not count against it. Example: SEK","type":"string"}},"required":["category","currency","amount"],"type":"object"},"VoidBody":{"description":"Body of a void over REST; the entry's id is in the path.","properties":{"reason":{"description":"Why the entry is being voided, in the owner's words. Example: logged twice","type":"string"}},"required":["reason"],"type":"object"},"Voided":{"description":"Confirmation that an entry was voided.","properties":{"id":{"description":"The entry that was voided.","format":"uuid","type":"string"},"reason":{"description":"Why the entry was voided, in the owner's words.","type":"string"},"voided_at":{"description":"When the void was recorded, RFC 3339 with time zone.","type":"string"}},"required":["id","voided_at","reason"],"type":"object"}},"securitySchemes":{"bearer":{"bearerFormat":"opaque","scheme":"bearer","type":"http"}}},"info":{"description":"Headless expense ledger for AI assistants. Record what a receipt says; the service validates it and stores it under the owner's identity, in the receipt's own currency. Amounts are decimal strings exactly as printed. Access needs an OAuth bearer token granted by the owner.","license":{"name":"proprietary"},"title":"Spendpoint","version":"0.1.0"},"openapi":"3.1.0","paths":{"/budgets":{"get":{"description":"Budgets are judged by calendar month of the purchase date, counting the current entries'\nlines in the budget's category and currency. The service reports, it never blocks.","operationId":"budgets_handler","parameters":[{"description":"The calendar month as YYYY-MM. Empty for the current month.","in":"query","name":"month","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetList"}}},"description":"The budgets above zero, in category order"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The month was refused"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:read scope"}},"security":[{"bearer":["expenses:read"]}],"summary":"Every budget with its standing in a month.","tags":["budgets"]},"post":{"description":"One budget per category and currency. Zero removes it; the row stays, so nothing is deleted.\nThe answer is the budget's standing in the current month.","operationId":"set_budget_handler","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetBudget"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetStatus"}}},"description":"The budget with this month's standing"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The category, currency or amount was refused"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:write scope"}},"security":[{"bearer":["expenses:write"]}],"summary":"Set, change or remove a monthly budget.","tags":["budgets"]}},"/categories":{"get":{"operationId":"list_categories_handler","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryList"}}},"description":"Every category in code order"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"}},"security":[{"bearer":[]}],"summary":"List every category, active and retired.","tags":["categories"]},"post":{"description":"Codes are permanent and lower-case; the meaning is what the assistant reads when choosing.","operationId":"add_category_handler","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NewCategory"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"The category as stored"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The code or meaning was refused, or the code exists"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:write scope"}},"security":[{"bearer":["expenses:write"]}],"summary":"Add a category.","tags":["categories"]}},"/categories/{code}":{"put":{"description":"The code never changes and nothing is deleted; a retired category stops being offered but\nstays on the entries that use it.","operationId":"update_category_handler","parameters":[{"description":"The category code","in":"path","name":"code","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CategoryBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Category"}}},"description":"The category as stored"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The meaning was refused, the code is unknown, or unknown cannot be retired"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:write scope"}},"security":[{"bearer":["expenses:write"]}],"summary":"Change a category's meaning or retire it.","tags":["categories"]}},"/connections":{"get":{"operationId":"list_connections_handler","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionList"}}},"description":"The live connections, oldest first"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"}},"security":[{"bearer":[]}],"summary":"Every assistant connected to this ledger, with the one making the call marked.","tags":["connections"]}},"/connections/{id}/end":{"post":{"description":"Ending the connection that makes the call is allowed and takes effect after this answer.","operationId":"end_connection_handler","parameters":[{"description":"The connection, from the list","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectionEnded"}}},"description":"Confirmation"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"No such live connection of this owner"}},"security":[{"bearer":[]}],"summary":"End a connection: its tokens stop working at once; the entries it recorded stay.","tags":["connections"]}},"/dictionary":{"get":{"operationId":"dictionary_handler","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Dictionary"}}},"description":"The dictionary"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"}},"security":[{"bearer":[]}],"summary":"The data dictionary: every table, view and column with its meaning, from the database catalog.","tags":["categories"]}},"/expenses":{"get":{"operationId":"list_handler","parameters":[{"description":"Earliest purchase date to include, YYYY-MM-DD. Empty for no lower bound.","in":"query","name":"from","required":false,"schema":{"type":"string"}},{"description":"Latest purchase date to include, YYYY-MM-DD. Empty for no upper bound.","in":"query","name":"to","required":false,"schema":{"type":"string"}},{"description":"Only entries in this category code. Empty for all.","in":"query","name":"category","required":false,"schema":{"type":"string"}},{"description":"Only merchants containing this text, case-insensitive. Empty for all.","in":"query","name":"merchant","required":false,"schema":{"type":"string"}},{"description":"Only entries in this ISO 4217 currency. Empty for all.","in":"query","name":"currency","required":false,"schema":{"type":"string"}},{"description":"Only entries with this label, compared without regard to case. Empty for all.","in":"query","name":"label","required":false,"schema":{"type":"string"}},{"description":"Only entries in this reimbursement state: personal, claimable, claimed or paid. Empty for all.","in":"query","name":"reimbursement","required":false,"schema":{"type":"string"}},{"description":"Entries per page, 1 to 200. Defaults to 50.","in":"query","name":"limit","required":false,"schema":{"format":"int32","minimum":0,"type":"integer"}},{"description":"Entries to skip, for paging. Defaults to 0.","in":"query","name":"offset","required":false,"schema":{"format":"int32","minimum":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExpenseList"}}},"description":"A page of entries and the total match count"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"A filter was refused"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:read scope"}},"security":[{"bearer":["expenses:read"]}],"summary":"List current entries, newest purchase first, with optional filters and paging.","tags":["expenses"]},"post":{"description":"Call this once per receipt. Always include the verbatim transcription. If the date or the\ntotal is not legible, ask the owner rather than guess. After the entry is stored, read it\nback to the owner so they can confirm what was recorded.","operationId":"capture","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CaptureReceipt"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Expense"}}},"description":"The entry as stored"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"An input was refused; the body says which and why"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:write scope"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"A current entry with the same merchant, date and total exists; resend with confirm_duplicate after the owner confirms"}},"security":[{"bearer":["expenses:write"]}],"summary":"Record one expense from a receipt the owner has shown their assistant.","tags":["expenses"]}},"/expenses/{id}":{"get":{"operationId":"get_handler","parameters":[{"description":"The entry","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Expense"}}},"description":"The entry"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:read scope"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"No such entry in this ledger"}},"security":[{"bearer":["expenses:read"]}],"summary":"One entry in full, with its lines and transcription, current or retired.","tags":["expenses"]}},"/expenses/{id}/amend":{"post":{"description":"The original entry is kept, retired and linked to the replacement. Send the complete\ncorrected receipt, every field and every line, not only what changed.","operationId":"amend_handler","parameters":[{"description":"The entry to correct, as returned when it was recorded","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AmendBody"}}},"required":true},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Expense"}}},"description":"The corrected entry as stored"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"An input was refused, or the id is not a current entry"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:write scope"}},"security":[{"bearer":["expenses:write"]}],"summary":"Correct a stored entry by replacing it.","tags":["expenses"]}},"/expenses/{id}/reimbursement":{"post":{"description":"The change is appended to the entry's history; the entry itself is not edited. The same\nstate again changes nothing. The entry comes back as it now stands.","operationId":"reimbursement_handler","parameters":[{"description":"The entry, as returned when it was recorded or listed","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReimbursementBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Expense"}}},"description":"The entry with its new state"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The state was refused, or the id is not a current entry"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:write scope"}},"security":[{"bearer":["expenses:write"]}],"summary":"Note a new reimbursement state on an entry.","tags":["expenses"]}},"/expenses/{id}/restore":{"post":{"description":"Only a void can be undone; an amended entry has its replacement. Refused while a current\nentry would duplicate the restored one. The void's row keeps when and why it was undone.","operationId":"restore_handler","parameters":[{"description":"The voided entry, as returned when it was recorded or listed","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Expense"}}},"description":"The entry, current again"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The reason was refused, the id is not a voided entry, or a current entry matches it"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:write scope"},"429":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The daily limit on voids, amendments and restores is reached"}},"security":[{"bearer":["expenses:write"]}],"summary":"Undo a void: bring a voided entry back into the ledger.","tags":["expenses"]}},"/expenses/{id}/void":{"post":{"description":"The entry stays on record for audit but leaves the ledger.","operationId":"void_handler","parameters":[{"description":"The entry to void, as returned when it was recorded","in":"path","name":"id","required":true,"schema":{"format":"uuid","type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoidBody"}}},"required":true},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Voided"}}},"description":"Confirmation of the void"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The reason was refused, or the id is not a current entry"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:write scope"}},"security":[{"bearer":["expenses:write"]}],"summary":"Void a stored entry that should never have been recorded.","tags":["expenses"]}},"/export":{"get":{"operationId":"export_handler","parameters":[{"description":"json for the structured bundle with categories and full entries; csv for one row per entry; csv_lines for one row per receipt line; csv_vat for one row per printed VAT rate. Defaults to json.","in":"query","name":"format","required":false,"schema":{"type":"string"}},{"description":"Include entries that were amended or voided, flagged. Defaults to false.","in":"query","name":"include_retired","required":false,"schema":{"type":"boolean"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportBundle"}}},"description":"The ledger, as application/json or text/csv"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Unknown format"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:read scope"}},"security":[{"bearer":["expenses:read"]}],"summary":"The whole ledger as a file: JSON with categories and full entries, or CSV of entries or of lines.","tags":["expenses"]}},"/report":{"get":{"operationId":"report_handler","parameters":[{"description":"Earliest purchase date to include, YYYY-MM-DD. Empty for no lower bound.","in":"query","name":"from","required":false,"schema":{"type":"string"}},{"description":"Latest purchase date to include, YYYY-MM-DD. Empty for no upper bound.","in":"query","name":"to","required":false,"schema":{"type":"string"}},{"description":"How to group: category (by the category of each receipt line, so split receipts count truthfully), merchant, month, label, or total. Defaults to category.","in":"query","name":"group_by","required":false,"schema":{"type":"string"}},{"description":"Only entries in this ISO 4217 currency. Empty for all; amounts are never converted, so each currency reports separately.","in":"query","name":"currency","required":false,"schema":{"type":"string"}},{"description":"Only entries with this label, compared without regard to case. Empty for all.","in":"query","name":"label","required":false,"schema":{"type":"string"}},{"description":"Only entries in this reimbursement state: personal, claimable, claimed or paid. Empty for all.","in":"query","name":"reimbursement","required":false,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}},"description":"The report"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"A parameter was refused"},"401":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"Missing or invalid access token"},"403":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}},"description":"The grant lacks the expenses:read scope"}},"security":[{"bearer":["expenses:read"]}],"summary":"Sums over current entries per group and currency, computed by the service.","tags":["expenses"]}}},"servers":[{"url":"https://spendpoint.ai"}],"tags":[{"description":"The ledger","name":"expenses"},{"description":"Monthly budgets per category and currency, and how the month stands against them","name":"budgets"},{"description":"The controlled list the ledger is classified by, and the dictionary that describes the data","name":"categories"},{"description":"The assistants the owner has connected, and how to disconnect one","name":"connections"}]}