mirror of
https://github.com/we-promise/sure.git
synced 2026-05-08 05:04:59 +00:00
* feat(api): support idempotent valuation writes * fix(api): clarify valuation upsert status * docs(api): document nested valuation upserts * docs(api): clarify valuation upsert semantics * docs(api): clarify valuation upsert signaling
4685 lines
125 KiB
YAML
4685 lines
125 KiB
YAML
---
|
|
openapi: 3.0.3
|
|
info:
|
|
title: Sure API
|
|
version: v1
|
|
description: OpenAPI documentation generated from executable request specs.
|
|
servers:
|
|
- url: https://app.sure.am
|
|
description: Production
|
|
- url: http://localhost:3000
|
|
description: Local development
|
|
components:
|
|
securitySchemes:
|
|
apiKeyAuth:
|
|
type: apiKey
|
|
name: X-Api-Key
|
|
in: header
|
|
description: API key for authentication. Generate one from your account settings.
|
|
schemas:
|
|
Pagination:
|
|
type: object
|
|
required:
|
|
- page
|
|
- per_page
|
|
- total_count
|
|
- total_pages
|
|
properties:
|
|
page:
|
|
type: integer
|
|
minimum: 1
|
|
per_page:
|
|
type: integer
|
|
minimum: 1
|
|
total_count:
|
|
type: integer
|
|
minimum: 0
|
|
total_pages:
|
|
type: integer
|
|
minimum: 0
|
|
FamilyExportFile:
|
|
type: object
|
|
required:
|
|
- attached
|
|
properties:
|
|
attached:
|
|
type: boolean
|
|
byte_size:
|
|
type: integer
|
|
nullable: true
|
|
minimum: 0
|
|
content_type:
|
|
type: string
|
|
nullable: true
|
|
FamilyExport:
|
|
type: object
|
|
required:
|
|
- id
|
|
- status
|
|
- filename
|
|
- downloadable
|
|
- file
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
status:
|
|
type: string
|
|
enum:
|
|
- pending
|
|
- processing
|
|
- completed
|
|
- failed
|
|
filename:
|
|
type: string
|
|
downloadable:
|
|
type: boolean
|
|
download_path:
|
|
type: string
|
|
nullable: true
|
|
file:
|
|
"$ref": "#/components/schemas/FamilyExportFile"
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
FamilyExportResponse:
|
|
type: object
|
|
required:
|
|
- data
|
|
properties:
|
|
data:
|
|
"$ref": "#/components/schemas/FamilyExport"
|
|
FamilyExportCollection:
|
|
type: object
|
|
required:
|
|
- data
|
|
- meta
|
|
properties:
|
|
data:
|
|
type: array
|
|
maxItems: 100
|
|
items:
|
|
"$ref": "#/components/schemas/FamilyExport"
|
|
meta:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
ErrorResponse:
|
|
type: object
|
|
required:
|
|
- error
|
|
properties:
|
|
error:
|
|
type: string
|
|
message:
|
|
type: string
|
|
nullable: true
|
|
details:
|
|
oneOf:
|
|
- type: array
|
|
items:
|
|
type: string
|
|
- type: object
|
|
nullable: true
|
|
errors:
|
|
type: array
|
|
items:
|
|
type: string
|
|
nullable: true
|
|
description: Validation error messages (alternative to details used by trades,
|
|
valuations, etc.)
|
|
ErrorResponseWithImportId:
|
|
type: object
|
|
required:
|
|
- error
|
|
- import_id
|
|
properties:
|
|
error:
|
|
type: string
|
|
message:
|
|
type: string
|
|
nullable: true
|
|
import_id:
|
|
type: string
|
|
format: uuid
|
|
description: Import ID preserved for retry or inspection after upload succeeds
|
|
but publish fails
|
|
MfaRequiredResponse:
|
|
type: object
|
|
required:
|
|
- error
|
|
- mfa_required
|
|
properties:
|
|
error:
|
|
type: string
|
|
mfa_required:
|
|
type: boolean
|
|
ToolCall:
|
|
type: object
|
|
required:
|
|
- id
|
|
- function_name
|
|
- function_arguments
|
|
- created_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
function_name:
|
|
type: string
|
|
function_arguments:
|
|
type: object
|
|
additionalProperties: true
|
|
function_result:
|
|
type: object
|
|
additionalProperties: true
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
Message:
|
|
type: object
|
|
required:
|
|
- id
|
|
- type
|
|
- role
|
|
- content
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
type:
|
|
type: string
|
|
enum:
|
|
- user_message
|
|
- assistant_message
|
|
role:
|
|
type: string
|
|
enum:
|
|
- user
|
|
- assistant
|
|
content:
|
|
type: string
|
|
model:
|
|
type: string
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
tool_calls:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/ToolCall"
|
|
nullable: true
|
|
MessageResponse:
|
|
allOf:
|
|
- "$ref": "#/components/schemas/Message"
|
|
- type: object
|
|
required:
|
|
- chat_id
|
|
properties:
|
|
chat_id:
|
|
type: string
|
|
format: uuid
|
|
ai_response_status:
|
|
type: string
|
|
enum:
|
|
- pending
|
|
- complete
|
|
- failed
|
|
nullable: true
|
|
ai_response_message:
|
|
type: string
|
|
nullable: true
|
|
ChatResource:
|
|
type: object
|
|
required:
|
|
- id
|
|
- title
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
title:
|
|
type: string
|
|
error:
|
|
type: string
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
ChatSummary:
|
|
allOf:
|
|
- "$ref": "#/components/schemas/ChatResource"
|
|
- type: object
|
|
required:
|
|
- message_count
|
|
properties:
|
|
message_count:
|
|
type: integer
|
|
minimum: 0
|
|
last_message_at:
|
|
type: string
|
|
format: date-time
|
|
nullable: true
|
|
ChatDetail:
|
|
allOf:
|
|
- "$ref": "#/components/schemas/ChatResource"
|
|
- type: object
|
|
required:
|
|
- messages
|
|
properties:
|
|
messages:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/Message"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
nullable: true
|
|
ChatCollection:
|
|
type: object
|
|
required:
|
|
- chats
|
|
- pagination
|
|
properties:
|
|
chats:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/ChatSummary"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
RetryResponse:
|
|
type: object
|
|
required:
|
|
- message
|
|
- message_id
|
|
properties:
|
|
message:
|
|
type: string
|
|
message_id:
|
|
type: string
|
|
format: uuid
|
|
Account:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
- account_type
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
account_type:
|
|
type: string
|
|
nullable: true
|
|
status:
|
|
type: string
|
|
AccountDetail:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
- balance
|
|
- balance_cents
|
|
- cash_balance
|
|
- cash_balance_cents
|
|
- currency
|
|
- classification
|
|
- account_type
|
|
- status
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
balance:
|
|
type: string
|
|
balance_cents:
|
|
type: integer
|
|
description: Signed balance in minor currency units
|
|
cash_balance:
|
|
type: string
|
|
cash_balance_cents:
|
|
type: integer
|
|
description: Signed cash balance in minor currency units
|
|
currency:
|
|
type: string
|
|
classification:
|
|
type: string
|
|
account_type:
|
|
type: string
|
|
nullable: true
|
|
subtype:
|
|
type: string
|
|
nullable: true
|
|
status:
|
|
type: string
|
|
enum:
|
|
- active
|
|
- draft
|
|
- disabled
|
|
- pending_deletion
|
|
institution_name:
|
|
type: string
|
|
nullable: true
|
|
institution_domain:
|
|
type: string
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
AccountCollection:
|
|
type: object
|
|
required:
|
|
- accounts
|
|
- pagination
|
|
properties:
|
|
accounts:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/AccountDetail"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
FamilySettings:
|
|
type: object
|
|
required:
|
|
- id
|
|
- currency
|
|
- locale
|
|
- date_format
|
|
- month_start_day
|
|
- moniker
|
|
- default_account_sharing
|
|
- custom_enabled_currencies
|
|
- enabled_currencies
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
nullable: true
|
|
currency:
|
|
type: string
|
|
locale:
|
|
type: string
|
|
date_format:
|
|
type: string
|
|
country:
|
|
type: string
|
|
nullable: true
|
|
timezone:
|
|
type: string
|
|
nullable: true
|
|
month_start_day:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 28
|
|
moniker:
|
|
type: string
|
|
enum:
|
|
- Family
|
|
- Group
|
|
default_account_sharing:
|
|
type: string
|
|
enum:
|
|
- shared
|
|
- private
|
|
custom_enabled_currencies:
|
|
type: boolean
|
|
enabled_currencies:
|
|
type: array
|
|
items:
|
|
type: string
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
Category:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
- color
|
|
- icon
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
color:
|
|
type: string
|
|
icon:
|
|
type: string
|
|
CategoryParent:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
CategoryDetail:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
- color
|
|
- icon
|
|
- subcategories_count
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
color:
|
|
type: string
|
|
icon:
|
|
type: string
|
|
parent:
|
|
"$ref": "#/components/schemas/CategoryParent"
|
|
nullable: true
|
|
subcategories_count:
|
|
type: integer
|
|
minimum: 0
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
CategoryCollection:
|
|
type: object
|
|
required:
|
|
- categories
|
|
- pagination
|
|
properties:
|
|
categories:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/CategoryDetail"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
Merchant:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
MerchantDetail:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
- type
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
type:
|
|
type: string
|
|
enum:
|
|
- FamilyMerchant
|
|
- ProviderMerchant
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
Tag:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
- color
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
color:
|
|
type: string
|
|
TagDetail:
|
|
type: object
|
|
required:
|
|
- id
|
|
- name
|
|
- color
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
color:
|
|
type: string
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
TagCollection:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/TagDetail"
|
|
RuleAction:
|
|
type: object
|
|
required:
|
|
- id
|
|
- action_type
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
action_type:
|
|
type: string
|
|
value:
|
|
type: string
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
RuleCondition:
|
|
type: object
|
|
required:
|
|
- id
|
|
- condition_type
|
|
- operator
|
|
- sub_conditions
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
condition_type:
|
|
type: string
|
|
operator:
|
|
type: string
|
|
value:
|
|
type: string
|
|
nullable: true
|
|
sub_conditions:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/RuleCondition"
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
Rule:
|
|
type: object
|
|
required:
|
|
- id
|
|
- resource_type
|
|
- active
|
|
- conditions
|
|
- actions
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
nullable: true
|
|
resource_type:
|
|
type: string
|
|
enum:
|
|
- transaction
|
|
active:
|
|
type: boolean
|
|
effective_date:
|
|
type: string
|
|
format: date
|
|
nullable: true
|
|
conditions:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/RuleCondition"
|
|
actions:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/RuleAction"
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
RuleResponse:
|
|
type: object
|
|
required:
|
|
- data
|
|
properties:
|
|
data:
|
|
"$ref": "#/components/schemas/Rule"
|
|
RuleCollection:
|
|
type: object
|
|
required:
|
|
- data
|
|
- meta
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/Rule"
|
|
meta:
|
|
type: object
|
|
required:
|
|
- current_page
|
|
- total_pages
|
|
- total_count
|
|
- per_page
|
|
properties:
|
|
current_page:
|
|
type: integer
|
|
next_page:
|
|
type: integer
|
|
nullable: true
|
|
prev_page:
|
|
type: integer
|
|
nullable: true
|
|
total_pages:
|
|
type: integer
|
|
total_count:
|
|
type: integer
|
|
per_page:
|
|
type: integer
|
|
RuleRun:
|
|
type: object
|
|
required:
|
|
- id
|
|
- rule_id
|
|
- rule_name
|
|
- execution_type
|
|
- status
|
|
- transactions_queued
|
|
- transactions_processed
|
|
- transactions_modified
|
|
- pending_jobs_count
|
|
- executed_at
|
|
- rule
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
rule_id:
|
|
type: string
|
|
format: uuid
|
|
rule_name:
|
|
type: string
|
|
nullable: true
|
|
execution_type:
|
|
type: string
|
|
enum:
|
|
- manual
|
|
- scheduled
|
|
status:
|
|
type: string
|
|
enum:
|
|
- pending
|
|
- success
|
|
- failed
|
|
transactions_queued:
|
|
type: integer
|
|
minimum: 0
|
|
transactions_processed:
|
|
type: integer
|
|
minimum: 0
|
|
transactions_modified:
|
|
type: integer
|
|
minimum: 0
|
|
pending_jobs_count:
|
|
type: integer
|
|
minimum: 0
|
|
executed_at:
|
|
type: string
|
|
format: date-time
|
|
error_message:
|
|
type: string
|
|
nullable: true
|
|
rule:
|
|
type: object
|
|
nullable: true
|
|
required:
|
|
- id
|
|
- resource_type
|
|
- active
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
nullable: true
|
|
resource_type:
|
|
type: string
|
|
active:
|
|
type: boolean
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
RuleRunResponse:
|
|
type: object
|
|
required:
|
|
- data
|
|
properties:
|
|
data:
|
|
"$ref": "#/components/schemas/RuleRun"
|
|
RuleRunCollection:
|
|
type: object
|
|
required:
|
|
- data
|
|
- meta
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/RuleRun"
|
|
meta:
|
|
type: object
|
|
required:
|
|
- current_page
|
|
- total_pages
|
|
- total_count
|
|
- per_page
|
|
properties:
|
|
current_page:
|
|
type: integer
|
|
next_page:
|
|
type: integer
|
|
nullable: true
|
|
prev_page:
|
|
type: integer
|
|
nullable: true
|
|
total_pages:
|
|
type: integer
|
|
total_count:
|
|
type: integer
|
|
per_page:
|
|
type: integer
|
|
Transfer:
|
|
type: object
|
|
required:
|
|
- id
|
|
- amount
|
|
- currency
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
amount:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
other_account:
|
|
"$ref": "#/components/schemas/Account"
|
|
nullable: true
|
|
RecurringTransaction:
|
|
type: object
|
|
required:
|
|
- id
|
|
- amount
|
|
- amount_cents
|
|
- currency
|
|
- expected_day_of_month
|
|
- last_occurrence_date
|
|
- next_expected_date
|
|
- status
|
|
- occurrence_count
|
|
- manual
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
amount:
|
|
type: string
|
|
amount_cents:
|
|
type: integer
|
|
description: Amount in currency minor units
|
|
currency:
|
|
type: string
|
|
expected_day_of_month:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 31
|
|
last_occurrence_date:
|
|
type: string
|
|
format: date
|
|
next_expected_date:
|
|
type: string
|
|
format: date
|
|
status:
|
|
type: string
|
|
enum:
|
|
- active
|
|
- inactive
|
|
occurrence_count:
|
|
type: integer
|
|
minimum: 0
|
|
name:
|
|
type: string
|
|
nullable: true
|
|
manual:
|
|
type: boolean
|
|
expected_amount_min:
|
|
type: string
|
|
nullable: true
|
|
expected_amount_min_cents:
|
|
type: integer
|
|
nullable: true
|
|
description: Minimum expected amount in currency minor units
|
|
expected_amount_max:
|
|
type: string
|
|
nullable: true
|
|
expected_amount_max_cents:
|
|
type: integer
|
|
nullable: true
|
|
description: Maximum expected amount in currency minor units
|
|
expected_amount_avg:
|
|
type: string
|
|
nullable: true
|
|
expected_amount_avg_cents:
|
|
type: integer
|
|
nullable: true
|
|
description: Average expected amount in currency minor units
|
|
account:
|
|
"$ref": "#/components/schemas/Account"
|
|
nullable: true
|
|
merchant:
|
|
"$ref": "#/components/schemas/Merchant"
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
RecurringTransactionCollection:
|
|
type: object
|
|
required:
|
|
- recurring_transactions
|
|
- pagination
|
|
properties:
|
|
recurring_transactions:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/RecurringTransaction"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
Transaction:
|
|
type: object
|
|
required:
|
|
- id
|
|
- date
|
|
- amount
|
|
- currency
|
|
- name
|
|
- classification
|
|
- account
|
|
- tags
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
date:
|
|
type: string
|
|
format: date
|
|
amount:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
name:
|
|
type: string
|
|
notes:
|
|
type: string
|
|
nullable: true
|
|
classification:
|
|
type: string
|
|
account:
|
|
"$ref": "#/components/schemas/Account"
|
|
category:
|
|
"$ref": "#/components/schemas/Category"
|
|
nullable: true
|
|
merchant:
|
|
"$ref": "#/components/schemas/Merchant"
|
|
nullable: true
|
|
tags:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/Tag"
|
|
transfer:
|
|
"$ref": "#/components/schemas/Transfer"
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
TransactionCollection:
|
|
type: object
|
|
required:
|
|
- transactions
|
|
- pagination
|
|
properties:
|
|
transactions:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/Transaction"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
Valuation:
|
|
type: object
|
|
required:
|
|
- id
|
|
- date
|
|
- amount
|
|
- currency
|
|
- kind
|
|
- account
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
date:
|
|
type: string
|
|
format: date
|
|
amount:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
notes:
|
|
type: string
|
|
nullable: true
|
|
kind:
|
|
type: string
|
|
account:
|
|
"$ref": "#/components/schemas/Account"
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
ValuationCollection:
|
|
type: object
|
|
required:
|
|
- valuations
|
|
- pagination
|
|
properties:
|
|
valuations:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/Valuation"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
DeleteResponse:
|
|
type: object
|
|
required:
|
|
- message
|
|
properties:
|
|
message:
|
|
type: string
|
|
ImportConfiguration:
|
|
type: object
|
|
properties:
|
|
date_col_label:
|
|
type: string
|
|
nullable: true
|
|
amount_col_label:
|
|
type: string
|
|
nullable: true
|
|
name_col_label:
|
|
type: string
|
|
nullable: true
|
|
category_col_label:
|
|
type: string
|
|
nullable: true
|
|
tags_col_label:
|
|
type: string
|
|
nullable: true
|
|
notes_col_label:
|
|
type: string
|
|
nullable: true
|
|
account_col_label:
|
|
type: string
|
|
nullable: true
|
|
date_format:
|
|
type: string
|
|
nullable: true
|
|
number_format:
|
|
type: string
|
|
nullable: true
|
|
signage_convention:
|
|
type: string
|
|
nullable: true
|
|
ImportStats:
|
|
type: object
|
|
required:
|
|
- rows_count
|
|
- valid_rows_count
|
|
- invalid_rows_count
|
|
- mappings_count
|
|
- unassigned_mappings_count
|
|
properties:
|
|
rows_count:
|
|
type: integer
|
|
minimum: 0
|
|
valid_rows_count:
|
|
type: integer
|
|
minimum: 0
|
|
invalid_rows_count:
|
|
type: integer
|
|
minimum: 0
|
|
mappings_count:
|
|
type: integer
|
|
minimum: 0
|
|
unassigned_mappings_count:
|
|
type: integer
|
|
minimum: 0
|
|
ImportStatusSummary:
|
|
type: object
|
|
required:
|
|
- uploaded
|
|
- configured
|
|
- terminal
|
|
properties:
|
|
uploaded:
|
|
type: boolean
|
|
configured:
|
|
type: boolean
|
|
terminal:
|
|
type: boolean
|
|
ImportStatusDetail:
|
|
allOf:
|
|
- "$ref": "#/components/schemas/ImportStatusSummary"
|
|
- type: object
|
|
required:
|
|
- cleaned
|
|
- publishable
|
|
- revertable
|
|
properties:
|
|
cleaned:
|
|
type: boolean
|
|
publishable:
|
|
type: boolean
|
|
revertable:
|
|
type: boolean
|
|
ImportSummary:
|
|
type: object
|
|
required:
|
|
- id
|
|
- type
|
|
- status
|
|
- created_at
|
|
- updated_at
|
|
- status_detail
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
type:
|
|
type: string
|
|
enum:
|
|
- TransactionImport
|
|
- TradeImport
|
|
- AccountImport
|
|
- MintImport
|
|
- CategoryImport
|
|
- RuleImport
|
|
- SureImport
|
|
status:
|
|
type: string
|
|
enum:
|
|
- pending
|
|
- complete
|
|
- importing
|
|
- reverting
|
|
- revert_failed
|
|
- failed
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
account_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
rows_count:
|
|
type: integer
|
|
minimum: 0
|
|
error:
|
|
type: string
|
|
nullable: true
|
|
status_detail:
|
|
"$ref": "#/components/schemas/ImportStatusSummary"
|
|
ImportDetail:
|
|
type: object
|
|
required:
|
|
- id
|
|
- type
|
|
- status
|
|
- created_at
|
|
- updated_at
|
|
- status_detail
|
|
- configuration
|
|
- stats
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
type:
|
|
type: string
|
|
enum:
|
|
- TransactionImport
|
|
- TradeImport
|
|
- AccountImport
|
|
- MintImport
|
|
- CategoryImport
|
|
- RuleImport
|
|
- SureImport
|
|
status:
|
|
type: string
|
|
enum:
|
|
- pending
|
|
- complete
|
|
- importing
|
|
- reverting
|
|
- revert_failed
|
|
- failed
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
account_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
error:
|
|
type: string
|
|
nullable: true
|
|
status_detail:
|
|
"$ref": "#/components/schemas/ImportStatusDetail"
|
|
configuration:
|
|
"$ref": "#/components/schemas/ImportConfiguration"
|
|
stats:
|
|
"$ref": "#/components/schemas/ImportStats"
|
|
ImportCollection:
|
|
type: object
|
|
required:
|
|
- data
|
|
- meta
|
|
properties:
|
|
data:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/ImportSummary"
|
|
meta:
|
|
type: object
|
|
required:
|
|
- current_page
|
|
- total_pages
|
|
- total_count
|
|
- per_page
|
|
properties:
|
|
current_page:
|
|
type: integer
|
|
minimum: 1
|
|
next_page:
|
|
type: integer
|
|
nullable: true
|
|
prev_page:
|
|
type: integer
|
|
nullable: true
|
|
total_pages:
|
|
type: integer
|
|
minimum: 0
|
|
total_count:
|
|
type: integer
|
|
minimum: 0
|
|
per_page:
|
|
type: integer
|
|
minimum: 1
|
|
ImportResponse:
|
|
type: object
|
|
required:
|
|
- data
|
|
properties:
|
|
data:
|
|
"$ref": "#/components/schemas/ImportDetail"
|
|
Trade:
|
|
type: object
|
|
required:
|
|
- id
|
|
- date
|
|
- amount
|
|
- currency
|
|
- name
|
|
- qty
|
|
- price
|
|
- account
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
date:
|
|
type: string
|
|
format: date
|
|
amount:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
name:
|
|
type: string
|
|
notes:
|
|
type: string
|
|
nullable: true
|
|
qty:
|
|
type: string
|
|
price:
|
|
type: string
|
|
investment_activity_label:
|
|
type: string
|
|
nullable: true
|
|
account:
|
|
"$ref": "#/components/schemas/Account"
|
|
security:
|
|
type: object
|
|
nullable: true
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
ticker:
|
|
type: string
|
|
name:
|
|
type: string
|
|
nullable: true
|
|
category:
|
|
type: object
|
|
nullable: true
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
name:
|
|
type: string
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
TradeCollection:
|
|
type: object
|
|
required:
|
|
- trades
|
|
- pagination
|
|
properties:
|
|
trades:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/Trade"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
Holding:
|
|
type: object
|
|
required:
|
|
- id
|
|
- date
|
|
- qty
|
|
- price
|
|
- amount
|
|
- currency
|
|
- account
|
|
- security
|
|
- created_at
|
|
- updated_at
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
date:
|
|
type: string
|
|
format: date
|
|
qty:
|
|
type: string
|
|
description: Quantity of shares held
|
|
price:
|
|
type: string
|
|
description: Formatted price per share
|
|
amount:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
cost_basis_source:
|
|
type: string
|
|
nullable: true
|
|
account:
|
|
"$ref": "#/components/schemas/Account"
|
|
security:
|
|
type: object
|
|
required:
|
|
- id
|
|
- ticker
|
|
- name
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
ticker:
|
|
type: string
|
|
name:
|
|
type: string
|
|
nullable: true
|
|
avg_cost:
|
|
type: string
|
|
nullable: true
|
|
created_at:
|
|
type: string
|
|
format: date-time
|
|
updated_at:
|
|
type: string
|
|
format: date-time
|
|
HoldingCollection:
|
|
type: object
|
|
required:
|
|
- holdings
|
|
- pagination
|
|
properties:
|
|
holdings:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/Holding"
|
|
pagination:
|
|
"$ref": "#/components/schemas/Pagination"
|
|
Money:
|
|
type: object
|
|
required:
|
|
- amount
|
|
- currency
|
|
- formatted
|
|
properties:
|
|
amount:
|
|
type: string
|
|
description: Numeric amount as string
|
|
currency:
|
|
type: string
|
|
description: ISO 4217 currency code
|
|
formatted:
|
|
type: string
|
|
description: Locale-formatted money string
|
|
BalanceSheet:
|
|
type: object
|
|
required:
|
|
- currency
|
|
- net_worth
|
|
- assets
|
|
- liabilities
|
|
properties:
|
|
currency:
|
|
type: string
|
|
description: Family primary currency
|
|
net_worth:
|
|
"$ref": "#/components/schemas/Money"
|
|
assets:
|
|
"$ref": "#/components/schemas/Money"
|
|
liabilities:
|
|
"$ref": "#/components/schemas/Money"
|
|
SuccessMessage:
|
|
type: object
|
|
required:
|
|
- message
|
|
properties:
|
|
message:
|
|
type: string
|
|
ResetInitiatedResponse:
|
|
type: object
|
|
required:
|
|
- message
|
|
- status
|
|
- job_id
|
|
- family_id
|
|
- status_url
|
|
properties:
|
|
message:
|
|
type: string
|
|
status:
|
|
type: string
|
|
enum:
|
|
- queued
|
|
job_id:
|
|
type: string
|
|
description: Informational Active Job identifier returned by the queue adapter;
|
|
reset status is family-scoped, not job-scoped.
|
|
family_id:
|
|
type: string
|
|
format: uuid
|
|
description: UUID of the family being reset.
|
|
status_url:
|
|
type: string
|
|
ResetStatusResponse:
|
|
type: object
|
|
required:
|
|
- status
|
|
- family_id
|
|
- reset_complete
|
|
- counts
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum:
|
|
- complete
|
|
- data_remaining
|
|
description: Counts-based family reset status at response time.
|
|
family_id:
|
|
type: string
|
|
format: uuid
|
|
description: UUID of the family whose reset target counts were checked.
|
|
reset_complete:
|
|
type: boolean
|
|
description: True when all reset target counts are zero at response time.
|
|
This is a family data snapshot, not a durable per-job completion record.
|
|
counts:
|
|
type: object
|
|
required:
|
|
- accounts
|
|
- categories
|
|
- tags
|
|
- merchants
|
|
- plaid_items
|
|
- imports
|
|
- budgets
|
|
properties:
|
|
accounts:
|
|
type: integer
|
|
minimum: 0
|
|
categories:
|
|
type: integer
|
|
minimum: 0
|
|
tags:
|
|
type: integer
|
|
minimum: 0
|
|
merchants:
|
|
type: integer
|
|
minimum: 0
|
|
plaid_items:
|
|
type: integer
|
|
minimum: 0
|
|
imports:
|
|
type: integer
|
|
minimum: 0
|
|
budgets:
|
|
type: integer
|
|
minimum: 0
|
|
paths:
|
|
"/api/v1/accounts":
|
|
get:
|
|
summary: List accounts
|
|
tags:
|
|
- Accounts
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: include_disabled
|
|
in: query
|
|
required: false
|
|
description: Include disabled accounts in the response. Defaults to false.
|
|
schema:
|
|
type: boolean
|
|
responses:
|
|
'200':
|
|
description: accounts paginated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/AccountCollection"
|
|
"/api/v1/accounts/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Account ID
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
get:
|
|
summary: Retrieve an account
|
|
tags:
|
|
- Accounts
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: include_disabled
|
|
in: query
|
|
required: false
|
|
description: Allow retrieving a disabled account. Defaults to false.
|
|
schema:
|
|
type: boolean
|
|
responses:
|
|
'200':
|
|
description: account retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/AccountDetail"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: insufficient scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: account not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/auth/signup":
|
|
post:
|
|
summary: Sign up a new user
|
|
tags:
|
|
- Auth
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: user created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
access_token:
|
|
type: string
|
|
refresh_token:
|
|
type: string
|
|
token_type:
|
|
type: string
|
|
expires_in:
|
|
type: integer
|
|
created_at:
|
|
type: integer
|
|
user:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
ui_layout:
|
|
type: string
|
|
enum:
|
|
- dashboard
|
|
- intro
|
|
ai_enabled:
|
|
type: boolean
|
|
'422':
|
|
description: validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: invite code required or invalid
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
user:
|
|
type: object
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
description: User email address
|
|
password:
|
|
type: string
|
|
description: Password (min 8 chars, mixed case, number, special
|
|
char)
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
required:
|
|
- email
|
|
- password
|
|
device:
|
|
type: object
|
|
properties:
|
|
device_id:
|
|
type: string
|
|
description: Unique device identifier
|
|
device_name:
|
|
type: string
|
|
description: Human-readable device name
|
|
device_type:
|
|
type: string
|
|
description: Device type (e.g. ios, android)
|
|
os_version:
|
|
type: string
|
|
app_version:
|
|
type: string
|
|
required:
|
|
- device_id
|
|
- device_name
|
|
- device_type
|
|
- os_version
|
|
- app_version
|
|
invite_code:
|
|
type: string
|
|
nullable: true
|
|
description: Invite code (required when invites are enforced)
|
|
required:
|
|
- user
|
|
- device
|
|
required: true
|
|
"/api/v1/auth/login":
|
|
post:
|
|
summary: Log in with email and password
|
|
tags:
|
|
- Auth
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: login successful
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
access_token:
|
|
type: string
|
|
refresh_token:
|
|
type: string
|
|
token_type:
|
|
type: string
|
|
expires_in:
|
|
type: integer
|
|
created_at:
|
|
type: integer
|
|
user:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
ui_layout:
|
|
type: string
|
|
enum:
|
|
- dashboard
|
|
- intro
|
|
ai_enabled:
|
|
type: boolean
|
|
'401':
|
|
description: invalid credentials or MFA required
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
email:
|
|
type: string
|
|
format: email
|
|
password:
|
|
type: string
|
|
otp_code:
|
|
type: string
|
|
nullable: true
|
|
description: TOTP code if MFA is enabled
|
|
device:
|
|
type: object
|
|
properties:
|
|
device_id:
|
|
type: string
|
|
device_name:
|
|
type: string
|
|
device_type:
|
|
type: string
|
|
os_version:
|
|
type: string
|
|
app_version:
|
|
type: string
|
|
required:
|
|
- device_id
|
|
- device_name
|
|
- device_type
|
|
- os_version
|
|
- app_version
|
|
required:
|
|
- email
|
|
- password
|
|
- device
|
|
required: true
|
|
"/api/v1/auth/sso_exchange":
|
|
post:
|
|
summary: Exchange mobile SSO authorization code for tokens
|
|
tags:
|
|
- Auth
|
|
description: Exchanges a one-time authorization code (received via deep link
|
|
after mobile SSO) for OAuth tokens. The code is single-use and expires after
|
|
5 minutes.
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: tokens issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
access_token:
|
|
type: string
|
|
refresh_token:
|
|
type: string
|
|
token_type:
|
|
type: string
|
|
expires_in:
|
|
type: integer
|
|
created_at:
|
|
type: integer
|
|
user:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
ui_layout:
|
|
type: string
|
|
enum:
|
|
- dashboard
|
|
- intro
|
|
ai_enabled:
|
|
type: boolean
|
|
'401':
|
|
description: invalid or expired code
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
code:
|
|
type: string
|
|
description: One-time authorization code from mobile SSO callback
|
|
required:
|
|
- code
|
|
required: true
|
|
"/api/v1/auth/refresh":
|
|
post:
|
|
summary: Refresh an access token
|
|
tags:
|
|
- Auth
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: token refreshed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
access_token:
|
|
type: string
|
|
refresh_token:
|
|
type: string
|
|
token_type:
|
|
type: string
|
|
expires_in:
|
|
type: integer
|
|
created_at:
|
|
type: integer
|
|
'401':
|
|
description: invalid refresh token
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'400':
|
|
description: missing refresh token
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
refresh_token:
|
|
type: string
|
|
description: The refresh token from a previous login or refresh
|
|
device:
|
|
type: object
|
|
properties:
|
|
device_id:
|
|
type: string
|
|
required:
|
|
- device_id
|
|
required:
|
|
- refresh_token
|
|
- device
|
|
required: true
|
|
"/api/v1/auth/sso_link":
|
|
post:
|
|
summary: Link an existing account via SSO
|
|
tags:
|
|
- Auth
|
|
description: Authenticates with email/password and links the SSO identity from
|
|
a previously issued linking code. Creates an OidcIdentity, logs the link via
|
|
SsoAuditLog, and issues mobile OAuth tokens.
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: account linked and tokens issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
access_token:
|
|
type: string
|
|
refresh_token:
|
|
type: string
|
|
token_type:
|
|
type: string
|
|
expires_in:
|
|
type: integer
|
|
created_at:
|
|
type: integer
|
|
user:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
ui_layout:
|
|
type: string
|
|
enum:
|
|
- dashboard
|
|
- intro
|
|
ai_enabled:
|
|
type: boolean
|
|
'400':
|
|
description: missing linking code
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'401':
|
|
description: invalid credentials or expired linking code
|
|
content:
|
|
application/json:
|
|
schema:
|
|
oneOf:
|
|
- "$ref": "#/components/schemas/ErrorResponse"
|
|
- "$ref": "#/components/schemas/MfaRequiredResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
linking_code:
|
|
type: string
|
|
description: One-time linking code from mobile SSO onboarding redirect
|
|
email:
|
|
type: string
|
|
format: email
|
|
description: Email of the existing account to link
|
|
password:
|
|
type: string
|
|
description: Password for the existing account
|
|
required:
|
|
- linking_code
|
|
- email
|
|
- password
|
|
required: true
|
|
"/api/v1/auth/sso_create_account":
|
|
post:
|
|
summary: Create a new account via SSO
|
|
tags:
|
|
- Auth
|
|
description: Creates a new user and family from a previously issued linking
|
|
code. Links the SSO identity via OidcIdentity, logs the JIT account creation
|
|
via SsoAuditLog, and issues mobile OAuth tokens. The linking code must have
|
|
allow_account_creation enabled.
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: account created and tokens issued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
access_token:
|
|
type: string
|
|
refresh_token:
|
|
type: string
|
|
token_type:
|
|
type: string
|
|
expires_in:
|
|
type: integer
|
|
created_at:
|
|
type: integer
|
|
user:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
first_name:
|
|
type: string
|
|
last_name:
|
|
type: string
|
|
ui_layout:
|
|
type: string
|
|
enum:
|
|
- dashboard
|
|
- intro
|
|
ai_enabled:
|
|
type: boolean
|
|
'400':
|
|
description: missing linking code
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'401':
|
|
description: invalid or expired linking code
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: account creation disabled
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: user validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
errors:
|
|
type: array
|
|
items:
|
|
type: string
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
linking_code:
|
|
type: string
|
|
description: One-time linking code from mobile SSO onboarding redirect
|
|
first_name:
|
|
type: string
|
|
description: First name (overrides value from SSO provider if provided)
|
|
last_name:
|
|
type: string
|
|
description: Last name (overrides value from SSO provider if provided)
|
|
required:
|
|
- linking_code
|
|
required: true
|
|
"/api/v1/auth/enable_ai":
|
|
patch:
|
|
summary: Enable AI features for the authenticated user
|
|
tags:
|
|
- Auth
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: ai enabled
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
user:
|
|
type: object
|
|
properties:
|
|
id:
|
|
type: string
|
|
format: uuid
|
|
email:
|
|
type: string
|
|
first_name:
|
|
type: string
|
|
nullable: true
|
|
last_name:
|
|
type: string
|
|
nullable: true
|
|
ui_layout:
|
|
type: string
|
|
enum:
|
|
- dashboard
|
|
- intro
|
|
ai_enabled:
|
|
type: boolean
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: insufficient scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/balance_sheet":
|
|
get:
|
|
summary: Show balance sheet
|
|
tags:
|
|
- Balance Sheet
|
|
description: Returns the family balance sheet including net worth, total assets,
|
|
and total liabilities with amounts converted to the family's primary currency.
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: balance sheet returned
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/BalanceSheet"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/categories":
|
|
get:
|
|
summary: List categories
|
|
tags:
|
|
- Categories
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: roots_only
|
|
in: query
|
|
required: false
|
|
description: Return only root categories (no parent)
|
|
schema:
|
|
type: boolean
|
|
- name: parent_id
|
|
in: query
|
|
required: false
|
|
description: Filter by parent category ID
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: categories filtered by parent
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/CategoryCollection"
|
|
"/api/v1/categories/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Category ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve a category
|
|
tags:
|
|
- Categories
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: subcategory retrieved with parent
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/CategoryDetail"
|
|
'404':
|
|
description: category not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/chats":
|
|
get:
|
|
summary: List chats
|
|
tags:
|
|
- Chats
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: chats listed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ChatCollection"
|
|
'403':
|
|
description: AI features disabled
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
post:
|
|
summary: Create chat
|
|
tags:
|
|
- Chats
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: chat created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ChatDetail"
|
|
'422':
|
|
description: validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
title:
|
|
type: string
|
|
example: Monthly budget review
|
|
message:
|
|
type: string
|
|
description: Optional initial message in the chat
|
|
model:
|
|
type: string
|
|
description: Optional OpenAI model identifier
|
|
required:
|
|
- title
|
|
required: true
|
|
"/api/v1/chats/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Chat ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve a chat
|
|
tags:
|
|
- Chats
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: chat retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ChatDetail"
|
|
'404':
|
|
description: chat not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
patch:
|
|
summary: Update a chat
|
|
tags:
|
|
- Chats
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: chat updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ChatDetail"
|
|
'404':
|
|
description: chat not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
title:
|
|
type: string
|
|
example: Updated chat title
|
|
required: true
|
|
delete:
|
|
summary: Delete a chat
|
|
tags:
|
|
- Chats
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'204':
|
|
description: chat deleted
|
|
'404':
|
|
description: chat not found
|
|
"/api/v1/chats/{chat_id}/messages":
|
|
parameters:
|
|
- name: chat_id
|
|
in: path
|
|
required: true
|
|
description: Chat ID
|
|
schema:
|
|
type: string
|
|
post:
|
|
summary: Create a message
|
|
tags:
|
|
- Chat Messages
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: message created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/MessageResponse"
|
|
'404':
|
|
description: chat not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
content:
|
|
type: string
|
|
model:
|
|
type: string
|
|
required:
|
|
- content
|
|
required: true
|
|
"/api/v1/chats/{chat_id}/messages/retry":
|
|
parameters:
|
|
- name: chat_id
|
|
in: path
|
|
required: true
|
|
description: Chat ID
|
|
schema:
|
|
type: string
|
|
post:
|
|
summary: Retry the last assistant response
|
|
tags:
|
|
- Chat Messages
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'202':
|
|
description: retry started
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RetryResponse"
|
|
'404':
|
|
description: chat not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: no assistant message available
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/family_exports":
|
|
get:
|
|
summary: Lists family exports
|
|
tags:
|
|
- Family Exports
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
responses:
|
|
'200':
|
|
description: family exports listed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/FamilyExportCollection"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
post:
|
|
summary: Queues a family export
|
|
tags:
|
|
- Family Exports
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'202':
|
|
description: family export queued
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/FamilyExportResponse"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: invalid params
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
additionalProperties: false
|
|
description: Family export creation does not accept request parameters.
|
|
"/api/v1/family_exports/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
format: uuid
|
|
required: true
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Shows a family export
|
|
tags:
|
|
- Family Exports
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: family export shown
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/FamilyExportResponse"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/family_exports/{id}/download":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
format: uuid
|
|
required: true
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Downloads a completed family export
|
|
tags:
|
|
- Family Exports
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'302':
|
|
description: family export download redirected
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'409':
|
|
description: export not ready
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/family_settings":
|
|
get:
|
|
summary: Retrieve family settings
|
|
description: Retrieve a read-only snapshot of non-secret family configuration.
|
|
tags:
|
|
- Family Settings
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: family settings retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/FamilySettings"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: insufficient scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/holdings":
|
|
get:
|
|
summary: List holdings
|
|
tags:
|
|
- Holdings
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: account_id
|
|
in: query
|
|
required: false
|
|
description: Filter by account ID
|
|
schema:
|
|
type: string
|
|
- name: account_ids
|
|
in: query
|
|
required: false
|
|
description: Filter by multiple account IDs
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
- name: date
|
|
in: query
|
|
required: false
|
|
description: Filter by exact date
|
|
schema:
|
|
type: string
|
|
format: date
|
|
- name: start_date
|
|
in: query
|
|
required: false
|
|
description: Filter holdings from this date (inclusive)
|
|
schema:
|
|
type: string
|
|
format: date
|
|
- name: end_date
|
|
in: query
|
|
required: false
|
|
description: Filter holdings until this date (inclusive)
|
|
schema:
|
|
type: string
|
|
format: date
|
|
- name: security_id
|
|
in: query
|
|
required: false
|
|
description: Filter by security ID
|
|
schema:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: holdings paginated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/HoldingCollection"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: invalid date filter
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/holdings/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Holding ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve holding
|
|
tags:
|
|
- Holdings
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: holding retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Holding"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: holding not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/imports":
|
|
get:
|
|
summary: List imports
|
|
description: List all imports for the user's family with pagination and filtering.
|
|
tags:
|
|
- Imports
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: status
|
|
in: query
|
|
required: false
|
|
description: Filter by status
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- pending
|
|
- complete
|
|
- importing
|
|
- reverting
|
|
- revert_failed
|
|
- failed
|
|
- name: type
|
|
in: query
|
|
required: false
|
|
description: Filter by import type
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- TransactionImport
|
|
- TradeImport
|
|
- AccountImport
|
|
- MintImport
|
|
- CategoryImport
|
|
- RuleImport
|
|
- SureImport
|
|
responses:
|
|
'200':
|
|
description: imports filtered by type
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ImportCollection"
|
|
post:
|
|
summary: Create import
|
|
description: Create a new import from raw CSV content, inline Sure NDJSON content,
|
|
or an uploaded Sure NDJSON file.
|
|
tags:
|
|
- Imports
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: import created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ImportResponse"
|
|
'422':
|
|
description: validation error - file too large
|
|
content:
|
|
application/json:
|
|
schema:
|
|
oneOf:
|
|
- "$ref": "#/components/schemas/ErrorResponse"
|
|
- "$ref": "#/components/schemas/ErrorResponseWithImportId"
|
|
'500':
|
|
description: import uploaded but publish enqueue failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponseWithImportId"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
raw_file_content:
|
|
type: string
|
|
description: Raw CSV or Sure NDJSON content as a string. Required
|
|
for SureImport unless a multipart file is uploaded.
|
|
type:
|
|
type: string
|
|
enum:
|
|
- TransactionImport
|
|
- TradeImport
|
|
- AccountImport
|
|
- MintImport
|
|
- CategoryImport
|
|
- RuleImport
|
|
- SureImport
|
|
description: Import type (defaults to TransactionImport)
|
|
account_id:
|
|
type: string
|
|
format: uuid
|
|
description: Account ID to import into
|
|
publish:
|
|
type: string
|
|
description: Set to "true" to automatically queue for processing
|
|
if configuration is valid
|
|
date_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the date column
|
|
amount_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the amount column
|
|
name_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the transaction name
|
|
column
|
|
category_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the category column
|
|
tags_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the tags column
|
|
notes_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the notes column
|
|
account_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the account column
|
|
when importing rows across multiple accounts
|
|
qty_col_label:
|
|
type: string
|
|
description: CSV trade imports only. Header name for the quantity
|
|
column
|
|
ticker_col_label:
|
|
type: string
|
|
description: CSV trade imports only. Header name for the ticker
|
|
column
|
|
price_col_label:
|
|
type: string
|
|
description: CSV trade imports only. Header name for the price column
|
|
entity_type_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the entity type column
|
|
currency_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the currency column
|
|
exchange_operating_mic_col_label:
|
|
type: string
|
|
description: CSV trade imports only. Header name for the exchange
|
|
operating MIC column
|
|
date_format:
|
|
type: string
|
|
description: CSV imports only. Date format pattern (e.g., "%m/%d/%Y")
|
|
number_format:
|
|
type: string
|
|
enum:
|
|
- '1,234.56'
|
|
- 1.234,56
|
|
- 1 234,56
|
|
- '1,234'
|
|
description: CSV imports only. Number format for parsing amounts
|
|
signage_convention:
|
|
type: string
|
|
enum:
|
|
- inflows_positive
|
|
- inflows_negative
|
|
description: CSV imports only. How to interpret positive/negative
|
|
amounts
|
|
col_sep:
|
|
type: string
|
|
enum:
|
|
- ","
|
|
- ";"
|
|
description: CSV imports only. Column separator
|
|
amount_type_strategy:
|
|
type: string
|
|
enum:
|
|
- signed_amount
|
|
- custom_column
|
|
description: CSV imports only. Amount parsing strategy
|
|
amount_type_inflow_value:
|
|
type: string
|
|
description: CSV imports only. Column value that marks an amount
|
|
as an inflow when using custom_column strategy
|
|
multipart/form-data:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
raw_file_content:
|
|
type: string
|
|
description: Raw CSV or Sure NDJSON content as a string. Required
|
|
for SureImport unless a multipart file is uploaded.
|
|
type:
|
|
type: string
|
|
enum:
|
|
- TransactionImport
|
|
- TradeImport
|
|
- AccountImport
|
|
- MintImport
|
|
- CategoryImport
|
|
- RuleImport
|
|
- SureImport
|
|
description: Import type (defaults to TransactionImport)
|
|
account_id:
|
|
type: string
|
|
format: uuid
|
|
description: Account ID to import into
|
|
publish:
|
|
type: string
|
|
description: Set to "true" to automatically queue for processing
|
|
if configuration is valid
|
|
date_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the date column
|
|
amount_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the amount column
|
|
name_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the transaction name
|
|
column
|
|
category_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the category column
|
|
tags_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the tags column
|
|
notes_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the notes column
|
|
account_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the account column
|
|
when importing rows across multiple accounts
|
|
qty_col_label:
|
|
type: string
|
|
description: CSV trade imports only. Header name for the quantity
|
|
column
|
|
ticker_col_label:
|
|
type: string
|
|
description: CSV trade imports only. Header name for the ticker
|
|
column
|
|
price_col_label:
|
|
type: string
|
|
description: CSV trade imports only. Header name for the price column
|
|
entity_type_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the entity type column
|
|
currency_col_label:
|
|
type: string
|
|
description: CSV imports only. Header name for the currency column
|
|
exchange_operating_mic_col_label:
|
|
type: string
|
|
description: CSV trade imports only. Header name for the exchange
|
|
operating MIC column
|
|
date_format:
|
|
type: string
|
|
description: CSV imports only. Date format pattern (e.g., "%m/%d/%Y")
|
|
number_format:
|
|
type: string
|
|
enum:
|
|
- '1,234.56'
|
|
- 1.234,56
|
|
- 1 234,56
|
|
- '1,234'
|
|
description: CSV imports only. Number format for parsing amounts
|
|
signage_convention:
|
|
type: string
|
|
enum:
|
|
- inflows_positive
|
|
- inflows_negative
|
|
description: CSV imports only. How to interpret positive/negative
|
|
amounts
|
|
col_sep:
|
|
type: string
|
|
enum:
|
|
- ","
|
|
- ";"
|
|
description: CSV imports only. Column separator
|
|
amount_type_strategy:
|
|
type: string
|
|
enum:
|
|
- signed_amount
|
|
- custom_column
|
|
description: CSV imports only. Amount parsing strategy
|
|
amount_type_inflow_value:
|
|
type: string
|
|
description: CSV imports only. Column value that marks an amount
|
|
as an inflow when using custom_column strategy
|
|
"/api/v1/imports/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Import ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve an import
|
|
description: Retrieve detailed information about a specific import, including
|
|
configuration and row statistics.
|
|
tags:
|
|
- Imports
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: import retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ImportResponse"
|
|
'404':
|
|
description: import not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/merchants":
|
|
get:
|
|
summary: List merchants
|
|
tags:
|
|
- Merchants
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: merchants listed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
"$ref": "#/components/schemas/MerchantDetail"
|
|
"/api/v1/merchants/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Merchant ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve a merchant
|
|
tags:
|
|
- Merchants
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: merchant retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/MerchantDetail"
|
|
'404':
|
|
description: merchant not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/recurring_transactions":
|
|
get:
|
|
summary: List recurring transactions
|
|
tags:
|
|
- Recurring Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: status
|
|
in: query
|
|
required: false
|
|
description: Filter by recurring status
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- active
|
|
- inactive
|
|
- name: account_id
|
|
in: query
|
|
required: false
|
|
description: Filter by account ID
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
responses:
|
|
'200':
|
|
description: recurring transactions listed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RecurringTransactionCollection"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: validation error - malformed account filter
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
post:
|
|
summary: Create recurring transaction
|
|
tags:
|
|
- Recurring Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: recurring transaction created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RecurringTransaction"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden - requires read_write scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: account not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: validation error - negative occurrence count
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
recurring_transaction:
|
|
type: object
|
|
properties:
|
|
account_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
merchant_id:
|
|
type: string
|
|
format: uuid
|
|
nullable: true
|
|
name:
|
|
type: string
|
|
nullable: true
|
|
amount:
|
|
type: number
|
|
currency:
|
|
type: string
|
|
expected_day_of_month:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 31
|
|
last_occurrence_date:
|
|
type: string
|
|
format: date
|
|
next_expected_date:
|
|
type: string
|
|
format: date
|
|
status:
|
|
type: string
|
|
enum:
|
|
- active
|
|
- inactive
|
|
occurrence_count:
|
|
type: integer
|
|
minimum: 0
|
|
manual:
|
|
type: boolean
|
|
expected_amount_min:
|
|
type: number
|
|
nullable: true
|
|
expected_amount_max:
|
|
type: number
|
|
nullable: true
|
|
expected_amount_avg:
|
|
type: number
|
|
nullable: true
|
|
required:
|
|
- amount
|
|
- currency
|
|
- expected_day_of_month
|
|
- last_occurrence_date
|
|
- next_expected_date
|
|
anyOf:
|
|
- required:
|
|
- name
|
|
- required:
|
|
- merchant_id
|
|
required:
|
|
- recurring_transaction
|
|
required: true
|
|
"/api/v1/recurring_transactions/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Recurring transaction ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve recurring transaction
|
|
tags:
|
|
- Recurring Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: recurring transaction retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RecurringTransaction"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: recurring transaction not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
patch:
|
|
summary: Update recurring transaction
|
|
tags:
|
|
- Recurring Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: recurring transaction updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RecurringTransaction"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden - requires read_write scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: recurring transaction not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: validation error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
recurring_transaction:
|
|
type: object
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum:
|
|
- active
|
|
- inactive
|
|
expected_day_of_month:
|
|
type: integer
|
|
minimum: 1
|
|
maximum: 31
|
|
next_expected_date:
|
|
type: string
|
|
format: date
|
|
required: true
|
|
delete:
|
|
summary: Delete recurring transaction
|
|
tags:
|
|
- Recurring Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: recurring transaction deleted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/SuccessMessage"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden - requires read_write scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: recurring transaction not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/rule_runs":
|
|
get:
|
|
summary: List rule runs
|
|
description: List rule run history for the authenticated user family.
|
|
tags:
|
|
- Rule Runs
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: rule_id
|
|
in: query
|
|
required: false
|
|
description: Filter by rule ID
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: status
|
|
in: query
|
|
required: false
|
|
description: Filter by run status
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- pending
|
|
- success
|
|
- failed
|
|
- name: execution_type
|
|
in: query
|
|
required: false
|
|
description: Filter by execution type
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- manual
|
|
- scheduled
|
|
- name: start_executed_at
|
|
in: query
|
|
required: false
|
|
description: Filter runs executed at or after this timestamp
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
- name: end_executed_at
|
|
in: query
|
|
required: false
|
|
description: Filter runs executed at or before this timestamp
|
|
schema:
|
|
type: string
|
|
format: date-time
|
|
responses:
|
|
'200':
|
|
description: rule runs listed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RuleRunCollection"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: insufficient scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: invalid filter
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/rule_runs/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Rule run ID
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
get:
|
|
summary: Retrieve a rule run
|
|
description: Retrieve one rule run from the authenticated user family.
|
|
tags:
|
|
- Rule Runs
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: rule run retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RuleRunResponse"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: insufficient scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: rule run not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/rules":
|
|
get:
|
|
summary: List rules
|
|
tags:
|
|
- Rules
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: resource_type
|
|
in: query
|
|
required: false
|
|
description: Filter by rule resource type
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- transaction
|
|
- name: active
|
|
in: query
|
|
required: false
|
|
description: Filter by active status
|
|
schema:
|
|
type: boolean
|
|
responses:
|
|
'200':
|
|
description: rules listed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RuleCollection"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden - requires read scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: unsupported resource type
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/rules/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Rule ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve a rule
|
|
tags:
|
|
- Rules
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: rule retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/RuleResponse"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden - requires read scope
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: rule not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/tags":
|
|
get:
|
|
summary: List tags
|
|
tags:
|
|
- Tags
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: tags listed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/TagCollection"
|
|
post:
|
|
summary: Create tag
|
|
tags:
|
|
- Tags
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: tag created with auto-assigned color
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/TagDetail"
|
|
'422':
|
|
description: validation error - missing name
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
tag:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
description: Tag name (required)
|
|
color:
|
|
type: string
|
|
description: Hex color code (optional, auto-assigned if not
|
|
provided)
|
|
required:
|
|
- name
|
|
required:
|
|
- tag
|
|
required: true
|
|
"/api/v1/tags/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Tag ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve a tag
|
|
tags:
|
|
- Tags
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: tag retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/TagDetail"
|
|
'404':
|
|
description: tag not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
patch:
|
|
summary: Update a tag
|
|
tags:
|
|
- Tags
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: tag updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/TagDetail"
|
|
'404':
|
|
description: tag not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
tag:
|
|
type: object
|
|
properties:
|
|
name:
|
|
type: string
|
|
color:
|
|
type: string
|
|
required: true
|
|
delete:
|
|
summary: Delete a tag
|
|
tags:
|
|
- Tags
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'204':
|
|
description: tag deleted
|
|
'404':
|
|
description: tag not found
|
|
"/api/v1/trades":
|
|
get:
|
|
summary: List trades
|
|
tags:
|
|
- Trades
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: account_id
|
|
in: query
|
|
required: false
|
|
description: Filter by account ID
|
|
schema:
|
|
type: string
|
|
- name: account_ids
|
|
in: query
|
|
required: false
|
|
description: Filter by multiple account IDs
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
- name: start_date
|
|
in: query
|
|
required: false
|
|
description: Filter trades from this date (inclusive)
|
|
schema:
|
|
type: string
|
|
format: date
|
|
- name: end_date
|
|
in: query
|
|
required: false
|
|
description: Filter trades until this date (inclusive)
|
|
schema:
|
|
type: string
|
|
format: date
|
|
responses:
|
|
'200':
|
|
description: trades paginated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/TradeCollection"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: invalid date filter
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
post:
|
|
summary: Create trade
|
|
tags:
|
|
- Trades
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: trade created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Trade"
|
|
'422':
|
|
description: validation error - missing security identifier
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: account not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
trade:
|
|
type: object
|
|
properties:
|
|
account_id:
|
|
type: string
|
|
format: uuid
|
|
description: Account ID (required)
|
|
date:
|
|
type: string
|
|
format: date
|
|
description: Trade date (required)
|
|
qty:
|
|
type: number
|
|
description: Quantity (required)
|
|
price:
|
|
type: number
|
|
description: Price (required)
|
|
type:
|
|
type: string
|
|
enum:
|
|
- buy
|
|
- sell
|
|
description: Trade type (required)
|
|
security_id:
|
|
type: string
|
|
format: uuid
|
|
description: Security ID (one of security_id, ticker, manual_ticker
|
|
required)
|
|
ticker:
|
|
type: string
|
|
description: Ticker symbol
|
|
manual_ticker:
|
|
type: string
|
|
description: Manual ticker for offline securities
|
|
currency:
|
|
type: string
|
|
description: Currency (defaults to account currency)
|
|
investment_activity_label:
|
|
type: string
|
|
description: Activity label (e.g. Buy, Sell)
|
|
category_id:
|
|
type: string
|
|
format: uuid
|
|
description: Category ID
|
|
required:
|
|
- account_id
|
|
- date
|
|
- qty
|
|
- price
|
|
- type
|
|
required:
|
|
- trade
|
|
required: true
|
|
"/api/v1/trades/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Trade ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve trade
|
|
tags:
|
|
- Trades
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: trade retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Trade"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: trade not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
patch:
|
|
summary: Update trade
|
|
tags:
|
|
- Trades
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: trade updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Trade"
|
|
'404':
|
|
description: trade not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
trade:
|
|
type: object
|
|
properties:
|
|
date:
|
|
type: string
|
|
format: date
|
|
qty:
|
|
type: number
|
|
price:
|
|
type: number
|
|
type:
|
|
type: string
|
|
enum:
|
|
- buy
|
|
- sell
|
|
nature:
|
|
type: string
|
|
enum:
|
|
- inflow
|
|
- outflow
|
|
name:
|
|
type: string
|
|
notes:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
investment_activity_label:
|
|
type: string
|
|
category_id:
|
|
type: string
|
|
format: uuid
|
|
required: true
|
|
delete:
|
|
summary: Delete trade
|
|
tags:
|
|
- Trades
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: trade deleted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/DeleteResponse"
|
|
'404':
|
|
description: trade not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/transactions":
|
|
get:
|
|
summary: List transactions
|
|
tags:
|
|
- Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: account_id
|
|
in: query
|
|
required: false
|
|
description: Filter by account ID
|
|
schema:
|
|
type: string
|
|
- name: category_id
|
|
in: query
|
|
required: false
|
|
description: Filter by category ID
|
|
schema:
|
|
type: string
|
|
- name: merchant_id
|
|
in: query
|
|
required: false
|
|
description: Filter by merchant ID
|
|
schema:
|
|
type: string
|
|
- name: start_date
|
|
in: query
|
|
required: false
|
|
description: Filter transactions from this date
|
|
schema:
|
|
type: string
|
|
format: date
|
|
- name: end_date
|
|
in: query
|
|
required: false
|
|
description: Filter transactions until this date
|
|
schema:
|
|
type: string
|
|
format: date
|
|
- name: min_amount
|
|
in: query
|
|
required: false
|
|
description: Filter by minimum amount
|
|
schema:
|
|
type: number
|
|
- name: max_amount
|
|
in: query
|
|
required: false
|
|
description: Filter by maximum amount
|
|
schema:
|
|
type: number
|
|
- name: type
|
|
in: query
|
|
required: false
|
|
description: Filter by transaction type
|
|
schema:
|
|
type: string
|
|
enum:
|
|
- income
|
|
- expense
|
|
- name: search
|
|
in: query
|
|
required: false
|
|
description: Search by name, notes, or merchant name
|
|
schema:
|
|
type: string
|
|
- name: account_ids
|
|
in: query
|
|
required: false
|
|
description: Filter by multiple account IDs
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
- name: category_ids
|
|
in: query
|
|
required: false
|
|
description: Filter by multiple category IDs
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
- name: merchant_ids
|
|
in: query
|
|
required: false
|
|
description: Filter by multiple merchant IDs
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
- name: tag_ids
|
|
in: query
|
|
required: false
|
|
description: Filter by tag IDs
|
|
schema:
|
|
type: array
|
|
items:
|
|
type: string
|
|
responses:
|
|
'200':
|
|
description: transactions filtered by date range
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/TransactionCollection"
|
|
post:
|
|
summary: Create transaction
|
|
tags:
|
|
- Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: transaction created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Transaction"
|
|
'422':
|
|
description: validation error - missing required fields
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
transaction:
|
|
type: object
|
|
properties:
|
|
account_id:
|
|
type: string
|
|
format: uuid
|
|
description: Account ID (required)
|
|
date:
|
|
type: string
|
|
format: date
|
|
description: Transaction date
|
|
amount:
|
|
type: number
|
|
description: Transaction amount
|
|
name:
|
|
type: string
|
|
description: Transaction name/description
|
|
description:
|
|
type: string
|
|
description: Alternative to name field
|
|
notes:
|
|
type: string
|
|
description: Additional notes
|
|
currency:
|
|
type: string
|
|
description: Currency code (defaults to family currency)
|
|
category_id:
|
|
type: string
|
|
format: uuid
|
|
description: Category ID
|
|
merchant_id:
|
|
type: string
|
|
format: uuid
|
|
description: Merchant ID
|
|
nature:
|
|
type: string
|
|
enum:
|
|
- income
|
|
- expense
|
|
- inflow
|
|
- outflow
|
|
description: Transaction nature (determines sign)
|
|
tag_ids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
description: Array of tag IDs
|
|
required:
|
|
- account_id
|
|
- date
|
|
- amount
|
|
- name
|
|
required:
|
|
- transaction
|
|
required: true
|
|
"/api/v1/transactions/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Transaction ID
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve a transaction
|
|
tags:
|
|
- Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: transaction retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Transaction"
|
|
'404':
|
|
description: transaction not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
patch:
|
|
summary: Update a transaction
|
|
tags:
|
|
- Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: transaction updated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Transaction"
|
|
'404':
|
|
description: transaction not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
transaction:
|
|
type: object
|
|
properties:
|
|
date:
|
|
type: string
|
|
format: date
|
|
amount:
|
|
type: number
|
|
name:
|
|
type: string
|
|
description:
|
|
type: string
|
|
description: Alternative to name field
|
|
notes:
|
|
type: string
|
|
currency:
|
|
type: string
|
|
description: Currency code
|
|
category_id:
|
|
type: string
|
|
format: uuid
|
|
merchant_id:
|
|
type: string
|
|
format: uuid
|
|
nature:
|
|
type: string
|
|
enum:
|
|
- income
|
|
- expense
|
|
- inflow
|
|
- outflow
|
|
tag_ids:
|
|
type: array
|
|
items:
|
|
type: string
|
|
format: uuid
|
|
description: Array of tag IDs to assign. Omit to preserve existing
|
|
tags; use [] to clear all tags.
|
|
required: true
|
|
delete:
|
|
summary: Delete a transaction
|
|
tags:
|
|
- Transactions
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: transaction deleted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/DeleteResponse"
|
|
'404':
|
|
description: transaction not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/users/reset":
|
|
delete:
|
|
summary: Reset account
|
|
tags:
|
|
- Users
|
|
description: Resets all financial data (accounts, categories, merchants, tags,
|
|
etc.) for the current user's family while keeping the user account intact.
|
|
The reset runs asynchronously in the background. The returned job_id is informational
|
|
only; reset status is family-scoped, not job-scoped. Requires admin role.
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: account reset initiated
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ResetInitiatedResponse"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden - requires read_write scope and admin role
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'500':
|
|
description: reset enqueue failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/users/reset/status":
|
|
get:
|
|
summary: Retrieve reset status
|
|
tags:
|
|
- Users
|
|
description: Returns counts of family-owned data targeted by account reset.
|
|
Use this after DELETE /api/v1/users/reset to decide whether reset materialization
|
|
has completed. Completion is a counts-based family snapshot and may change
|
|
if new data is created after reset.
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: reset status returned
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ResetStatusResponse"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'403':
|
|
description: forbidden - requires admin role
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/users/me":
|
|
delete:
|
|
summary: Delete account
|
|
tags:
|
|
- Users
|
|
description: Permanently deactivates the current user account and all associated
|
|
data. This action cannot be undone.
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: account deleted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/SuccessMessage"
|
|
'401':
|
|
description: unauthorized
|
|
'403':
|
|
description: insufficient scope
|
|
'422':
|
|
description: deactivation failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
"/api/v1/valuations":
|
|
get:
|
|
summary: List valuations
|
|
tags:
|
|
- Valuations
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters:
|
|
- name: page
|
|
in: query
|
|
required: false
|
|
description: 'Page number (default: 1)'
|
|
schema:
|
|
type: integer
|
|
- name: per_page
|
|
in: query
|
|
required: false
|
|
description: 'Items per page (default: 25, max: 100)'
|
|
schema:
|
|
type: integer
|
|
- name: account_id
|
|
in: query
|
|
required: false
|
|
description: Filter by account ID
|
|
schema:
|
|
type: string
|
|
format: uuid
|
|
- name: start_date
|
|
in: query
|
|
required: false
|
|
description: Filter valuations from this date
|
|
schema:
|
|
type: string
|
|
format: date
|
|
- name: end_date
|
|
in: query
|
|
required: false
|
|
description: Filter valuations until this date
|
|
schema:
|
|
type: string
|
|
format: date
|
|
responses:
|
|
'200':
|
|
description: valuations listed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ValuationCollection"
|
|
'401':
|
|
description: unauthorized
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'422':
|
|
description: invalid account filter
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
post:
|
|
summary: Create valuation
|
|
tags:
|
|
- Valuations
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'201':
|
|
description: valuation created
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Valuation"
|
|
'200':
|
|
description: existing valuation upserted
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Valuation"
|
|
'422':
|
|
description: validation error - missing date
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: account not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
valuation:
|
|
type: object
|
|
properties:
|
|
account_id:
|
|
type: string
|
|
format: uuid
|
|
description: Account ID (required)
|
|
amount:
|
|
type: number
|
|
description: Valuation amount (required)
|
|
date:
|
|
type: string
|
|
format: date
|
|
description: Valuation date (required)
|
|
notes:
|
|
type: string
|
|
description: Additional notes
|
|
upsert:
|
|
type: boolean
|
|
description: Nested alternative to the top-level response-status
|
|
flag. Top-level upsert takes precedence when both are provided.
|
|
required:
|
|
- account_id
|
|
- amount
|
|
- date
|
|
upsert:
|
|
type: boolean
|
|
description: Response-status signal only. When true and a same-account
|
|
same-date valuation exists before the request, the endpoint returns
|
|
200 OK instead of 201 Created. The underlying reconciliation write
|
|
path is unchanged; this flag does not add duplicate-prevention
|
|
or safe-retry guarantees beyond existing same-date reconciliation
|
|
behavior.
|
|
required:
|
|
- valuation
|
|
required: true
|
|
"/api/v1/valuations/{id}":
|
|
parameters:
|
|
- name: id
|
|
in: path
|
|
required: true
|
|
description: Valuation ID (entry ID)
|
|
schema:
|
|
type: string
|
|
get:
|
|
summary: Retrieve a valuation
|
|
tags:
|
|
- Valuations
|
|
security:
|
|
- apiKeyAuth: []
|
|
responses:
|
|
'200':
|
|
description: valuation retrieved
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Valuation"
|
|
'404':
|
|
description: valuation not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
patch:
|
|
summary: Update a valuation
|
|
tags:
|
|
- Valuations
|
|
security:
|
|
- apiKeyAuth: []
|
|
parameters: []
|
|
responses:
|
|
'200':
|
|
description: valuation updated with amount and date
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/Valuation"
|
|
'422':
|
|
description: validation error - only one of amount/date provided
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
'404':
|
|
description: valuation not found
|
|
content:
|
|
application/json:
|
|
schema:
|
|
"$ref": "#/components/schemas/ErrorResponse"
|
|
requestBody:
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
valuation:
|
|
type: object
|
|
properties:
|
|
amount:
|
|
type: number
|
|
description: New valuation amount (must provide with date)
|
|
date:
|
|
type: string
|
|
format: date
|
|
description: New valuation date (must provide with amount)
|
|
notes:
|
|
type: string
|
|
description: Additional notes
|
|
required: true
|