{"openapi":"3.1.0","info":{"title":"P2P Dash API","version":"1.0.0","description":"Read-only access to your own P2P Dash data. The account, each portfolio and each platform offer the same five views: `summary`, `timeseries`, `metrics`, `income-projection` and `tax`. All amounts are EUR. Errors are JSON with an `error.code`, also for a path that does not exist (404). The one exception: a method an endpoint does not support gets a 405 without a body. This is the first version of the API and it is still changing: fields and endpoints can change without a new version."},"servers":[{"url":"/"}],"security":[{"bearerAuth":["account:read"]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"Personal Access Token, e.g. `p2pdash_…`. Every endpoint needs the `account:read` scope."}},"schemas":{"AccountInfo":{"type":"object","properties":{"access":{"type":"array","items":{"type":"string","enum":["account","stats","admin"]},"description":"The API areas the token's owner may use. A token still needs the matching scope for each."},"token":{"type":"object","properties":{"name":{"type":["string","null"]},"scopes":{"type":"array","items":{"type":"string","enum":["account:read","stats:read","admin:read","admin:write"]}},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"expiresAt":{"type":["string","null"],"description":"ISO-8601 timestamp, null for a token that never expires"}},"required":["name","scopes","createdAt","expiresAt"]}},"required":["access","token"]},"Error":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string","enum":["unauthorized","insufficient_scope","forbidden","plan_required","rate_limited","not_found","invalid_request","internal_error"]},"message":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"field":{"type":"string","description":"Dotted path into the query or body, empty for the input as a whole","example":"from"},"message":{"type":"string"}},"required":["field","message"]},"description":"Only with `invalid_request`: one entry per rejected field. `message` repeats the first."}},"required":["code","message"]}},"required":["error"]},"Summary":{"type":"object","properties":{"platformCount":{"type":"integer","description":"Platforms with data in this scope"},"firstDate":{"type":["string","null"],"description":"UTC day of the first data, null without data","example":"2021-03-02"},"lastDate":{"type":["string","null"],"description":"UTC day of the last data, null without data","example":"2024-06-15"},"interest":{"type":"number"},"principalRepayment":{"type":"number"},"fee":{"type":"number"},"tax":{"type":"number"},"bonus":{"type":"number"},"deposit":{"type":"number"},"withdrawal":{"type":"number"},"investment":{"type":"number"},"defaultLoss":{"type":"number"},"internalTransfer":{"type":"number"},"transactionCount":{"type":"integer"},"totalBalance":{"type":"number","description":"Account value: deposit − withdrawal + interest + bonus − fee − tax − defaultLoss. Equals availableBalance + investedBalance; computed amounts are rounded to 8 decimals, so compare with a tolerance."},"availableBalance":{"type":"number","description":"Cash on the platform that is not invested"},"investedBalance":{"type":"number","description":"investment − principalRepayment − defaultLoss"},"netDeposits":{"type":"number","description":"deposit − withdrawal"},"netIncome":{"type":"number","description":"interest + bonus − fee − tax − defaultLoss"}},"required":["platformCount","firstDate","lastDate","interest","principalRepayment","fee","tax","bonus","deposit","withdrawal","investment","defaultLoss","internalTransfer","transactionCount","totalBalance","availableBalance","investedBalance","netDeposits","netIncome"]},"TimeseriesPoint":{"type":"object","properties":{"date":{"type":"string","description":"UTC calendar day, the last day of the bucket","example":"2024-06-15"},"interest":{"type":"number"},"principalRepayment":{"type":"number"},"fee":{"type":"number"},"tax":{"type":"number"},"bonus":{"type":"number"},"deposit":{"type":"number"},"withdrawal":{"type":"number"},"investment":{"type":"number"},"defaultLoss":{"type":"number"},"internalTransfer":{"type":"number"},"transactionCount":{"type":"integer"},"totalBalance":{"type":"number","description":"Account value: deposit − withdrawal + interest + bonus − fee − tax − defaultLoss. Equals availableBalance + investedBalance; computed amounts are rounded to 8 decimals, so compare with a tolerance."},"availableBalance":{"type":"number","description":"Cash on the platform that is not invested"},"investedBalance":{"type":"number","description":"investment − principalRepayment − defaultLoss"},"sources":{"type":"array","items":{"type":"string","enum":["imported","manual","estimated"]},"description":"Where the rows behind this point come from: `imported` from a platform export, `manual` entered by hand, `estimated` cash flows the app derived because the export lacks them."}},"required":["date","interest","principalRepayment","fee","tax","bonus","deposit","withdrawal","investment","defaultLoss","internalTransfer","transactionCount","totalBalance","availableBalance","investedBalance","sources"],"description":"The money moved within the bucket and the closing balances at the end of it. Balances count from the first day of data, also when `from` narrows the response. Only days with data produce a point; between two points the balances do not change."},"XirrMetrics":{"type":"object","properties":{"total":{"type":"object","properties":{"allTimeXirr":{"type":["number","null"]},"allTimeXirrExclBonus":{"type":["number","null"]},"yearly":{"type":"object","additionalProperties":{"type":["number","null"]},"description":"Year → XIRR (fraction), e.g. { \"2024\": 0.075 }"},"yearlyExclBonus":{"type":"object","additionalProperties":{"type":["number","null"]},"description":"Year → XIRR (fraction), e.g. { \"2024\": 0.075 }"}},"required":["allTimeXirr","allTimeXirrExclBonus","yearly","yearlyExclBonus"]},"platforms":{"type":"array","items":{"type":"object","properties":{"allTimeXirr":{"type":["number","null"]},"allTimeXirrExclBonus":{"type":["number","null"]},"yearly":{"type":"object","additionalProperties":{"type":["number","null"]},"description":"Year → XIRR (fraction), e.g. { \"2024\": 0.075 }"},"yearlyExclBonus":{"type":"object","additionalProperties":{"type":["number","null"]},"description":"Year → XIRR (fraction), e.g. { \"2024\": 0.075 }"},"id":{"type":"string"},"name":{"type":"string"}},"required":["allTimeXirr","allTimeXirrExclBonus","yearly","yearlyExclBonus","id","name"]}}},"required":["total","platforms"]},"Metrics":{"type":"object","properties":{"xirr":{"$ref":"#/components/schemas/XirrMetrics"},"cashDrag":{"type":"object","properties":{"total":{"type":"object","properties":{"allTime":{"type":["number","null"]},"yearly":{"type":"object","additionalProperties":{"type":["number","null"]},"description":"Year → value in the unit of the enclosing metric, e.g. { \"2024\": 0.012 }; null = no data for that year"}},"required":["allTime","yearly"]},"platforms":{"type":"array","items":{"type":"object","properties":{"allTime":{"type":["number","null"]},"yearly":{"type":"object","additionalProperties":{"type":["number","null"]},"description":"Year → value in the unit of the enclosing metric, e.g. { \"2024\": 0.012 }; null = no data for that year"},"id":{"type":"string"},"name":{"type":"string"}},"required":["allTime","yearly","id","name"]}}},"required":["total","platforms"],"description":"Idle-cash share (fraction). Lower is better."},"averageBalance":{"type":"object","properties":{"total":{"type":"object","properties":{"allTime":{"type":["number","null"]},"yearly":{"type":"object","additionalProperties":{"type":["number","null"]},"description":"Year → value in the unit of the enclosing metric, e.g. { \"2024\": 0.012 }; null = no data for that year"}},"required":["allTime","yearly"]},"platforms":{"type":"array","items":{"type":"object","properties":{"allTime":{"type":["number","null"]},"yearly":{"type":"object","additionalProperties":{"type":["number","null"]},"description":"Year → value in the unit of the enclosing metric, e.g. { \"2024\": 0.012 }; null = no data for that year"},"id":{"type":"string"},"name":{"type":"string"}},"required":["allTime","yearly","id","name"]}}},"required":["total","platforms"],"description":"Time-weighted average invested balance."},"capitalFreedomIndex":{"type":"object","properties":{"total":{"type":"number"},"platforms":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"value":{"type":"number"}},"required":["id","name","value"]}}},"required":["total","platforms"],"description":"Share of the current balance not backed by net deposits (deposits − withdrawals), 0–100; 100 = all own capital withdrawn (per platform + total)."}},"required":["xirr","cashDrag","averageBalance","capitalFreedomIndex"]},"TaxReportPlatform":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"years":{"type":"array","items":{"type":"object","properties":{"year":{"type":"integer"},"interest":{"type":"number"},"bonus":{"type":"number"},"tax":{"type":"number"},"fee":{"type":"number"},"defaultLoss":{"type":"number"},"deposit":{"type":"number"},"withdrawal":{"type":"number"}},"required":["year","interest","bonus","tax","fee","defaultLoss","deposit","withdrawal"]},"description":"Newest year first"}},"required":["id","name","type","years"]},"IncomeProjection":{"type":"object","properties":{"total":{"type":["object","null"],"properties":{"currentBalance":{"type":"number"},"xirr":{"type":["number","null"],"description":"All-time XIRR without bonus (fraction), the rate the earnings are projected from; compare with allTimeXirrExclBonus in the metrics, not allTimeXirr."},"dailyEarnings":{"type":["number","null"]},"monthlyEarnings":{"type":["number","null"]},"annualEarnings":{"type":["number","null"]}},"required":["currentBalance","xirr","dailyEarnings","monthlyEarnings","annualEarnings"]},"platforms":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string"},"currentBalance":{"type":"number"},"xirr":{"type":["number","null"],"description":"All-time XIRR without bonus (fraction), the rate the earnings are projected from; compare with allTimeXirrExclBonus in the metrics, not allTimeXirr."},"dailyEarnings":{"type":["number","null"]},"monthlyEarnings":{"type":["number","null"]},"annualEarnings":{"type":["number","null"]}},"required":["id","name","type","currentBalance","xirr","dailyEarnings","monthlyEarnings","annualEarnings"]}}},"required":["total","platforms"]},"Totals":{"type":"object","properties":{"interest":{"type":"number"},"principalRepayment":{"type":"number"},"fee":{"type":"number"},"tax":{"type":"number"},"bonus":{"type":"number"},"deposit":{"type":"number"},"withdrawal":{"type":"number"},"investment":{"type":"number"},"defaultLoss":{"type":"number"},"internalTransfer":{"type":"number"},"transactionCount":{"type":"integer"},"totalBalance":{"type":"number","description":"Account value: deposit − withdrawal + interest + bonus − fee − tax − defaultLoss. Equals availableBalance + investedBalance; computed amounts are rounded to 8 decimals, so compare with a tolerance."},"availableBalance":{"type":"number","description":"Cash on the platform that is not invested"},"investedBalance":{"type":"number","description":"investment − principalRepayment − defaultLoss"},"netDeposits":{"type":"number","description":"deposit − withdrawal"},"netIncome":{"type":"number","description":"interest + bonus − fee − tax − defaultLoss"}},"required":["interest","principalRepayment","fee","tax","bonus","deposit","withdrawal","investment","defaultLoss","internalTransfer","transactionCount","totalBalance","availableBalance","investedBalance","netDeposits","netIncome"],"description":"All-time sums and the balances that follow from them."},"PlatformRef":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","description":"Key into the platform types list","example":"mintos"},"intent":{"type":["string","null"],"enum":["grow","compound","hold","shrink","exit"]},"color":{"type":["string","null"],"description":"The user's own color; null means the platform type's color","example":"#ff0000"}},"required":["id","name","type","intent","color"]},"Platform":{"allOf":[{"$ref":"#/components/schemas/PlatformRef"},{"type":"object","properties":{"firstDate":{"type":["string","null"],"description":"UTC day of the first data, null without data","example":"2021-03-02"},"lastDate":{"type":["string","null"],"description":"UTC day of the last data, null without data","example":"2024-06-15"},"portfolios":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"]},"description":"The portfolios this platform belongs to"},"summary":{"$ref":"#/components/schemas/Totals"}},"required":["firstDate","lastDate","portfolios","summary"]}]},"IntentChange":{"type":"object","properties":{"changedAt":{"type":"string","description":"ISO-8601 timestamp"},"fromIntent":{"type":["string","null"],"enum":["grow","compound","hold","shrink","exit"],"description":"null = no intent before"},"toIntent":{"type":["string","null"],"enum":["grow","compound","hold","shrink","exit"],"description":"null = intent cleared"}},"required":["changedAt","fromIntent","toIntent"]},"PlatformType":{"type":"object","properties":{"type":{"type":"string","example":"mintos"},"name":{"type":"string","example":"Mintos"},"url":{"type":["string","null"]},"country":{"type":["string","null"],"description":"Where the platform is based, ISO 3166-1 alpha-2","example":"LV"},"investmentCountries":{"type":"array","items":{"type":"string"},"description":"Countries the loans come from, ISO 3166-1 alpha-2"},"assetClasses":{"type":"array","items":{"type":"string"},"description":"Primary first","example":["consumer","sme"]},"foundingYear":{"type":["integer","null"],"description":"Year the platform opened to investors"},"regulation":{"type":["object","null"],"properties":{"tier":{"type":"integer","minimum":1,"maximum":4,"description":"1 = MiFID II, 2 = ECSP, 3 = national regulation, 4 = none"},"licenses":{"type":"array","items":{"type":"string"}},"authority":{"type":["string","null"]},"investorProtection":{"type":["number","null"],"description":"Limit of the investor compensation scheme in EUR"}},"required":["tier","licenses","authority","investorProtection"]},"secondaryMarket":{"type":["boolean","null"]},"buybackGuarantee":{"type":["boolean","null"]},"autoInvest":{"type":["boolean","null"]},"color":{"type":"string","example":"#fc62b3"}},"required":["type","name","url","country","investmentCountries","assetClasses","foundingYear","regulation","secondaryMarket","buybackGuarantee","autoInvest","color"],"description":"Facts about a platform type, the same for every caller. null or an empty list means the fact is not on file."},"Portfolio":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":["string","null"]},"shareType":{"type":["string","null"],"enum":["percentage","absolute"]},"createdAt":{"type":"string","description":"ISO-8601 timestamp"},"updatedAt":{"type":"string","description":"ISO-8601 timestamp"},"platforms":{"type":"array","items":{"$ref":"#/components/schemas/PlatformRef"}}},"required":["id","name","description","shareType","createdAt","updatedAt","platforms"]}},"parameters":{}},"paths":{"/api/v1/account":{"get":{"operationId":"getAccount","tags":["Account"],"summary":"The calling token and what its owner may use","description":"A cheap call to check that a token works.","security":[{"bearerAuth":["account:read"]}],"responses":{"200":{"description":"Token and access","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AccountInfo"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/account/summary":{"get":{"operationId":"getAccountSummary","tags":["Account"],"summary":"Account totals across all platforms","security":[{"bearerAuth":["account:read"]}],"responses":{"200":{"description":"Aggregated account summary","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Summary"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/account/timeseries":{"get":{"operationId":"getAccountTimeseries","tags":["Account"],"summary":"Aggregated timeseries across all platforms","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Inclusive lower bound. For `month`/`year` granularity it is snapped down to the start of its period, so returned buckets are always whole periods — the response may therefore begin before the supplied `from` date.","example":"2024-01-01"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Inclusive upper bound. For `month`/`year` granularity it is snapped up to the end of its period.","example":"2024-12-31"},"required":false,"name":"to","in":"query"},{"schema":{"type":"string","enum":["day","month","year"],"description":"Roll-up bucket (default `day`). `month`/`year` buckets are dated to the last day of the period (e.g. `2024-06-30`, `2024-12-31`).","example":"month"},"required":false,"name":"granularity","in":"query"}],"responses":{"200":{"description":"Timeseries points","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesPoint"}}},"required":["data"]}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/account/metrics":{"get":{"operationId":"getAccountMetrics","tags":["Account"],"summary":"Analytics: XIRR, cash drag, average balance, capital freedom","security":[{"bearerAuth":["account:read"]}],"responses":{"200":{"description":"Account metrics","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Metrics"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/account/tax":{"get":{"operationId":"getAccountTax","tags":["Account"],"summary":"Tax-relevant figures per platform and year","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"integer","description":"Only this calendar year. Platforms without data in it are left out.","example":2024},"required":false,"name":"year","in":"query"}],"responses":{"200":{"description":"Tax report","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxReportPlatform"}}},"required":["data"]}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/account/income-projection":{"get":{"operationId":"getAccountIncomeProjection","tags":["Account"],"summary":"Projected earnings from current balance and XIRR","security":[{"bearerAuth":["account:read"]}],"responses":{"200":{"description":"Income projection","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/IncomeProjection"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platforms":{"get":{"operationId":"listPlatforms","tags":["Platforms"],"summary":"List platforms with their totals","security":[{"bearerAuth":["account:read"]}],"responses":{"200":{"description":"Platform list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Platform"}}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platforms/{id}":{"get":{"operationId":"getPlatform","tags":["Platforms"],"summary":"A single platform with its totals","description":"The same object as in the platform list.","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Platform","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Platform"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Platform not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platforms/{id}/summary":{"get":{"operationId":"getPlatformSummary","tags":["Platforms"],"summary":"Totals for a single platform","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Platform summary","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Summary"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Platform not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platforms/{id}/timeseries":{"get":{"operationId":"getPlatformTimeseries","tags":["Platforms"],"summary":"Timeseries for a single platform","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Inclusive lower bound. For `month`/`year` granularity it is snapped down to the start of its period, so returned buckets are always whole periods — the response may therefore begin before the supplied `from` date.","example":"2024-01-01"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Inclusive upper bound. For `month`/`year` granularity it is snapped up to the end of its period.","example":"2024-12-31"},"required":false,"name":"to","in":"query"},{"schema":{"type":"string","enum":["day","month","year"],"description":"Roll-up bucket (default `day`). `month`/`year` buckets are dated to the last day of the period (e.g. `2024-06-30`, `2024-12-31`).","example":"month"},"required":false,"name":"granularity","in":"query"}],"responses":{"200":{"description":"Timeseries points","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesPoint"}}},"required":["data"]}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Platform not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platforms/{id}/metrics":{"get":{"operationId":"getPlatformMetrics","tags":["Platforms"],"summary":"Analytics for a single platform","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Platform metrics","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Metrics"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Platform not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platforms/{id}/income-projection":{"get":{"operationId":"getPlatformIncomeProjection","tags":["Platforms"],"summary":"Projected earnings for a single platform","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Income projection","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/IncomeProjection"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Platform not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platforms/{id}/tax":{"get":{"operationId":"getPlatformTax","tags":["Platforms"],"summary":"Tax-relevant figures per year for a single platform","description":"The same list as the account tax report, with this platform as its only entry, or empty without data.","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","description":"Only this calendar year. Platforms without data in it are left out.","example":2024},"required":false,"name":"year","in":"query"}],"responses":{"200":{"description":"Tax report","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxReportPlatform"}}},"required":["data"]}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Platform not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platforms/{id}/intent-history":{"get":{"operationId":"getPlatformIntentHistory","tags":["Platforms"],"summary":"How the intent of a platform changed over time","description":"Every recorded change, oldest first. An intent that was set before changes were recorded has no entry, so the list can be empty while the platform has an intent.","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Intent changes","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/IntentChange"}}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Platform not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/platform-types":{"get":{"operationId":"listPlatformTypes","tags":["Reference"],"summary":"Facts about every supported platform type","description":"Country, asset classes and regulation per platform type. Join it to your platforms through `type`. The same data for every caller.","security":[{"bearerAuth":["account:read"]}],"responses":{"200":{"description":"Platform types","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PlatformType"}}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios":{"get":{"operationId":"listPortfolios","tags":["Portfolios"],"summary":"List portfolios with their platforms","security":[{"bearerAuth":["account:read"]}],"responses":{"200":{"description":"Portfolio list","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Portfolio"}}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios/{id}":{"get":{"operationId":"getPortfolio","tags":["Portfolios"],"summary":"A single portfolio with its platforms","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Portfolio detail","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Portfolio"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Portfolio not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios/{id}/summary":{"get":{"operationId":"getPortfolioSummary","tags":["Portfolios"],"summary":"Aggregated totals for a portfolio","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Portfolio summary","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Summary"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Portfolio not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios/{id}/timeseries":{"get":{"operationId":"getPortfolioTimeseries","tags":["Portfolios"],"summary":"Aggregated timeseries for a portfolio","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Inclusive lower bound. For `month`/`year` granularity it is snapped down to the start of its period, so returned buckets are always whole periods — the response may therefore begin before the supplied `from` date.","example":"2024-01-01"},"required":false,"name":"from","in":"query"},{"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"Inclusive upper bound. For `month`/`year` granularity it is snapped up to the end of its period.","example":"2024-12-31"},"required":false,"name":"to","in":"query"},{"schema":{"type":"string","enum":["day","month","year"],"description":"Roll-up bucket (default `day`). `month`/`year` buckets are dated to the last day of the period (e.g. `2024-06-30`, `2024-12-31`).","example":"month"},"required":false,"name":"granularity","in":"query"}],"responses":{"200":{"description":"Timeseries points","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TimeseriesPoint"}}},"required":["data"]}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Portfolio not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios/{id}/metrics":{"get":{"operationId":"getPortfolioMetrics","tags":["Portfolios"],"summary":"Analytics for a portfolio","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Portfolio metrics","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Metrics"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Portfolio not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios/{id}/income-projection":{"get":{"operationId":"getPortfolioIncomeProjection","tags":["Portfolios"],"summary":"Projected earnings for a portfolio","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Income projection","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/IncomeProjection"}},"required":["data"]}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Portfolio not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/portfolios/{id}/tax":{"get":{"operationId":"getPortfolioTax","tags":["Portfolios"],"summary":"Tax-relevant figures per platform and year for a portfolio","security":[{"bearerAuth":["account:read"]}],"parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","description":"Only this calendar year. Platforms without data in it are left out.","example":2024},"required":false,"name":"year","in":"query"}],"responses":{"200":{"description":"Tax report","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/TaxReportPlatform"}}},"required":["data"]}}}},"400":{"description":"Invalid query parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing, invalid, or expired token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Token lacks the required scope, the account has no access to this part of the API, or the plan excludes API access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Portfolio not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"Unexpected server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"webhooks":{}}