curl --request POST \
--url https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--header 'x-request-id: <x-request-id>' \
--header 'x-user-key: <api-key>' \
--data '
{
"conversionMode": "eToroApp",
"pnlLevel": "pnl",
"accountLevel": "totals",
"instrumentLevel": "details",
"mirrorLevel": "details",
"instrumentIds": [
1001
],
"mirrorFilters": [
{
"mirrorId": 0,
"instrumentMode": "custom",
"instrumentIds": [
1001
]
},
{
"mirrorId": 123,
"instrumentMode": "all"
}
]
}
'import requests
url = "https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio"
payload = {
"conversionMode": "eToroApp",
"pnlLevel": "pnl",
"accountLevel": "totals",
"instrumentLevel": "details",
"mirrorLevel": "details",
"instrumentIds": [1001],
"mirrorFilters": [
{
"mirrorId": 0,
"instrumentMode": "custom",
"instrumentIds": [1001]
},
{
"mirrorId": 123,
"instrumentMode": "all"
}
]
}
headers = {
"x-request-id": "<x-request-id>",
"x-api-key": "<api-key>",
"x-user-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-request-id': '<x-request-id>',
'x-api-key': '<api-key>',
'x-user-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
conversionMode: 'eToroApp',
pnlLevel: 'pnl',
accountLevel: 'totals',
instrumentLevel: 'details',
mirrorLevel: 'details',
instrumentIds: [1001],
mirrorFilters: [
{mirrorId: 0, instrumentMode: 'custom', instrumentIds: [1001]},
{mirrorId: 123, instrumentMode: 'all'}
]
})
};
fetch('https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'conversionMode' => 'eToroApp',
'pnlLevel' => 'pnl',
'accountLevel' => 'totals',
'instrumentLevel' => 'details',
'mirrorLevel' => 'details',
'instrumentIds' => [
1001
],
'mirrorFilters' => [
[
'mirrorId' => 0,
'instrumentMode' => 'custom',
'instrumentIds' => [
1001
]
],
[
'mirrorId' => 123,
'instrumentMode' => 'all'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>",
"x-request-id: <x-request-id>",
"x-user-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio"
payload := strings.NewReader("{\n \"conversionMode\": \"eToroApp\",\n \"pnlLevel\": \"pnl\",\n \"accountLevel\": \"totals\",\n \"instrumentLevel\": \"details\",\n \"mirrorLevel\": \"details\",\n \"instrumentIds\": [\n 1001\n ],\n \"mirrorFilters\": [\n {\n \"mirrorId\": 0,\n \"instrumentMode\": \"custom\",\n \"instrumentIds\": [\n 1001\n ]\n },\n {\n \"mirrorId\": 123,\n \"instrumentMode\": \"all\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-request-id", "<x-request-id>")
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("x-user-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio")
.header("x-request-id", "<x-request-id>")
.header("x-api-key", "<api-key>")
.header("x-user-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"conversionMode\": \"eToroApp\",\n \"pnlLevel\": \"pnl\",\n \"accountLevel\": \"totals\",\n \"instrumentLevel\": \"details\",\n \"mirrorLevel\": \"details\",\n \"instrumentIds\": [\n 1001\n ],\n \"mirrorFilters\": [\n {\n \"mirrorId\": 0,\n \"instrumentMode\": \"custom\",\n \"instrumentIds\": [\n 1001\n ]\n },\n {\n \"mirrorId\": 123,\n \"instrumentMode\": \"all\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-request-id"] = '<x-request-id>'
request["x-api-key"] = '<api-key>'
request["x-user-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"conversionMode\": \"eToroApp\",\n \"pnlLevel\": \"pnl\",\n \"accountLevel\": \"totals\",\n \"instrumentLevel\": \"details\",\n \"mirrorLevel\": \"details\",\n \"instrumentIds\": [\n 1001\n ],\n \"mirrorFilters\": [\n {\n \"mirrorId\": 0,\n \"instrumentMode\": \"custom\",\n \"instrumentIds\": [\n 1001\n ]\n },\n {\n \"mirrorId\": 123,\n \"instrumentMode\": \"all\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"cid": 123,
"timestamp": "2023-11-07T05:31:56Z",
"accountCurrency": "<string>",
"accountTotals": {
"accountAvailableCash": 123,
"accountFrozenCash": 123,
"accountCurrentPnl": 123,
"accountTotalValue": 123,
"accountTotalUsedMargin": 123,
"accountBalance": 123,
"dailyGainAccountCurrency": -24.57,
"yesterdayTotalValue": 5179.05,
"dailyGainAccountCurrencyPercent": -0.47
},
"instrumentAggregates": [
{
"instrumentId": 123,
"assetCurrency": "<string>",
"totalMarginAccountCurrency": 123,
"totalFees": 123,
"totalFeesAcctCcy": 123,
"totalTaxes": 123,
"totalTaxesAcctCcy": 123,
"totalMarginAssetCurrency": 123,
"pnlAssetCurrency": 123,
"accountCurrencyRoePercent": 123,
"netContracts": 123,
"netUnits": 123,
"netCurrentExposureAssetCurrency": 123,
"netCurrentExposureAccountCurrency": 123,
"netInitialExposureAccountCurrency": 123,
"accountCurrencyReturn": 123,
"liquidationValueAccountCurrency": 123,
"liquidationValueAssetCurrency": 123,
"avgLeverage": 123,
"avgOpenRate": 123,
"netAvgOpenRate": 123,
"avgConversionRate": 123,
"dailyGainAssetCurrency": -18.42,
"dailyGainAccountCurrency": -18.42
}
],
"mirrors": [
{
"mirrorId": 123,
"mirrorAvailableCash": 123,
"mirrorDepositTotal": 123,
"mirrorWithdrawalTotal": 123,
"mirrorStopLossPercentage": 123,
"mirrorStopLoss": 123,
"mirrorClosedPositionsPnl": 123,
"mirrorTotals": {
"mirrorNetFunding": 123,
"mirrorPositionsPnl": 123,
"mirrorLiquidationValue": 123,
"mirrorPositionsPnlPercent": 123,
"mirrorMarginPercent": 123,
"mirrorValuePercent": 123,
"mirrorActiveMargin": 123,
"mirrorDailyGainAccountCurrency": -6.15
},
"instrumentAggregates": [
{
"instrumentId": 123,
"assetCurrency": "<string>",
"totalMarginAccountCurrency": 123,
"totalFees": 123,
"totalFeesAcctCcy": 123,
"totalTaxes": 123,
"totalTaxesAcctCcy": 123,
"totalMarginAssetCurrency": 123,
"pnlAssetCurrency": 123,
"accountCurrencyRoePercent": 123,
"netContracts": 123,
"netUnits": 123,
"netCurrentExposureAssetCurrency": 123,
"netCurrentExposureAccountCurrency": 123,
"netInitialExposureAccountCurrency": 123,
"accountCurrencyReturn": 123,
"liquidationValueAccountCurrency": 123,
"liquidationValueAssetCurrency": 123,
"avgLeverage": 123,
"avgOpenRate": 123,
"netAvgOpenRate": 123,
"avgConversionRate": 123,
"dailyGainAssetCurrency": -18.42,
"dailyGainAccountCurrency": -18.42
}
]
}
]
}Get a filtered aggregated portfolio snapshot
Rate limit: 60 requests per 60 seconds. This is a shared quota — the same budget is consumed by a group of related endpoints, so calling any of them reduces what is left for the others (you cannot call each at the full rate independently). Endpoints sharing this quota:
GET /api/v1/trading/info/demo/aggregate-portfolio
Returns the demo portfolio using aggregation levels and structured per-mirror instrument filters from the request body. This filter does not affect the account totals, that are still calculated based on the full portfolio.
curl --request POST \
--url https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--header 'x-request-id: <x-request-id>' \
--header 'x-user-key: <api-key>' \
--data '
{
"conversionMode": "eToroApp",
"pnlLevel": "pnl",
"accountLevel": "totals",
"instrumentLevel": "details",
"mirrorLevel": "details",
"instrumentIds": [
1001
],
"mirrorFilters": [
{
"mirrorId": 0,
"instrumentMode": "custom",
"instrumentIds": [
1001
]
},
{
"mirrorId": 123,
"instrumentMode": "all"
}
]
}
'import requests
url = "https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio"
payload = {
"conversionMode": "eToroApp",
"pnlLevel": "pnl",
"accountLevel": "totals",
"instrumentLevel": "details",
"mirrorLevel": "details",
"instrumentIds": [1001],
"mirrorFilters": [
{
"mirrorId": 0,
"instrumentMode": "custom",
"instrumentIds": [1001]
},
{
"mirrorId": 123,
"instrumentMode": "all"
}
]
}
headers = {
"x-request-id": "<x-request-id>",
"x-api-key": "<api-key>",
"x-user-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {
'x-request-id': '<x-request-id>',
'x-api-key': '<api-key>',
'x-user-key': '<api-key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
conversionMode: 'eToroApp',
pnlLevel: 'pnl',
accountLevel: 'totals',
instrumentLevel: 'details',
mirrorLevel: 'details',
instrumentIds: [1001],
mirrorFilters: [
{mirrorId: 0, instrumentMode: 'custom', instrumentIds: [1001]},
{mirrorId: 123, instrumentMode: 'all'}
]
})
};
fetch('https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'conversionMode' => 'eToroApp',
'pnlLevel' => 'pnl',
'accountLevel' => 'totals',
'instrumentLevel' => 'details',
'mirrorLevel' => 'details',
'instrumentIds' => [
1001
],
'mirrorFilters' => [
[
'mirrorId' => 0,
'instrumentMode' => 'custom',
'instrumentIds' => [
1001
]
],
[
'mirrorId' => 123,
'instrumentMode' => 'all'
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>",
"x-request-id: <x-request-id>",
"x-user-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio"
payload := strings.NewReader("{\n \"conversionMode\": \"eToroApp\",\n \"pnlLevel\": \"pnl\",\n \"accountLevel\": \"totals\",\n \"instrumentLevel\": \"details\",\n \"mirrorLevel\": \"details\",\n \"instrumentIds\": [\n 1001\n ],\n \"mirrorFilters\": [\n {\n \"mirrorId\": 0,\n \"instrumentMode\": \"custom\",\n \"instrumentIds\": [\n 1001\n ]\n },\n {\n \"mirrorId\": 123,\n \"instrumentMode\": \"all\"\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-request-id", "<x-request-id>")
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("x-user-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio")
.header("x-request-id", "<x-request-id>")
.header("x-api-key", "<api-key>")
.header("x-user-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"conversionMode\": \"eToroApp\",\n \"pnlLevel\": \"pnl\",\n \"accountLevel\": \"totals\",\n \"instrumentLevel\": \"details\",\n \"mirrorLevel\": \"details\",\n \"instrumentIds\": [\n 1001\n ],\n \"mirrorFilters\": [\n {\n \"mirrorId\": 0,\n \"instrumentMode\": \"custom\",\n \"instrumentIds\": [\n 1001\n ]\n },\n {\n \"mirrorId\": 123,\n \"instrumentMode\": \"all\"\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://public-api.etoro.com/api/v1/trading/info/demo/aggregate-portfolio")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-request-id"] = '<x-request-id>'
request["x-api-key"] = '<api-key>'
request["x-user-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"conversionMode\": \"eToroApp\",\n \"pnlLevel\": \"pnl\",\n \"accountLevel\": \"totals\",\n \"instrumentLevel\": \"details\",\n \"mirrorLevel\": \"details\",\n \"instrumentIds\": [\n 1001\n ],\n \"mirrorFilters\": [\n {\n \"mirrorId\": 0,\n \"instrumentMode\": \"custom\",\n \"instrumentIds\": [\n 1001\n ]\n },\n {\n \"mirrorId\": 123,\n \"instrumentMode\": \"all\"\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"cid": 123,
"timestamp": "2023-11-07T05:31:56Z",
"accountCurrency": "<string>",
"accountTotals": {
"accountAvailableCash": 123,
"accountFrozenCash": 123,
"accountCurrentPnl": 123,
"accountTotalValue": 123,
"accountTotalUsedMargin": 123,
"accountBalance": 123,
"dailyGainAccountCurrency": -24.57,
"yesterdayTotalValue": 5179.05,
"dailyGainAccountCurrencyPercent": -0.47
},
"instrumentAggregates": [
{
"instrumentId": 123,
"assetCurrency": "<string>",
"totalMarginAccountCurrency": 123,
"totalFees": 123,
"totalFeesAcctCcy": 123,
"totalTaxes": 123,
"totalTaxesAcctCcy": 123,
"totalMarginAssetCurrency": 123,
"pnlAssetCurrency": 123,
"accountCurrencyRoePercent": 123,
"netContracts": 123,
"netUnits": 123,
"netCurrentExposureAssetCurrency": 123,
"netCurrentExposureAccountCurrency": 123,
"netInitialExposureAccountCurrency": 123,
"accountCurrencyReturn": 123,
"liquidationValueAccountCurrency": 123,
"liquidationValueAssetCurrency": 123,
"avgLeverage": 123,
"avgOpenRate": 123,
"netAvgOpenRate": 123,
"avgConversionRate": 123,
"dailyGainAssetCurrency": -18.42,
"dailyGainAccountCurrency": -18.42
}
],
"mirrors": [
{
"mirrorId": 123,
"mirrorAvailableCash": 123,
"mirrorDepositTotal": 123,
"mirrorWithdrawalTotal": 123,
"mirrorStopLossPercentage": 123,
"mirrorStopLoss": 123,
"mirrorClosedPositionsPnl": 123,
"mirrorTotals": {
"mirrorNetFunding": 123,
"mirrorPositionsPnl": 123,
"mirrorLiquidationValue": 123,
"mirrorPositionsPnlPercent": 123,
"mirrorMarginPercent": 123,
"mirrorValuePercent": 123,
"mirrorActiveMargin": 123,
"mirrorDailyGainAccountCurrency": -6.15
},
"instrumentAggregates": [
{
"instrumentId": 123,
"assetCurrency": "<string>",
"totalMarginAccountCurrency": 123,
"totalFees": 123,
"totalFeesAcctCcy": 123,
"totalTaxes": 123,
"totalTaxesAcctCcy": 123,
"totalMarginAssetCurrency": 123,
"pnlAssetCurrency": 123,
"accountCurrencyRoePercent": 123,
"netContracts": 123,
"netUnits": 123,
"netCurrentExposureAssetCurrency": 123,
"netCurrentExposureAccountCurrency": 123,
"netInitialExposureAccountCurrency": 123,
"accountCurrencyReturn": 123,
"liquidationValueAccountCurrency": 123,
"liquidationValueAssetCurrency": 123,
"avgLeverage": 123,
"avgOpenRate": 123,
"netAvgOpenRate": 123,
"avgConversionRate": 123,
"dailyGainAssetCurrency": -18.42,
"dailyGainAccountCurrency": -18.42
}
]
}
]
}Authorizations
API key of the application. Only valid together with the x-user-key header — the pair is an alternative to OAuth bearer authentication, never sent alongside it. The pair is granted the same permissions the operation's OAuth scopes describe.
Demo credential for trying the API from these docs: lhgfaslk21490FAScVPkdsb53F9dNkfHG4faZSG5vfjndfcfgdssdgsdHF4663
User-specific authentication key. Only valid together with the x-api-key header — the pair is an alternative to OAuth bearer authentication, never sent alongside it.
Demo credential for trying the API from these docs: eyJlYW4iOiJVbnJlZ2lzdGVyZWRBcHBsaWNhdGlvbiIsImVrIjoiOE5sZ2cwcW5EUVdROUFNWGpXT2lmOWktZnpidG5KcUlqWGJ3WHJZZkpZcldrbG90ZEhvLVBjSWhQaU8xU1ZtMW84aU1WZGZqN2xWNzFjLXFxLmcybXE1dnh4Q1hUT25xaWRUaTFlcEhmVk1fIn0_
Headers
A unique request identifier.
"f0bfaf25-1252-4a64-b06d-8ab77ceb5202"
Body
All aggregation levels are honored. Omitted properties use the same defaults as GET.
eToroApp, realtime none, pnl, dailyPnl Controls accountTotals. none omits it; totals and details include full-portfolio totals.
none, totals, details Controls per-instrument aggregates for both the manual (non copy-trading) portfolio and each mirror's positions — a single request-level setting, not scoped per mirror. none omits instrument-level aggregates; totals and details include them at the requested level.
none, totals, details Controls copy-trading data. none omits mirrors and requires mirrorFilters to be absent; totals includes mirrors without their instrument-level aggregates; details additionally includes each mirror's instrument-level aggregates, per instrumentLevel.
none, totals, details Filters which copy-trading relationships to include, by mirror ID. Mirror ID 0 represents the manual (non copy-trading) part of the portfolio. When mirrorLevel is none, mirrorFilters must be absent — only the manual part of the portfolio is returned. When mirrorLevel is totals or details, an absent mirrorFilters returns all mirrors plus the manual part; an empty array returns none.
Show child attributes
Show child attributes
UTC timestamp representing the start of 'today' in the user's local timezone — normally the user's most recent local midnight, expressed in UTC. Required when pnlLevel is dailyPnl; rejected otherwise. Must not be more than 48 hours in the past or more than 5 minutes in the future.
Response
Successfully retrieved aggregated portfolio data
Complete snapshot of the authenticated user's investment portfolio, organized by asset.
Customer ID.
Time at which this portfolio snapshot was calculated.
ISO 4217 code of the account's base currency (e.g. 'USD').
Account-level balance and equity totals.
Show child attributes
Show child attributes
Positions held directly (not via copy trading), grouped by instrument.
Show child attributes
Show child attributes
Copy-trading relationships the user has active.
Show child attributes
Show child attributes