{
  "info": {
    "name": "Savi Finance JSON-RPC API",
    "description": "JSON-RPC 2.0 requests for the Savi Finance API. Set saviToken locally before using authenticated requests. Keep tokens out of shared collections and exported files; use a secure Postman variable or Vault. Public requests do not send authorization.",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{saviToken}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "apiBaseUrl",
      "value": "https://api-v2.financesavi.com/rpc",
      "type": "string",
      "description": "Versioned JSON-RPC API endpoint."
    },
    {
      "key": "saviToken",
      "value": "",
      "type": "string",
      "description": "Set locally to your API bearer token. Do not share or export populated values."
    }
  ],
  "item": [
    {
      "name": "Public methods",
      "item": [
        {
          "name": "loginByEmailVerification",
          "request": {
            "method": "POST",
            "auth": {
              "type": "noauth"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"loginByEmailVerification\",\n  \"params\": {\n    \"email\": \"you@example.com\",\n    \"code\": \"123456\",\n    \"authenticationMethod\": \"EMAIL_CODE\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "Login By Email Verification - exchanges the 6-digit code emailed by sendLoginCodeEmail for a bearer token.\n\nAuthentication: Not required\n\nParameters:\n- email (string, required): The address the code was sent to\n- code (string, required): The 6-digit code from the email\n- authenticationMethod (string, required): EMAIL_CODE\n\nBehavior:\n- Succeeds only if the code matches and has not expired\n- Each code accepts at most 5 attempts, including the successful one. After that it is locked and a new code must be requested\n- A code can be used once\n- An unknown email and a wrong, used, or locked code all return \"invalid code\"\n- Requests are rate limited per client IP and per email\n- Issues an opaque bearer token on success. Send it as 'Authorization: Bearer <token>' on methods that require authentication\n\nReturns:\n- { token: string, userId: string }\n\nExample:\n{\n  \"method\": \"loginByEmailVerification\",\n  \"params\": {\n    \"email\": \"you@example.com\",\n    \"code\": \"123456\",\n    \"authenticationMethod\": \"EMAIL_CODE\"\n  }\n}\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "ping",
          "request": {
            "method": "POST",
            "auth": {
              "type": "noauth"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"ping\",\n  \"params\": {},\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "Ping handler - tests basic connectivity.\n\nThis handler accepts an optional message parameter and returns a normalized response.\nIf no message is provided, it returns \"pong\". If a message is provided, it returns\nthe trimmed message.\n\nAuthentication: Not required\n\nParameters:\n- message (string, optional): Message to echo back\n\nReturns:\n- reply (string): Normalized message or \"pong\" if empty\n\nExample:\n{\n  \"method\": \"ping\",\n  \"params\": {\n    \"message\": \"hello world\"\n  }\n}\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "sendLoginCodeEmail",
          "request": {
            "method": "POST",
            "auth": {
              "type": "noauth"
            },
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"sendLoginCodeEmail\",\n  \"params\": {\n    \"email\": \"you@example.com\",\n    \"loginCodeType\": \"SHORT_LIVED\",\n    \"emailType\": \"LOGIN_CODE\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "Send Login Code Email - issues a one-time code or login link via email.\n\nThis method mirrors the functionality of the GraphQL resolver send_login_code_email.\nIt generates a login code for the specified email, persists its metadata, and sends\nan email using the configured mail driver (fake or SES SMTP).\n\nAuthentication: Not required\n\nParameters:\n- email (string, required): Recipient email address\n- loginCodeType (string, required): SHORT_LIVED (code) or LONG_LIVED (link)\n- emailType (string, required): LOGIN_CODE or WEB_LOGIN_LINK\n\nConstraints:\n- WEB_LOGIN_LINK requires LONG_LIVED\n- LOGIN_CODE requires SHORT_LIVED\n- Resend rate limited to once per 60 seconds per email\n- Requests are also rate limited per client IP and per email\n- The response is the same whether or not the email already has an account\n\nReturns:\n- { message: \"ok\", loginUrl?: string }\n\nTo sign in with a 6-digit code, use loginCodeType SHORT_LIVED with emailType\nLOGIN_CODE, then exchange the code with loginByEmailVerification.\n\nExample:\n{\n  \"method\": \"sendLoginCodeEmail\",\n  \"params\": {\n    \"email\": \"you@example.com\",\n    \"loginCodeType\": \"SHORT_LIVED\",\n    \"emailType\": \"LOGIN_CODE\"\n  }\n}\n\nThis request can change real data or send email. Review its parameters before sending.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        }
      ]
    },
    {
      "name": "Authenticated methods",
      "item": [
        {
          "name": "advanceTestClock",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"advanceTestClock\",\n  \"params\": {\n    \"id\": \"tc_example\",\n    \"frozenTime\": \"2026-10-02T19:24:43.985Z\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "advanceTestClock advances an owned test clock monotonically. Repeating the current frozenTime is idempotent; moving backwards or beyond maxTime is rejected. The returned snapshot includes transactions and goal contributions visible at the new simulated time.\n\nThis request can change real data or send email. Review its parameters before sending.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "createAccount",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"createAccount\",\n  \"params\": {\n    \"ownerId\": \"user_8f3a1c2d9b\",\n    \"name\": \"Everyday Chequing\",\n    \"accountType\": \"DEPOSITORY\",\n    \"accountSubtype\": \"CHECKING\",\n    \"defaultCurrency\": \"CAD\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "createAccount - Creates a new account for the authenticated user.\n\nParameters:\n- ownerId (string, required): ID of the user this account belongs to\n- name (string, required): Display name of the account\n- description (string, optional): Description of the account\n- industryAccountRateId (string, optional): If provided, auto-creates rewards from that industry account rate introOffers\n- accountType (string, required): Type of account (DEPOSITORY, CREDIT, LOAN, INVESTMENT, CASH, ASSET, GIFT_CARD, OTHER, GOVERNMENT)\n- accountSubtype (string, required): Specific subtype of account\n- assetType (string, optional): Asset type (only for ASSET accounts)\n- investmentType (string, optional): Investment type (only for INVESTMENT accounts)\n- giftCardVendorId (string, optional): Vendor ID (only for GIFT_CARD accounts)\n- giftCardVendorName (string, optional): Vendor name fallback (only for GIFT_CARD accounts)\n- defaultCurrency (string, required): Currency code (default: CAD)\n- savingInterestRate (float, optional): Interest rate for savings accounts\n- debtInterestRate (float, optional): Interest rate for debt accounts\n- creditLimit (number, optional): Credit limit in cents for credit accounts\n- isVariableInterestRate (bool, optional): Variable rate flag for debt accounts\n- interestRecurrenceRate (string, optional): DAILY, WEEKLY, BIWEEKLY, MONTHLY, QUARTERLY, SEMIANNUALLY, ANNUALLY\n- gracePeriod (string, optional): ISO8601/RFC3339 datetime for debt grace period\n- positionOrder (int, optional): Display order\n- countryId (int, optional): Country ID for regional availability\n- governmentAccountType (string, optional): Government account subtype\n- stockSymbol (string, optional): Stock symbol for investment accounts\n- stockPrice (float, optional): Stock price\n- stockQuantity (float, optional): Stock quantity\n- fuelEfficiency (float, optional): KM per liter (only for CAR asset type)\n\nReturns:\n- accountId (string): Newly created account ID\n- autoRewardsAttemptedCount (int): Number of auto reward creations attempted\n- autoRewardsCreatedCount (int): Number of auto rewards created\n- autoRewardsSkippedCount (int): Number of auto rewards skipped\n\nExample:\n{\n  \"method\": \"createAccount\",\n  \"params\": {\n    \"ownerId\": \"u_abc123\",\n    \"name\": \"My Checking Account\",\n    \"accountType\": \"DEPOSITORY\",\n    \"accountSubtype\": \"CHECKING\",\n    \"defaultCurrency\": \"CAD\"\n  }\n}\n\nThis request can change real data or send email. Review its parameters before sending.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "createTestClock",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"createTestClock\",\n  \"params\": {\n    \"frozenTime\": \"2026-10-02T18:24:43.985Z\",\n    \"transactions\": [\n      {\n        \"at\": \"2026-10-02T19:24:43.985Z\",\n        \"name\": \"Simulated payroll\",\n        \"amount\": 2500,\n        \"currency\": \"CAD\",\n        \"type\": \"INCOME\"\n      }\n    ],\n    \"goals\": [\n      {\n        \"name\": \"Emergency fund\",\n        \"targetAmount\": 1000,\n        \"initialAmount\": 100,\n        \"contributions\": [\n          {\n            \"at\": \"2026-10-02T19:24:43.985Z\",\n            \"amount\": 150\n          },\n          {\n            \"at\": \"2026-10-02T20:24:43.985Z\",\n            \"amount\": 250\n          }\n        ]\n      }\n    ]\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "createTestClock creates an isolated, disposable simulation scenario.\n\nAuthentication: required. The clock is owned by the authenticated identity and\nexpires after seven days. Its data stays outside the ordinary account, transaction,\ngoal, and bank-connection collections. Transactions and goal contributions\nappear as the clock advances; no bank request is sent.\n\nParameters:\n- frozenTime (RFC 3339 timestamp, optional): initial simulated time; defaults to now.\n- transactions (array, optional): up to 100 entries. Each needs an RFC 3339 at\n  between frozenTime and maxTime, a 1–120 character name, a positive amount up\n  to 1,000,000,000, a three-letter uppercase currency code, and type INCOME or\n  EXPENSE. Category is optional and limited to 80 characters.\n- goals (array, optional): up to 25 goals with a 1–120 character name and a\n  positive targetAmount up to 1,000,000,000. initialAmount defaults to zero\n  and cannot exceed targetAmount. Each goal accepts up to 100 positive\n  contributions, each up to 1,000,000,000, scheduled between frozenTime and\n  maxTime.\n\nTime range: frozenTime must be within ten years of now. maxTime is ten years\nafter frozenTime. Event times outside that range are rejected.\n\nReturns: clock ID, frozen time, visible transactions, pending transactions, and\ngoal progress with posted and upcoming contributions.\n\nThis request can change real data or send email. Review its parameters before sending.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "createTransaction",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"createTransaction\",\n  \"params\": {\n    \"accountId\": \"account_5kQe2Xv9Lm\",\n    \"name\": \"Coffee Shop\",\n    \"amount\": -450,\n    \"currency\": \"CAD\",\n    \"category\": \"FOOD\",\n    \"transactedAt\": \"2026-10-01T09:30:00Z\",\n    \"fileIds\": []\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "createTransaction — creates a new transaction for the authenticated user.\n\nAuthentication: Required (Bearer token). The user must be the owner or collaborator of the target account.\n\nParameters:\n- accountId (string, required): Account the transaction belongs to\n- name (string, required): Transaction display name\n- amount (float, required): Amount in smallest denomination (negative = expense, positive = income)\n- currency (string, optional): 3-letter ISO currency code for transaction denomination\n- category (string, required): Top-level category (FOOD, INCOME, RENT, TRANSPORTATION, …)\n- transactedAt (string, required): ISO 8601 / RFC3339 datetime of the transaction\n- fileIds ([string], required): List of attached file IDs (pass [] for none)\n- type (string, optional): INCOME | EXPENSE | TRANSFER — inferred from amount/category if omitted\n- categoryId (string, optional): v2 category ID — resolved from category if omitted\n- incomeCategory (string, optional): Income sub-category\n- expenseCategory (string, optional): Expense sub-category\n- subcategory (string, optional): Sub-category label\n- vendorId (string, optional): Vendor ID\n- vendorName (string, optional): Vendor display name\n- description (string, optional): Additional notes\n- tagIds ([string], optional): Tag IDs to attach\n- cronExpression (string, optional): Recurrence cron expression\n- endDate (string, optional): ISO 8601 recurrence end date\n- isExcludedFromAnalytics (bool, optional): Exclude from spending analytics\n- lineItems ([{id, name, amount}], optional): Itemised line items\n- oneOffSplitParticipants ([{name, amount}], optional): Freeform Split With Others rows stored directly on the transaction. The server generates persisted row ids; names are display labels only and do not identify or notify another user.\n- appleCardTransaction ({transactionId}, optional): Apple Card / FinanceKit metadata; triggers idempotent create and BANK_INTEGRATION source\n\nReturns:\n- transactionId (string): Newly created (or idempotently matched) transaction ID\n\nThis request can change real data or send email. Review its parameters before sending.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "deleteTestClock",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"deleteTestClock\",\n  \"params\": {\n    \"id\": \"tc_example\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "deleteTestClock permanently deletes an owned test clock and its isolated scenario. It does not modify ordinary financial data.\n\nThis request can change real data or send email. Review its parameters before sending.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "deleteTransaction",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"deleteTransaction\",\n  \"params\": {\n    \"transactionId\": \"tx_9bLm4Rt7Yc\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "deleteTransaction — deletes a transaction by ID.\n\nThe authenticated user must be the owner or collaborator of the account the\ntransaction belongs to, and must have an OWNER or COOWNER role if a role is\nassigned to their credentials.\n\nAuthentication: Required (Bearer token)\n\nParameters:\n- transactionId (string, required): ID of the transaction to delete\n\nReturns:\n- message (string): Always \"ok\" on success\n\nErrors:\n- unauthenticated: No valid auth token provided\n- permission_denied: User is not allowed to delete this transaction\n- invalid_params: transactionId missing, transaction not found, or account not found\n\nThis request can change real data or send email. Review its parameters before sending.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "getAccount",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"getAccount\",\n  \"params\": {\n    \"accountId\": \"account_5kQe2Xv9Lm\",\n    \"userId\": \"user_8f3a1c2d9b\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "Get Account - retrieves a single account by ID with optional data.\n\nThis handler returns a specific account where the specified user is either the owner\nor a collaborator. It supports optional inclusion of computed balances, crypto\nholdings, Plaid access object data, collaborators, and collaborator invitations.\n\nComputed balance invariant: computedBalance is the sum of the account's\nnon-deleted transactions expressed in the account's own currency. A transaction\ndenominated in a different currency (Plaid isoCurrencyCode) is converted to the\naccount currency using the latest USD-normalized fiat rate before summing.\nNegative amounts (refunds/reversals) sum naturally. If a required rate is\nunavailable the request fails rather than returning a mixed-currency sum.\n\nAuthentication: Required (Bearer token)\n\nParameters:\n- accountId (string, required): ID of the account to retrieve\n- userId (string, required): ID of the user making the request\n- includeComputedBalance (boolean, optional): Include computed account balance\n- includeCryptoHoldings (boolean, optional): Include crypto holdings for crypto accounts\n- includePlaidAccessObject (boolean, optional): Include Plaid integration data\n- includeCollaborators (boolean, optional): Include list of collaborators\n- includeCollaboratorInvitations (boolean, optional): Include pending collaborator invitations (owner only)\n\nReturns:\n- account (object): AccountWithCryptoHoldings object with requested data\n\nExample:\n{\n  \"method\": \"getAccount\",\n  \"params\": {\n    \"accountId\": \"acc123\",\n    \"userId\": \"user123\",\n    \"includeComputedBalance\": true,\n    \"includeCryptoHoldings\": true,\n    \"includePlaidAccessObject\": true,\n    \"includeCollaborators\": true,\n    \"includeCollaboratorInvitations\": true\n  }\n}\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "getCurrentUser",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"getCurrentUser\",\n  \"params\": {},\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "Get Current User - returns information about the authenticated user.\n\nThis handler returns the current user's credentials and associated user\naccounts based on the raw access-binding sequence. Expiry is not filtered,\nduplicates retain binding order, and bindings to missing users are skipped. No\nparameters are required.\n\nAuthentication: Required (Bearer token)\n\nParameters: None\n\nReturns:\n- credentials (object): User credential information including ID and type\n- users (array): Array of user accounts associated with the credential\n\nExample:\n{\n  \"method\": \"getCurrentUser\",\n  \"params\": {}\n}\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "getTestClock",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"getTestClock\",\n  \"params\": {\n    \"id\": \"tc_example\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "getTestClock returns the current frozen time, posted and pending synthetic transactions, and each goal's progress with its posted and upcoming contributions. Clocks are visible only to their creator and expire automatically.\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "getTransaction",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"getTransaction\",\n  \"params\": {\n    \"transactionId\": \"tx_9bLm4Rt7Yc\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "getTransaction — fetches a single transaction by ID.\n\nThe authenticated user must be the owner or a collaborator of the account the\ntransaction belongs to. Read access only — no role gate.\n\nAuthentication: Required (Bearer token)\n\nParameters:\n- transactionId (string, required): ID of the transaction to fetch\n\nReturns:\n- transaction (object): The transaction document\n\nErrors:\n- unauthenticated: No valid auth token provided\n- permission_denied: User is not allowed to view this transaction\n- invalid_params: transactionId missing, transaction not found, or account not found\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "listAccounts",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"listAccounts\",\n  \"params\": {\n    \"userId\": \"user_8f3a1c2d9b\"\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "List Accounts - retrieves accounts for a specific user with optional data.\n\nThis handler returns all accounts where the specified user is either the owner\nor a collaborator. It supports optional inclusion of computed balances, crypto\nholdings, and Plaid access object data.\n\nComputed balance invariant: each account's computedBalance is the sum of its\nnon-deleted transactions expressed in that account's own currency. A transaction\ndenominated in a different currency (Plaid isoCurrencyCode) is converted to the\naccount currency using the latest USD-normalized fiat rate before summing.\nNegative amounts (refunds/reversals) sum naturally. If a required rate is\nunavailable the request fails rather than returning a mixed-currency sum.\n\nAuthentication: Required (Bearer token)\n\nParameters:\n- userId (string, required): ID of the user whose accounts to retrieve\n- includeComputedBalance (boolean, optional): Include computed account balances\n- includeCryptoHoldings (boolean, optional): Include crypto holdings for crypto accounts\n- includePlaidAccessObject (boolean, optional): Include Plaid integration data\n\nReturns:\n- accounts (array): Array of AccountWithCryptoHoldings objects\n\nExample:\n{\n  \"method\": \"listAccounts\",\n  \"params\": {\n    \"userId\": \"user123\",\n    \"includeComputedBalance\": true,\n    \"includeCryptoHoldings\": true,\n    \"includePlaidAccessObject\": true\n  }\n}\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "listAlerts",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"listAlerts\",\n  \"params\": {},\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "listAlerts — returns all spending/income alerts owned by the authenticated user.\n\nAuthentication: Required (Bearer token).\nAuthorization: Caller must have an access binding with role OWNER or COOWNER.\n\nParameters: none. The caller is identified via the Bearer token and default\npersonal user binding.\n\nReturns:\n- alerts ([]object): Zero or more alert records (ordering is implementation-defined).\n  Each alert has: id, userId, amount, category, isIncomeAlert, percentage,\n  message, isActive, currentTotal, createdAt, updatedAt (see getAlert for field\n  semantics).\n\nErrors:\n- permissionDenied: caller lacks OWNER/COOWNER role.\n- internal: store failure.\n\nExample request:\n{\n  \"method\": \"listAlerts\",\n  \"params\": {}\n}\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "listLifePlans",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"listLifePlans\",\n  \"params\": {\n    \"pagination\": {\n      \"limit\": 20,\n      \"skip\": 0\n    }\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "listLifePlans — paginated listing of life plans owned by the caller with their associated data.\n\nEach plan is returned along with all saving goals the caller contributes to,\nfixed income/expense blocks, and per-event income/expenses. The response\ncurrently attaches ALL of the caller's goals (not plan-scoped) because the\ndata model treats a user's goals as a global pool.\n\nAuthentication: Required (Bearer token).\n\nParameters:\n- pagination ({limit, skip}, required): limit caps records returned; skip\n  offsets for pagination.\n\nReturns:\n- lifePlans ([]object): Plan records with:\n  - id, name (string)\n  - annualInflationRate (float64), currentSavings (float64)\n  - savingGoals ([]SavingGoalResponse)\n  - fixedIncomeBlocks, fixedExpenseBlocks ([]LifePlanFixedBlock): Templated\n    recurring cash flows with startDay/endDay (year/month/day).\n  - incomes, expenses ([]LifePlanIncome/Expense): Bespoke one-off / recurring\n    cash flows with startDate, endDate?, recurrence, amount, category?.\n- numItems (int): Length of lifePlans (not total — paginated).\n\nErrors:\n- invalidParams: pagination missing.\n- unauthenticated: missing or invalid Bearer token.\n- internal: store failure.\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "listProjections",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"listProjections\",\n  \"params\": {\n    \"isIncome\": false\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "listProjections — lists cash-flow projections owned by the caller, with optional filters.\n\nUsed by budget and balance-forecast views to load all recurring expected\nincomes/expenses. Filters are AND-combined: passing both isIncome and\ncategory narrows to projections that match both.\n\nAuthentication: Required (Bearer token).\n\nParameters:\n- isIncome (bool, optional): If set, filter to income (true) or expense (false) projections only.\n- category (string, optional): If set, filter to projections with this transaction category.\n\nReturns:\n- projections ([]object): Projection records with fields:\n  - id, userId, name, category, isIncome\n  - startMonth, endMonth? (ISO 8601)\n  - amount (number), repeatFrequency (MONTHLY/WEEKLY/YEARLY/NEVER/CUSTOM)\n  - customRepeatFrequency? ({frequencyUnit, frequencyAmount})\n  - overrides ([]object): Time-bound overrides.\n  - createdAt, updatedAt (ISO 8601)\n\nErrors:\n- unauthenticated: missing or invalid Bearer token.\n- internal: store failure.\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "listSavedFilters",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"listSavedFilters\",\n  \"params\": {\n    \"limit\": 20,\n    \"skip\": 0\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "listSavedFilters — paginated listing of saved filters owned by the caller.\n\nAuthentication: Required (Bearer token).\n\nParameters:\n- limit (int, optional): Maximum records to return. Defaults to 10 if 0 or negative.\n- skip (int, optional): Records to skip for pagination. Defaults to 0.\n\nReturns:\n- savedFilters ([]object): SavedFilterResponse records (see createSavedFilter).\n- total (int64): Total number of saved filters the caller owns (ignores limit/skip).\n  Use this for pagination UI.\n\nErrors:\n- unauthenticated: missing or invalid Bearer token.\n- internal: store failure.\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "listSavingGoals",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"listSavingGoals\",\n  \"params\": {\n    \"pagination\": {\n      \"limit\": 10,\n      \"skip\": 0\n    }\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "listSavingGoals — lists the saving goals the caller contributes to.\n\nAuthentication: Required (Bearer token).\n\nParameters:\n- pagination ({limit, skip}, required by schema but ignored server-side).\n\nReturns:\n- savingGoals ([]SavingGoal): goals where the caller is a contributor, each with\n  a computed goalImageUrl.\n\nErrors:\n- unauthenticated: missing or invalid Bearer token.\n- internal: store failure.\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "listTransactions",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"listTransactions\",\n  \"params\": {\n    \"pagination\": {\n      \"limit\": 10,\n      \"skip\": 0\n    }\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "List Transactions - retrieves transactions for the authenticated user with optional filtering.\n\nThis handler returns transactions from accounts where the user is either the owner or collaborator.\nIt supports comprehensive filtering by account, tags, vendors, categories, dates, amounts, and search queries.\n\nAuthentication: Required (Bearer token)\n\nParameters:\n- pagination (object, optional): Controls result paging\n  - limit (int): Max records to return, 0-100 (default 50; 0 also means the default)\n  - skip (int): Number of records to skip (non-negative)\n- sort (array, optional): Sort criteria (default: transactedAt DESC); only the first entry is applied\n  - field (string): One of transactedAt, amount, name, vendorName, category, createdAt, updatedAt, _id\n  - operator (string): Sort direction (\"ASC\" or \"DESC\")\n- ids (array, optional): Filter by transaction IDs (at most 500, unique, non-empty)\n- accountId (string, optional): Filter by single account ID (legacy, use accountIds)\n- accountIds (array, optional): Filter by multiple account IDs (at most 100, unique, non-empty)\n- tagIds (array, optional): Filter transactions that have all specified tags (at most 500)\n- vendorIds (array, optional): Filter by vendor IDs (at most 500)\n- vendorNames (array, optional): Filter by vendor names (vendorId must be null/empty; at most 500)\n- categories (array, optional): Filter by transaction categories (FOOD, RENT, INCOME, etc.; at most 500)\n- categoryIds (array, optional): Filter by transaction category IDs (new category system; at most 500)\n- sources (array, optional): Filter by transaction sources (BANK_INTEGRATION, MANUAL, etc.; at most 500)\n- startDate (string, optional): Filter transactions on or after this date (ISO 8601)\n- endDate (string, optional): Filter transactions on or before this date (ISO 8601)\n- searchQuery (string, optional): Case-insensitive literal substring match on transaction name, description, or vendor name\n- transactionType (string, optional): Filter by type (\"INCOME\", \"EXPENSE\", \"TRANSFER\")\n- minAmountInclusive (number, optional): Minimum transaction amount (inclusive)\n- maxAmountInclusive (number, optional): Maximum transaction amount (inclusive)\n- minimumAbsoluteAmountInclusive (number, optional): Minimum absolute amount (inclusive, matches positive or negative)\n- maximumAbsoluteAmountInclusive (number, optional): Maximum absolute amount (inclusive, matches positive or negative)\n- includeUntagged (boolean, optional): Include untagged transactions when filtering by tags\n\nReturns:\n- transactions (array): Array of transaction objects\n- numItems (int): Total number of transactions matching the filter (ignoring limit)\n\nExample:\n{\n  \"method\": \"listTransactions\",\n  \"params\": {\n    \"pagination\": {\n      \"limit\": 20,\n      \"skip\": 0\n    },\n    \"sort\": [\n      {\n        \"field\": \"transactedAt\",\n        \"operator\": \"DESC\"\n      }\n    ],\n    \"accountIds\": [\"account_123\"],\n    \"categories\": [\"FOOD\", \"ENTERTAINMENT\"],\n    \"startDate\": \"2024-01-01T00:00:00Z\",\n    \"endDate\": \"2024-12-31T23:59:59Z\",\n    \"minAmountInclusive\": -10000,\n    \"maxAmountInclusive\": 0\n  }\n}\n\nThis request is read-only.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        },
        {
          "name": "updateTransaction",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "body": {
              "mode": "raw",
              "raw": "{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"updateTransaction\",\n  \"params\": {\n    \"transactionId\": \"tx_9bLm4Rt7Yc\",\n    \"transaction\": {\n      \"name\": \"Morning coffee\"\n    },\n    \"transactionFieldMasks\": [\n      {\n        \"path\": \"name\"\n      }\n    ]\n  },\n  \"id\": 1\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            },
            "url": "{{apiBaseUrl}}",
            "description": "updateTransaction — partially updates a transaction using field masks.\n\nAuthentication: Required (Bearer token). User must be account owner or collaborator,\nwith OWNER or COOWNER role if a role is assigned.\n\nParameters:\n- transactionId (string, required): ID of the transaction to update\n- transaction (object, required): Fields to update (all optional)\n  - accountId (string): Destination account ID for moving a manual transaction. The accountId field must also be included in transactionFieldMasks. Transactions with source BANK_INTEGRATION cannot be moved between accounts. Destination-account authorization is enforced.\n  - name (string): New display name\n  - amount (float): New amount in smallest denomination\n  - category (string): Top-level category (auto-resolves categoryId if not provided)\n  - categoryId (string): v2 category ID\n  - incomeCategory (string): Income sub-category\n  - expenseCategory (string): Expense sub-category\n  - subcategory (string): Sub-category label\n  - vendorId (string): Vendor ID\n  - vendorName (string): Vendor display name\n  - description (string): Notes\n  - transactedAt (string): ISO 8601 datetime\n  - isPending (bool): Pending flag\n  - inReview (bool): In-review flag\n  - fileIds ([string]): Attached file IDs (replaces existing)\n  - tagIds ([string]): Attached tag IDs (replaces existing)\n  - cronExpression (string): Recurrence cron expression\n  - endDate (string): ISO 8601 recurrence end date\n  - isExcludedFromAnalytics (bool): Exclude from analytics\n  - lineItems ([{id, name, amount}]): Line items (replaces existing)\n  - oneOffSplitParticipants ([{id?, name, amount}]): Freeform Split With Others rows reconciled by persisted row id. Omit id to add a new row.\n  - deletedOneOffSplitParticipants ([string]): Persisted split row ids to delete\n- transactionFieldMasks (array, required): Array of {path} objects specifying which fields to update\n\nReturns:\n- transactionId (string): ID of the updated transaction\n\nThis request can change real data or send email. Review its parameters before sending.\n\nExample identifiers may not exist in your account. Replace them with your own IDs where needed."
          }
        }
      ]
    }
  ]
}
