v0.0.0
OpenAPI 3.1.0

Spendy2

Spendy2 is an end-to-end encrypted personal finance dashboard that does two things:

  • It stores details of your transactions in an encrypted database.
  • The frontend decrypts this database to provide a dashboard view and easy edit access.

Most importantly, it does NOT handle the actual import of data. Parsing transactions from a pdf statement, bank API, or any other source and adding it to the database will need to be handled by you.

Server:https://spendy2.com
Client Libraries

Users

​

Registration takes two requests, so the password never leaves the client: send a registrationRequest to get a registrationResponse, then send the registrationRecord computed from it. A user who never uploads a database is removed again.

Users Operations

Register a user

​

Registers a user with OPAQUE in two requests: a registrationRequest returns the registrationResponse, then the registrationRecord creates the user.

Body

required
application/json

Responses

  • application/json
  • application/json
  • application/json
  • application/json
Request Example for post/api/users
curl https://spendy2.com/api/users \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "username": "",
  "registrationRequest": ""
}'
{
  "registrationResponse": "string"
}

Auth

​

A login also takes two requests: start it with a startLoginRequest, then finish it with the finishLoginRequest computed from the response. After a failed or unfinished login, the next start is delayed by a random backoff that grows with each attempt. Each user has a limited number of sessions; logging in beyond it ends the oldest.

Start logging in

​

Just like user registration, log in uses OPAQUE that requires the use of two different requests to complete the login attempt. Start login by calling this API first.

Body

required
application/json

Responses

  • application/json
  • application/json
  • application/json
Request Example for post/api/auth/login/start
curl https://spendy2.com/api/auth/login/start \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "username": "",
  "startLoginRequest": ""
}'
{
  "loginResponse": "string"
}

Finish logging in

​

Completes the log in process and creates a session on success.

Body

required
application/json

Responses

  • application/json
  • application/json
Request Example for post/api/auth/login/finish
curl https://spendy2.com/api/auth/login/finish \
  --request POST \
  --header 'Content-Type: application/json' \
  --data '{
  "username": "",
  "finishLoginRequest": ""
}'
{
  "token": "string"
}

Log out

​

Ends the current session.

Responses

  • Logged out

  • application/json
Request Example for post/api/auth/logout
curl https://spendy2.com/api/auth/logout \
  --request POST \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN'
No Body

Database

​

All of the user data is stored in a single encrypted, compressed SQLite database with the following table schema:

Upload the database

​

Replaces the stored database if it is still the one the precondition names. Send exactly one of If-Match and If-None-Match, and a Content-Length.

Headers

  • The ETag of the stored database this upload replaces

  • * for the first upload

Body

required
application/json

Responses

  • application/json
  • application/json
  • application/json
  • text/plain
Request Example for put/api/users/me/database
curl https://spendy2.com/api/users/me/database \
  --request PUT \
  --header 'content-length: ' \
  --header 'Content-Type: application/octet-stream' \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN' \
  --data-binary '@filename'
No Body

Download the database

​

Downloads the stored database. With If-None-Match set to its ETag, responds 304 if it hasn't changed.

Headers

  • The ETag of a database the client already has

Responses

  • application/octet-stream
  • application/json
  • application/json
Request Example for get/api/users/me/database
curl https://spendy2.com/api/users/me/database \
  --header 'Authorization: Bearer YOUR_SECRET_TOKEN'
@filename