Your own holdings, not a public dataset. These are the only /v1 endpoints that write. A key reaches the portfolios of the account it belongs to, plus those colleagues shared with your organization, and nothing in a path, body or query string can name another account. Any other portfolio is reported as 404, exactly like one that does not exist. A change to a portfolio shared with you view only returns 403 forbidden, and only a portfolio's creator can delete it. An organization key owns no portfolios and reaches only those shared with its organization. Trackers are the API's other account-owned read surface, but they are managed only in the Portal.
The same portfolios are reachable from an AI assistant through the portfolio MCP tools and from your Equibles dashboard. All three read and write the same rows.
How a lot is recorded
A lot is one acquisition: what was bought or sold, how much of it, at what price, and when. Positions are lots rolled up for display, so the original cost and date always stay recoverable.
quantityis signed. Positive is long, negative is a short sale or a written (sold-to-open) option. Shares for a stock, contracts for an option.costPerUnitis a price, so it is never negative: what was paid for a long, what was received for a short. The direction is carried by the sign of the quantity alone. For an option it is the premium per share of the underlying: two contracts at $12.40 isquantity: 2,costPerUnit: 12.40, not 1240.- An option is identified by its OCC symbol (
optionContract). Its expiration, strike, type and contract size are read back from the live options data rather than parsed out of the symbol, so an unknown or expired symbol is rejected instead of stored. Find symbols with the options endpoints. - Quantities and costs are never restated for a stock split. Which side of a split a broker's figures were taken on is unknowable here, and guessing would corrupt your cost basis.
- A sale is a close, not an edit. Closing records the sale price and date and moves the result into
realizedGain; editing the quantity down instead loses it. Closing part of a lot splits it, and the remainder keeps its original cost basis. - A stock on another exchange is sent as
MIC:TICKER, its exchange's market identifier code and its ticker there:XPAR:AIRis Airbus in Paris,XLON:SHELis Shell in London. Lots, positions and watches return it astickerplusexchange, which is null for a U.S. listing. It is marked at its settled close only. - A lot is in its listing's currency. Each lot and position carries
currency, the currency its prices and own figures are in, in major units (London prices in pounds, not pence); options are in US dollars. - A portfolio reports in one
currency, chosen when it is created (USDby default; alsoEUR,GBP,CHF,DKK,NOK,SEK,CNYorHKD). Every total is in it, and each position and lot restates its figures there in itsconverted*fields: cost at the rate on the purchase date, or the broker rate sent asfxRatewith the lot, and value at the latest official rate, listed with its date inconversionRates. A closed lot's proceeds convert at the rate on its closing date. Each lot names the rates it converted at inpurchaseRateandcloseRate. - A portfolio holds at most 200 lots, and an account at most 10 portfolios.
How a portfolio is priced
Each position is marked from its own price lane and names both the lane and the trading session:
markSource: "SettledClose", the official end-of-day close, withmarkAsOfnaming its session.markSource: "LiveQuote", a live reading, used only when it belongs to a newer trading day than the settled close. Once the official row for that day is written, the settled close takes over again.markSource: "OptionDailyClose", the contract's own daily snapshot, attributed to the session the provider dated it with.markAsOf: nullmeans the session is unknown, never today.markSource: null, meaning the position could not be priced.markUnavailableReasonsays why, andmarkPerUnit,marketValueandunrealizedGainare allnull. No price is never reported as a price of zero, which would read as a total loss.
costBasis covers every open lot, priced or not, whose cost converts into the portfolio's currency. marketValue and the unrealized figures cover only the priced ones, and unvaluedPositionCount is what tells you the totals cover part of the portfolio rather than all of it. A position with no official rate into the portfolio's currency is never converted at a guessed one: its converted* fields are null, conversionUnavailableReason says why, and unconvertedPositionCount (or unconvertedClosedLotCount for realized results) counts what the totals leave out. coverageNote is set when a bound stopped a pass from pricing everything.
A portfolio can also watch instruments it does not hold. A watched instrument appears in the valuation's watching array with a mark from the same price lanes and nothing else: no quantity, cost or value fields exist on a watch row, and it is never part of costBasis, marketValue or any gain figure. Watching an instrument you then buy shows one row, not two: the held position appears in positions carrying its watchId, and watching lists only what is not held. A portfolio watches at most 200 instruments.
Percentages are plain numbers: 57.9335 means 57.9335%.
GET /v1/portfolios
Your portfolios and how many lots each holds. Deliberately unpriced: valuing every portfolio to render a list would fan out to the market data for each one.
Parameters: none.
curl "https://api.equibles.com/v1/portfolios" \
-H "Authorization: Bearer eq_your_api_key"import requests
r = requests.get(
"https://api.equibles.com/v1/portfolios",
headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.json())const res = await fetch("https://api.equibles.com/v1/portfolios", {
headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(await res.json());{
"data": [
{
"id": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
"name": "Main",
"currency": "USD",
"openLotCount": 2,
"closedLotCount": 1,
"createdAtUtc": "2026-02-11T09:14:22Z",
"access": "Owner"
},
{
"id": "2d5e0c41-8b77-4a19-93cc-1f6e4a2b8d90",
"name": "Retirement",
"currency": "USD",
"openLotCount": 5,
"closedLotCount": 0,
"createdAtUtc": "2026-05-30T18:03:41Z",
"access": "Owner"
}
]
}
GET /v1/portfolios/shared
Portfolios colleagues shared with your organization, with who shared each and what you may do with it: Edit lets you add, change, close and remove lots and watches, View only reads. Unpriced like your own list; fetch one by id to have it valued. Empty unless your account holds a seat in an organization or the key is an organization key; when the organization requires company sign-in, link it once from the Portal first.
Parameters: none.
curl "https://api.equibles.com/v1/portfolios/shared" \
-H "Authorization: Bearer eq_your_api_key"import requests
r = requests.get(
"https://api.equibles.com/v1/portfolios/shared",
headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.json())const res = await fetch("https://api.equibles.com/v1/portfolios/shared", {
headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(await res.json());{
"data": [
{
"id": "9a3e57c1-0b42-4d8e-a6f5-2c71d9e04b63",
"name": "Semis basket",
"currency": "USD",
"openLotCount": 6,
"closedLotCount": 2,
"createdAtUtc": "2026-04-02T13:20:05Z",
"access": "Edit",
"sharedBy": "Jane Doe"
}
]
}
POST /v1/portfolios
Creates an empty portfolio and returns 201. The name must be unique among your own and is how the MCP tools address it. A duplicate name, or an eleventh portfolio, returns 400 invalid_parameter naming the reason.
Body: name (required, up to 128 characters); currency (optional ISO code the totals are reported in, USD by default).
curl -X POST "https://api.equibles.com/v1/portfolios" \
-H "Authorization: Bearer eq_your_api_key" \
-H "Content-Type: application/json" \
-d '{"name": "Main"}'import requests
r = requests.post(
"https://api.equibles.com/v1/portfolios",
headers={"Authorization": "Bearer eq_your_api_key"},
json={"name": "Main"},
)
print(r.json())const res = await fetch("https://api.equibles.com/v1/portfolios", {
method: "POST",
headers: {
Authorization: "Bearer eq_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({ name: "Main" }),
});
console.log(await res.json());{
"id": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
"name": "Main",
"currency": "USD",
"openLotCount": 0,
"closedLotCount": 0,
"createdAtUtc": "2026-02-11T09:14:22Z",
"access": "Owner"
}
GET /v1/portfolios/
One portfolio, priced. Open lots are rolled up into a position per instrument, each carrying its own lots; instruments watched but not held come in watching with marks only; closed lots are listed separately with their realized result.
A portfolio shared with you carries sharedBy, and access says whether you may change it.
Parameters: {id} (path), a portfolio id from your list or the shared list.
curl "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77" \
-H "Authorization: Bearer eq_your_api_key"import requests
r = requests.get(
"https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.json())const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77", {
headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(await res.json());{
"id": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
"name": "Main",
"access": "Owner",
"asOfUtc": "2026-08-18T17:42:09Z",
"currency": "USD",
"conversionRates": [],
"costBasis": 7220.000,
"marketValue": 11402.800,
"unrealizedGain": 4182.800,
"unrealizedGainPercent": 57.9335,
"realizedGain": 1043.250,
"unconvertedClosedLotCount": 0,
"unvaluedPositionCount": 0,
"unconvertedPositionCount": 0,
"coverageNote": null,
"positions": [
{
"instrumentKind": "Stock",
"ticker": "NVDA",
"exchange": null,
"name": "Nvidia Corp",
"occTicker": null,
"expirationDate": null,
"strikePrice": null,
"contractType": null,
"sharesPerContract": null,
"quantity": 40.0,
"currency": "USD",
"costBasis": 4740.000,
"averageCostPerUnit": 118.50,
"markPerUnit": 176.32,
"markSource": "LiveQuote",
"markAsOf": "2026-08-18",
"markUnavailableReason": null,
"marketValue": 7052.800,
"unrealizedGain": 2312.800,
"unrealizedGainPercent": 48.7932,
"expired": false,
"convertedCostBasis": 4740.000,
"convertedMarketValue": 7052.800,
"convertedUnrealizedGain": 2312.800,
"convertedUnrealizedGainPercent": 48.7932,
"conversionUnavailableReason": null,
"lots": [
{
"id": "a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411",
"instrumentKind": "Stock",
"ticker": "NVDA",
"exchange": null,
"name": "Nvidia Corp",
"occTicker": null,
"expirationDate": null,
"strikePrice": null,
"contractType": null,
"sharesPerContract": null,
"quantity": 40.0,
"costPerUnit": 118.50,
"costBasis": 4740.000,
"currency": "USD",
"purchaseFxRate": null,
"purchaseFxCurrency": null,
"acquiredDate": "2025-09-02",
"note": "core position",
"closedDate": null,
"closePricePerUnit": null,
"marketValue": 7052.800,
"unrealizedGain": 2312.800,
"realizedGain": null,
"convertedCostBasis": 4740.000,
"convertedMarketValue": 7052.800,
"convertedUnrealizedGain": 2312.800,
"convertedRealizedGain": null,
"purchaseRate": {
"from": "USD",
"to": "USD",
"rate": 1.0,
"asOf": null
},
"closeRate": null,
"isOpen": true
}
]
},
{
"instrumentKind": "Option",
"ticker": "NVDA",
"exchange": null,
"name": "Nvidia Corp",
"occTicker": "O:NVDA270115C00200000",
"expirationDate": "2027-01-15",
"strikePrice": 200.0,
"contractType": "Call",
"sharesPerContract": 100,
"quantity": 2.0,
"currency": "USD",
"costBasis": 2480.000,
"averageCostPerUnit": 12.40,
"markPerUnit": 21.75,
"markSource": "OptionDailyClose",
"markAsOf": "2026-08-17",
"markUnavailableReason": null,
"marketValue": 4350.000,
"unrealizedGain": 1870.000,
"unrealizedGainPercent": 75.4032,
"expired": false,
"convertedCostBasis": 2480.000,
"convertedMarketValue": 4350.000,
"convertedUnrealizedGain": 1870.000,
"convertedUnrealizedGainPercent": 75.4032,
"conversionUnavailableReason": null,
"lots": [
{
"id": "b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22",
"instrumentKind": "Option",
"ticker": "NVDA",
"exchange": null,
"name": "Nvidia Corp",
"occTicker": "O:NVDA270115C00200000",
"expirationDate": "2027-01-15",
"strikePrice": 200.0,
"contractType": "Call",
"sharesPerContract": 100,
"quantity": 2.0,
"costPerUnit": 12.40,
"costBasis": 2480.000,
"currency": "USD",
"purchaseFxRate": null,
"purchaseFxCurrency": null,
"acquiredDate": "2026-03-17",
"note": null,
"closedDate": null,
"closePricePerUnit": null,
"marketValue": 4350.000,
"unrealizedGain": 1870.000,
"realizedGain": null,
"convertedCostBasis": 2480.000,
"convertedMarketValue": 4350.000,
"convertedUnrealizedGain": 1870.000,
"convertedRealizedGain": null,
"purchaseRate": {
"from": "USD",
"to": "USD",
"rate": 1.0,
"asOf": null
},
"closeRate": null,
"isOpen": true
}
]
}
],
"watching": [
{
"id": "d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34",
"instrumentKind": "Stock",
"ticker": "AMD",
"exchange": null,
"name": "Advanced Micro Devices Inc",
"occTicker": null,
"expirationDate": null,
"strikePrice": null,
"contractType": null,
"sharesPerContract": null,
"currency": "USD",
"markPerUnit": 172.94,
"markSource": "SettledClose",
"markAsOf": "2026-08-17",
"markUnavailableReason": null,
"expired": false
},
{
"id": "f8a2c655-1e09-4b7d-a3c8-40d61b9e2a17",
"instrumentKind": "Option",
"ticker": "AMD",
"exchange": null,
"name": "Advanced Micro Devices Inc",
"occTicker": "O:AMD270115C00200000",
"expirationDate": "2027-01-15",
"strikePrice": 200.0,
"contractType": "Call",
"sharesPerContract": 100,
"currency": "USD",
"markPerUnit": 14.85,
"markSource": "OptionDailyClose",
"markAsOf": "2026-08-17",
"markUnavailableReason": null,
"expired": false
}
],
"closedLots": [
{
"id": "c92b6f37-5e18-4c74-a0d5-71e93b6a4f08",
"instrumentKind": "Stock",
"ticker": "MSFT",
"exchange": null,
"name": "Microsoft Corp",
"occTicker": null,
"expirationDate": null,
"strikePrice": null,
"contractType": null,
"sharesPerContract": null,
"quantity": 15.0,
"costPerUnit": 402.10,
"costBasis": 6031.500,
"currency": "USD",
"purchaseFxRate": null,
"purchaseFxCurrency": null,
"acquiredDate": "2025-11-04",
"note": null,
"closedDate": "2026-06-26",
"closePricePerUnit": 471.65,
"marketValue": null,
"unrealizedGain": null,
"realizedGain": 1043.250,
"convertedCostBasis": 6031.500,
"convertedMarketValue": null,
"convertedUnrealizedGain": null,
"convertedRealizedGain": 1043.250,
"purchaseRate": {
"from": "USD",
"to": "USD",
"rate": 1.0,
"asOf": null
},
"closeRate": {
"from": "USD",
"to": "USD",
"rate": 1.0,
"asOf": null
},
"isOpen": false
}
]
}
POST /v1/portfolios/
Records one purchase or sale and returns 201 with the stored lot.
Retrying is safe. An identical request within a few minutes returns the lot that already landed, with "deduplicated": true and HTTP 200 instead of 201, so a retried timeout never leaves you holding the position twice.
Body: ticker (required; MIC:TICKER for another exchange, e.g. XPAR:AIR; for an option, the U.S. underlying), quantity (required, signed), costPerUnit (required, positive), acquiredDate (required, YYYY-MM-DD, not in the future), optionContract (optional OCC symbol), note (optional, up to 256 characters), fxRate (optional broker exchange rate for a lot in another currency than the portfolio's: the portfolio's currency per 1 unit of the lot's; omitted, the official rate on acquiredDate applies).
curl -X POST "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots" \
-H "Authorization: Bearer eq_your_api_key" \
-H "Content-Type: application/json" \
-d '{"ticker": "NVDA", "optionContract": "O:NVDA270115C00200000", "quantity": 2, "costPerUnit": 12.40, "acquiredDate": "2026-03-17"}'import requests
r = requests.post(
"https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots",
headers={"Authorization": "Bearer eq_your_api_key"},
json={
"ticker": "NVDA",
"optionContract": "O:NVDA270115C00200000",
"quantity": 2,
"costPerUnit": 12.40,
"acquiredDate": "2026-03-17",
},
)
print(r.json())const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots", {
method: "POST",
headers: {
Authorization: "Bearer eq_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({
ticker: "NVDA",
optionContract: "O:NVDA270115C00200000",
quantity: 2,
costPerUnit: 12.4,
acquiredDate: "2026-03-17",
}),
});
console.log(await res.json());{
"portfolioId": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
"portfolioName": "Main",
"deduplicated": false,
"lot": {
"id": "b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22",
"instrumentKind": "Option",
"ticker": "NVDA",
"exchange": null,
"name": "Nvidia Corp",
"occTicker": "O:NVDA270115C00200000",
"expirationDate": "2027-01-15",
"strikePrice": 200.0,
"contractType": "Call",
"sharesPerContract": 100,
"quantity": 2.0,
"costPerUnit": 12.40,
"costBasis": 2480.00,
"currency": "USD",
"purchaseFxRate": null,
"purchaseFxCurrency": null,
"acquiredDate": "2026-03-17",
"note": null,
"closedDate": null,
"closePricePerUnit": null,
"marketValue": null,
"unrealizedGain": null,
"realizedGain": null,
"convertedCostBasis": null,
"convertedMarketValue": null,
"convertedUnrealizedGain": null,
"convertedRealizedGain": null,
"purchaseRate": null,
"closeRate": null,
"isOpen": true
}
}
A lot returned by a write is unpriced: marketValue and unrealizedGain are null because a write answers about what was recorded, not what it is worth. Fetch the portfolio to have it valued.
PATCH /v1/portfolios/
Corrects a lot that was entered wrong. Only the fields you send change.
The instrument itself cannot be edited: a lot on the wrong stock or the wrong contract is a different holding, so delete it and add the right one.
Body: any of quantity, costPerUnit, acquiredDate, note, fxRate, clearFxRate. Send "note": "" to clear a note, and "clearFxRate": true to remove a broker rate so the lot converts at the official rate on its trade date.
curl -X PATCH "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411" \
-H "Authorization: Bearer eq_your_api_key" \
-H "Content-Type: application/json" \
-d '{"costPerUnit": 118.50, "note": "core position"}'import requests
r = requests.patch(
"https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411",
headers={"Authorization": "Bearer eq_your_api_key"},
json={"costPerUnit": 118.50, "note": "core position"},
)
print(r.json())const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411", {
method: "PATCH",
headers: {
Authorization: "Bearer eq_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({ costPerUnit: 118.5, note: "core position" }),
});
console.log(await res.json());{
"portfolioId": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
"portfolioName": "Main",
"deduplicated": false,
"lot": {
"id": "a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411",
"instrumentKind": "Stock",
"ticker": "NVDA",
"exchange": null,
"name": "Nvidia Corp",
"occTicker": null,
"expirationDate": null,
"strikePrice": null,
"contractType": null,
"sharesPerContract": null,
"quantity": 40.0,
"costPerUnit": 118.50,
"costBasis": 4740.00,
"currency": "USD",
"purchaseFxRate": null,
"purchaseFxCurrency": null,
"acquiredDate": "2025-09-02",
"note": "core position",
"closedDate": null,
"closePricePerUnit": null,
"marketValue": null,
"unrealizedGain": null,
"realizedGain": null,
"convertedCostBasis": null,
"convertedMarketValue": null,
"convertedUnrealizedGain": null,
"convertedRealizedGain": null,
"purchaseRate": null,
"closeRate": null,
"isOpen": true
}
}
POST /v1/portfolios/
Records a sale. Omit quantity to close the whole lot, or pass less to close part of it. A partial close splits the lot, so the returned closed lot carries its own id and the remainder stays open on the original cost basis.
Body: closePricePerUnit (required, positive), closeDate (required, YYYY-MM-DD, not before the lot was acquired), quantity (optional, unsigned).
curl -X POST "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411/close" \
-H "Authorization: Bearer eq_your_api_key" \
-H "Content-Type: application/json" \
-d '{"closePricePerUnit": 471.65, "closeDate": "2026-06-26"}'import requests
r = requests.post(
"https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411/close",
headers={"Authorization": "Bearer eq_your_api_key"},
json={"closePricePerUnit": 471.65, "closeDate": "2026-06-26"},
)
print(r.json())const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/a3f1c204-9d6e-4a58-8b12-0f7c2d9e5411/close", {
method: "POST",
headers: {
Authorization: "Bearer eq_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({ closePricePerUnit: 471.65, closeDate: "2026-06-26" }),
});
console.log(await res.json());{
"portfolioId": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
"portfolioName": "Main",
"deduplicated": false,
"lot": {
"id": "c92b6f37-5e18-4c74-a0d5-71e93b6a4f08",
"instrumentKind": "Stock",
"ticker": "MSFT",
"exchange": null,
"name": "Microsoft Corp",
"occTicker": null,
"expirationDate": null,
"strikePrice": null,
"contractType": null,
"sharesPerContract": null,
"quantity": 15.0,
"costPerUnit": 402.10,
"costBasis": 6031.50,
"currency": "USD",
"purchaseFxRate": null,
"purchaseFxCurrency": null,
"acquiredDate": "2025-11-04",
"note": null,
"closedDate": "2026-06-26",
"closePricePerUnit": 471.65,
"marketValue": null,
"unrealizedGain": null,
"realizedGain": 1043.25,
"convertedCostBasis": null,
"convertedMarketValue": null,
"convertedUnrealizedGain": null,
"convertedRealizedGain": null,
"purchaseRate": null,
"closeRate": null,
"isOpen": false
}
}
DELETE /v1/portfolios/
Removes a lot as though it had never been recorded, for something entered by mistake. A sale is recorded by closing the lot instead, which keeps its realized profit and loss. Returns 204 with no body, and cannot be undone.
curl -X DELETE "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22" \
-H "Authorization: Bearer eq_your_api_key"import requests
r = requests.delete(
"https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22",
headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.status_code)const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/lots/b7c48e19-2a05-4de3-91f6-3d8a5c1b7e22", {
method: "DELETE",
headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(res.status);POST /v1/portfolios/
Puts an instrument on the portfolio's watchlist without recording any position, and returns 201 with the stored watch row. Pass optionContract with the OCC symbol to watch an option, or omit it to watch the stock. The instrument is verified against the live reference data before anything is stored, exactly like a lot's, so an unknown ticker or contract is rejected rather than saved. Watching an instrument the portfolio already watches returns 400 invalid_parameter saying so.
The write answers with identity only; the mark fields fill in on the priced GET, which lists the row in watching.
Body: ticker (required; MIC:TICKER for another exchange; for an option, the underlying's ticker), optionContract (optional OCC symbol).
curl -X POST "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches" \
-H "Authorization: Bearer eq_your_api_key" \
-H "Content-Type: application/json" \
-d '{"ticker": "AMD"}'import requests
r = requests.post(
"https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches",
headers={"Authorization": "Bearer eq_your_api_key"},
json={"ticker": "AMD"},
)
print(r.json())const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches", {
method: "POST",
headers: {
Authorization: "Bearer eq_your_api_key",
"Content-Type": "application/json",
},
body: JSON.stringify({ ticker: "AMD" }),
});
console.log(await res.json());{
"portfolioId": "6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
"portfolioName": "Main",
"watch": {
"id": "d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34",
"instrumentKind": "Stock",
"ticker": "AMD",
"exchange": null,
"name": "Advanced Micro Devices Inc",
"occTicker": null,
"expirationDate": null,
"strikePrice": null,
"contractType": null,
"sharesPerContract": null,
"currency": null,
"markPerUnit": null,
"markSource": null,
"markAsOf": null,
"markUnavailableReason": null,
"expired": false
}
}
To watch an option instead, name the contract alongside its underlying, the same pair the lot endpoint takes: {"ticker": "AMD", "optionContract": "O:AMD270115C00200000"}. A contract with no published contract size is still watchable — a watch row has no economics for the multiplier to compute — though it could not be held as a lot.
DELETE /v1/portfolios/
Stops watching an instrument. Removes only the watch row — any lots on the same instrument are untouched. Returns 204 with no body. The {watchId} comes from the valuation's watching array, or from the answer to the POST above.
curl -X DELETE "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches/d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34" \
-H "Authorization: Bearer eq_your_api_key"import requests
r = requests.delete(
"https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches/d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34",
headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.status_code)const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77/watches/d4b90f21-7c3a-4e8f-b6a1-92e5c7d80f34", {
method: "DELETE",
headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(res.status);DELETE /v1/portfolios/
Deletes a portfolio and every lot in it, including the closed ones and their realized history. Returns 204 with no body, and cannot be undone. Only the portfolio's creator can delete it; a portfolio shared with you returns 403.
curl -X DELETE "https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77" \
-H "Authorization: Bearer eq_your_api_key"import requests
r = requests.delete(
"https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77",
headers={"Authorization": "Bearer eq_your_api_key"},
)
print(r.status_code)const res = await fetch("https://api.equibles.com/v1/portfolios/6f1d2a80-4f3c-4b6a-9a21-6c0b8f4d1e77", {
method: "DELETE",
headers: { Authorization: "Bearer eq_your_api_key" },
});
console.log(res.status);Privacy
A portfolio is yours. It is stored against your account, it is never used to build market data or any public dataset, and no other account sees it unless you share it with your organization, and then only that organization's members. Deleting a portfolio deletes its lots with it.