Kubera Data API v3

Read and write your Kubera portfolio programmatically — authenticate with an API key/secret, list and export portfolios, create and update assets and debts, manage cash flow entries, and archive items.

On this page

Authentication

Generate your API key and secret from Kubera Settings > API.

  • IP restrictions are optional but highly recommended.
  • Keep your API key and secret confidential at all times.
  • In case of accidental disclosure, delete the compromised keys.
  • When creating a key, choose the appropriate permission level. The default setting is “Read portfolio data”.
  • Remove any API keys that are no longer in use.

Required headers

Every request must include these three headers:

Header Value
x-api-token     Your API key
x-timestamp     Current time in seconds (Unix epoch)
x-signature     HMAC-SHA256 signature (see below)

Signature generation

Build the signing string by concatenating the API key, timestamp, HTTP method, request path, and the compact JSON body, then sign it with HMAC-SHA256 using your secret. The hex digest is your x-signature    .

JavaScript

const crypto = require('crypto-js');
const apiKey = 'Your API Key';
const secret = 'Your API Secret';
const timestamp = Math.floor(Date.now() / 1000); // x-timestamp
const bodyData = JSON.stringify(request.body); // use compact encoding
const data = `${apiKey}${timestamp}POST${request.path}${bodyData}`;
const signature = crypto.HmacSHA256(data, secret).toString(crypto.enc.Hex); // x-signature

Python

import time
import math
import requests
import hashlib
import hmac
import json

api_key = "Your API Key"
secret = "Your API Secret"
item_id = "Item ID"
request_body = {"value": 400}
timestamp = str(math.floor(time.time()))  # x-timestamp
bodyData = json.dumps(request_body, separators=(',', ':')) if request_body else ""
requestType = "POST"
request_path = f"/api/v3/data/item/{item_id}"
data = f"{api_key}{timestamp}{requestType}{request_path}{bodyData}"
signature = hmac.new(
    secret.encode('utf-8'),
    data.encode('utf-8'),
    hashlib.sha256
).hexdigest()  # x-signature

Note

The body must be serialized with compact encoding (no spaces between keys/values), and the exact same string must be sent as the request body. For a request with no body (e.g. GET), use an empty string.

For example, with Request.body = { value: 400 }     and Request.path = /api/v3/data/item/<ASSET_ID/DEBT_ID>    , add the headers:

x-timestamp: timestamp
x-signature: signature

More examples

Worked examples using a sample key and secret:

const crypto = require('crypto-js');
let apiKey = 'a20d0129-c121-433c-90e3-97068458584d';
let secret = 's-397a324204a34921a72c9ec7a41c22f2';

Case 1 — GET (no body)

timestamp = 1726554618;
bodyData  = ``;
data      = `a20d0129-c121-433c-90e3-97068458584d1726554618GET/api/v3/data/portfolio`;
signature = 8a24943d24d6def02b38fd6522a4a899883243f30e9f3bda715ddbb6345e0abf

Case 2 — POST (with body)

timestamp = 1726554715;
bodyData  = `{"value":400}`;
data      = `a20d0129-c121-433c-90e3-97068458584d1726554715POST/api/v3/data/item/27f59377-44e8-4a94-ac3b-f1e1c5080a48{"value":400}`;
signature = 584977d5822c3bf697ce929cc86ef4ac41331edba4f3d3c55d0d67361b76542e

API limits

There are different types of limits, all of which are subject to change at any time.

Limit Threshold
Rate 30 requests per minute
Kubera Essential 500 requests per day (UTC)
Kubera Black 2000 requests per day (UTC)

Export – portfolio list

Fetch the list of portfolios.

curl --location --request GET 'https://api.kubera.com/api/v3/data/portfolio' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>'

Response

{
  "data": portfolio[],
  "errorCode": 0
}

Portfolio object

{
  "id": Portfolio Id,
  "name": Portfolio Name,
  "currency": Portfolio Currency
}

Example:

{
  "id": "6eb1ac79-2ae1-49e6-aada-3a5fb4fdce55",
  "name": "Mike",
  "currency": "USD"
}

Export – portfolio data

Fetch a particular user portfolio’s data.

curl --location --request GET 'https://api.kubera.com/api/v3/data/portfolio/<PORTFOLIO_ID>' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>'

Note

Use the PORTFOLIO_ID     from the Export – user portfolio list response.

Basic response

{
  "data": {
    "asset": asset[],
    "debt": debt[],
    "id": Portfolio id,
    "name": Portfolio Name,
    "ticker": Portfolio Currency,
    "timestamp": Time,
    "document": document[],
    "insurance": insurance[],
    "totalAssets": { "amount": number, "currency": number },
    "totalDebts": { "amount": number, "currency": number },
    "netWorth": { "amount": number, "currency": number },
    "costBasis": Number,
    "unrealizedGain": Number,
    "allocationByAssetClass": {
      "Cash": Number,
      "Crypto": Number,
      "Stock": Number,
      "Fund": Number,
      "Derivative": Number,
      "Investment": Number
    }
  },
  "errorCode": 0
}

(Additional fields may be provided.)

Create – item

Note

Use the PORTFOLIO_ID     from the Export – user portfolio list response.

Create a new manual asset or debt in a portfolio. The item is added to the portfolio’s first Asset section (or first Debt section when isDebt     is true    ), unless sheetName    /sectionName     match an existing section.

curl --location --request POST 'https://api.kubera.com/api/v3/data/item' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>' \
--data '{
  "portfolioId": "<PORTFOLIO_ID>",
  "name": "Apple",
  "ticker": "AAPL",
  "value": 10,
  "cost": 1500
}'

For a cash / manually-valued item, pass currency     instead of ticker     (or neither, to use the portfolio currency):

curl --location --request POST 'https://api.kubera.com/api/v3/data/item' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>' \
--data '{
  "portfolioId": "<PORTFOLIO_ID>",
  "name": "Savings",
  "currency": "USD",
  "value": 5000
}'

Important

The value     field is overloaded:

  • When ticker     is set (a ticker-backed holding such as a stock, ETF, fund, crypto or precious metal), value     is the quantity held (shares/units), not a currency amount. Kubera derives the market value as quantity × price.
  • For a cash / manually-valued item, value     is the monetary amount in the item’s currency.

cost     is always a monetary amount (a total, not a per-unit price).

Allowed properties

Property Type Description
portfolioId     string Required. Portfolio to add the item to.
name     string Required. Item name.
value     number Required. Quantity (ticker items) or amount (cash items).
ticker     string Ticker symbol, e.g. AAPL, BTC. When set, value     is the quantity.
currency     string Currency code for a cash item, e.g. USD. Ignored when ticker     is set. Defaults to the portfolio currency.
cost     number Cost basis as a monetary amount.
description     string
isDebt     boolean true     to create a debt. Defaults to false     (asset).
sheetName     string Target an existing section by sheet name (with sectionName    ).
sectionName     string Target an existing section by name.

Note: symbol     is accepted as a legacy alias for ticker    ; prefer ticker    .

Response

{
  "data": {
    "success": true,
    "itemId": New Item Id,
    "portfolioId": Portfolio Id,
    "sectionId": Section Id
  },
  "errorCode": 0
}

Example:

{
  "data": {
    "success": true,
    "itemId": "cust-abc",
    "portfolioId": "6eb1ac79-2ae1-49e6-aada-3a5fb4fdce55",
    "sectionId": "9fcbee08-3524-470f-9352-ba99f0f6cf37"
  },
  "errorCode": 0
}

Update – item

Note

Use the ASSET_ID     / DEBT_ID     from the Export – user portfolio data response.

Update a particular asset or debt.

curl --location --request POST 'https://api.kubera.com/api/v3/data/item/<ASSET_ID/DEBT_ID>' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>' \
--data '{
  "value": 400
}'

You can modify historical values by sending a POST request in the following format:

curl --location --request POST 'https://api.kubera.com/api/v3/data/item/<ASSET_ID/DEBT_ID>' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>' \
--data '{
  "value": 350,
  "date": "2026-01-01"
}'

Allowed properties

Property Type Description
name     string
description     string
value     number
cost     number
date     string YYYY-MM-DD format.

Archive – item

Note

Use the ASSET_ID     / DEBT_ID     from the Export – user portfolio data response.

Archive a single manual asset or debt. Behavior depends on the item:

  • holding (belongs to a parent account) has its value zeroed; the parent and sibling holdings are untouched.
  • top-level account is archived.

Only manually-added items can be archived. Connected/linked accounts (bank, brokerage, crypto, etc.) cannot be archived and are rejected.

curl --location --request POST 'https://api.kubera.com/api/v3/data/item/<ASSET_ID/DEBT_ID>/archive' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>'

No request body is required.

Response

{
  "data": {},
  "errorCode": 0
}

Get cash flow entries

Fetch the list of cash flow entries.

curl --location --request GET 'https://api.kubera.com/api/v3/data/item/<ASSET_ID>/cashFlow' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>'

Response

{
  "data": cashFlow[],
  "errorCode": 0
}

cashFlow object

{
  "cashIn": Number,
  "cashOut": Number,
  "currency": String,
  "date": String,
  "note": String
}

Example:

{
  "cashIn": 300,
  "cashOut": null,
  "currency": "USD",
  "date": "2025-02-02",
  "note": "Initial investment"
}

Insert/update cash flow entries

curl --location --request POST 'https://api.kubera.com/api/v3/data/item/<ASSET_ID>/cashFlow' \
--header 'Content-Type: application/json' \
--header 'x-api-token: <API_KEY>' \
--header 'x-timestamp: <TIMESTAMP>' \
--header 'x-signature: <SIGNATURE>' \
--data '{
  "cashIn": 100.0,
  "cashOut": 200.0,
  "date": "2025-04-02",
  "currency": "USD",
  "note": "3rd investment"
}'

Object reference

Asset / Debt / Insurance object

Field Description
accountNumber     Account number
cashIn     Value object
cashOut     Value object
category     Type — asset / debt / insurance
committedCapital     Value object
connection     Connection object
cost     Cost object
costBasisForTax     Value object
description     Item description
exchange     Exchange name
holdingsCount     Number of holdings
id     Asset / debt / insurance id
investable     Investable type. non_investable     / investable_easy_convert     / investable_cash    
irr     IRR
isin     ISIN
name     Name
note     Item note
ownership     Ownership percentage
parent     Parent account object
quantity     Quantity
rate     Rate object
sectionId     Containing section id
sectionName     Section name
sheetId     Containing sheet id
sheetName     Sheet name
subType     More detailed item type
taxability     taxable     / tax-deferred     / tax-free    
taxOnUnrealizedGain     Value object
taxRate     Tax percentage
ticker     Ticker symbol
tickerId     Ticker id
tickerSector     Sector name
tickerSubType     Asset class
unfunded     Value object
value     Value object

Document object

Field Description
fileType     MIME type
id     Document id
name     Name
size     Size in bytes

Value object

Field Description
amount     Numeric amount
currency     Currency code

Connection object

Field Description
accountId     Account id
aggregator     Aggregator name
id     Connection id
lastUpdatedTimestamp     Last updated timestamp
providerName     Institution name

Rate object

Field Description
currency     Currency
price     Price

Example — holding

{
  "id": "9f4445b3-0b25-49fb-b1d9-4387e081639d_8E4L9XLl6MudjEpwPAAgivmdZRdBPJuvMPlPb",
  "name": "Nflx Feb 01'18 $355 Call",
  "sectionId": "9fcbee08-3524-470f-9352-ba99f0f6cf37",
  "sectionName": "Chase - Plaid IRA - 5555",
  "sheetId": "627a1796-f28e-4646-a796-d983e8576d46",
  "sheetName": "Sheet 6",
  "category": "asset",
  "value": { "amount": 110, "currency": "USD" },
  "ticker": "USD",
  "tickerId": 150,
  "tickerSubType": null,
  "tickerSector": "Other",
  "quantity": 110,
  "irr": 1099900,
  "investable": "investable_easy_to_convert",
  "ownership": 100,
  "description": null,
  "note": null,
  "isin": null,
  "subType": "derivative",
  "holdingsCount": 0,
  "cost": { "amount": 0.01, "currency": "USD" },
  "costBasisForTax": { "amount": 0.01, "currency": "USD" },
  "taxRate": 30,
  "taxability": "taxable",
  "taxOnUnrealizedGain": { "amount": 32.997, "currency": "USD" },
  "connection": {
    "aggregator": "plaid",
    "providerName": "Chase",
    "lastUpdatedTimestamp": 1723452761,
    "id": "9DorR9zEmNsqA6xvyM1JtmolBWNWNjfRzBpv4",
    "accountId": "P6LzkBlD1Xhn3B649KLvcxE14Jm37Vuo47Wzk"
  },
  "parent": {
    "id": "9f4445b3-0b25-49fb-b1d9-4387e081639d",
    "name": "Chase - Plaid IRA - 5555"
  }
}

Example — account

{
  "id": "9f4445b3-0b25-49fb-b1d9-4387e081639d",
  "name": "Chase - Plaid IRA - 5555",
  "sectionId": "9fcbee08-3524-470f-9352-ba99f0f6cf37",
  "sectionName": "Chase - Plaid IRA - 5555",
  "sheetId": "627a1796-f28e-4646-a796-d983e8576d46",
  "sheetName": "Sheet 6",
  "category": "asset",
  "value": { "amount": 249.20000000000002, "currency": "USD" },
  "ticker": "USD",
  "tickerId": 150,
  "tickerSubType": null,
  "tickerSector": "Other",
  "quantity": 249.20000000000002,
  "irr": 522.8442889277682,
  "investable": "investable_easy_convert",
  "ownership": 100,
  "description": null,
  "note": null,
  "isin": null,
  "subType": "investment",
  "holdingsCount": 2,
  "cost": { "amount": 40.01, "currency": "USD" },
  "costBasisForTax": { "amount": 40.01, "currency": "USD" },
  "taxRate": 30,
  "taxability": "taxable",
  "taxOnUnrealizedGain": { "amount": 62.757000000000005, "currency": "USD" },
  "connection": {
    "aggregator": "plaid",
    "providerName": "Chase",
    "lastUpdatedTimestamp": null,
    "id": "9DorR9zEmNsqA6xvyM1JtmolBWNWNjfRzBpv4",
    "accountId": "P6LzkBlD1Xhn3B649KLvcxE14Jm37Vuo47Wzk"
  }
}

Unofficial SDKs

Heads up

These are not maintained or verified by the Kubera team. Use at your own risk.