# Create Agent Portfolio (v2) Source: https://api-portal.etoro.com/api-reference/agent-portfolios/create-agent-portfolio-v2 /api-reference/openapi.json post /api/v2/agent-portfolios **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a new agent-portfolio using scope names. Scopes are specified by name (scopeNames); scope ids are not supported in v2. IMPORTANT: investmentAmountInUsd is the amount deducted from YOUR (the caller's) account balance to copy-trade this agent-portfolio — it is NOT the agent-portfolio's own balance. Positions are mirrored proportionally: e.g. if you invest $2,000 and agentPortfolioVirtualBalance is $10,000, each position is copied at 20% of its size into your account. # Create User Token (v2) Source: https://api-portal.etoro.com/api-reference/agent-portfolios/create-user-token-v2 /api-reference/openapi.json post /api/v2/agent-portfolios/{agentPortfolioId}/user-tokens **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a new user token for the specified agent-portfolio using scope names. Scopes are specified by name (scopeNames); scope ids are not supported in v2. # Delete Agent Portfolio Source: https://api-portal.etoro.com/api-reference/agent-portfolios/delete-agent-portfolio /api-reference/openapi.json delete /api/v1/agent-portfolios/{agentPortfolioId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Permanently removes a agent-portfolio by revoking all user tokens, stopping the copy mirror, and deleting from storage. # Delete User Token Source: https://api-portal.etoro.com/api-reference/agent-portfolios/delete-user-token /api-reference/openapi.json delete /api/v1/agent-portfolios/{agentPortfolioId}/user-tokens/{userTokenId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Permanently revokes the specified user token from a agent-portfolio. # Get Agent Portfolios Source: https://api-portal.etoro.com/api-reference/agent-portfolios/get-agent-portfolios /api-reference/openapi.json get /api/v1/agent-portfolios **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves all agent-portfolios belonging to the authenticated user. # Get Allowed Scopes (v2) Source: https://api-portal.etoro.com/api-reference/agent-portfolios/get-allowed-scopes-v2 /api-reference/openapi.json get /api/v2/agent-portfolios/user-tokens/scopes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the permission scope names that may be assigned to agent-portfolio user tokens. # Update User Token (v2) Source: https://api-portal.etoro.com/api-reference/agent-portfolios/update-user-token-v2 /api-reference/openapi.json patch /api/v2/agent-portfolios/{agentPortfolioId}/user-tokens/{userTokenId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Updates the settings of an existing user token using scope names. At least one field must be provided. Scopes are specified by name (scopeNames); scope ids are not supported in v2. # Get application key data Source: https://api-portal.etoro.com/api-reference/app-data/get-application-key-data /api-reference/openapi.json get /api/v1/keydata/{application} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the key/value data configured for the given application. # Get account balance history Source: https://api-portal.etoro.com/api-reference/balances/get-account-balance-history /api-reference/openapi.json get /api/v1/balances/{accountType}/{accountId}/history **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns end-of-day balance snapshots for a specific account identified by type and account ID for the authenticated user. History is available for the last 12 months. The maximum date range per request is 365 days. # Get aggregated balances Source: https://api-portal.etoro.com/api-reference/balances/get-aggregated-balances /api-reference/openapi.json get /api/v1/balances **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns aggregated balances across all account types for the authenticated user. Optionally filter by account type or specify the display currency for totals. Important: totalBalance and displayBalance are portfolio value, not spendable cash. For Trading, Options, MoneyFarm, Spaceship and Plaee they represent total account value including invested positions; for Crypto, the fiat value of holdings. Only for Cash accounts do they equal available cash. Do not use them to decide whether a trade or withdrawal is affordable — request expand=equityDetails and read equityDetails.available (Trading, Options, MoneyFarm, Cash, Plaee) or equityDetails.spendableBalanceInFiat (Crypto). Spaceship accounts expose no spendable figure. Note that equityDetails amounts are denominated in each account's own native currency, not in displayCurrency, so they must be converted before being compared with displayBalance or totalBalance. # Get balance for a specific account Source: https://api-portal.etoro.com/api-reference/balances/get-balance-for-a-specific-account /api-reference/openapi.json get /api/v1/balances/{accountType}/{accountId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the balance for a specific account identified by type and account ID for the authenticated user. Zero-balance accounts are always returned by this endpoint, so a 404 means the account does not exist rather than that its balance is zero. Important: totalBalance and displayBalance are portfolio value, not spendable cash. For Trading, Options, MoneyFarm, Spaceship and Plaee they represent total account value including invested positions; for Crypto, the fiat value of holdings. Only for Cash accounts do they equal available cash. Do not use them to decide whether a trade or withdrawal is affordable — request expand=equityDetails and read equityDetails.available (Trading, Options, MoneyFarm, Cash, Plaee) or equityDetails.spendableBalanceInFiat (Crypto). Spaceship accounts expose no spendable figure. Note that equityDetails amounts are denominated in each account's own native currency, not in displayCurrency, so they must be converted before being compared with displayBalance or totalBalance. # Get balances by account type Source: https://api-portal.etoro.com/api-reference/balances/get-balances-by-account-type /api-reference/openapi.json get /api/v1/balances/{accountType} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns balances for a specific account type for the authenticated user. Optionally filter by account IDs. Important: totalBalance and displayBalance are portfolio value, not spendable cash. For Trading, Options, MoneyFarm, Spaceship and Plaee they represent total account value including invested positions; for Crypto, the fiat value of holdings. Only for Cash accounts do they equal available cash. Do not use them to decide whether a trade or withdrawal is affordable — request expand=equityDetails and read equityDetails.available (Trading, Options, MoneyFarm, Cash, Plaee) or equityDetails.spendableBalanceInFiat (Crypto). Spaceship accounts expose no spendable figure. Note that equityDetails amounts are denominated in each account's own native currency, not in displayCurrency, so they must be converted before being compared with displayBalance or totalBalance. # Get historical balance snapshots Source: https://api-portal.etoro.com/api-reference/balances/get-historical-balance-snapshots /api-reference/openapi.json get /api/v1/balances/history **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns end-of-day balance snapshots across all account types for the authenticated user. History is available for the last 12 months. The maximum date range per request is 365 days. # Get historical balances by account type Source: https://api-portal.etoro.com/api-reference/balances/get-historical-balances-by-account-type /api-reference/openapi.json get /api/v1/balances/{accountType}/history **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns end-of-day balance snapshots for a specific account type for the authenticated user. History is available for the last 12 months. The maximum date range per request is 365 days. # List cash account transactions (paginated) Source: https://api-portal.etoro.com/api-reference/cash-accounts/list-cash-account-transactions-paginated /api-reference/openapi.json get /api/v1/money/accounts/cash/{accountId}/transactions **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a cursor-paginated list of transactions for the given cash account. Use pageSize and pageToken for pagination; nextPageToken is null when there is no next page. # Get club dashboard data Source: https://api-portal.etoro.com/api-reference/clubs/get-club-dashboard-data /api-reference/openapi.json get /api/v1/clubs **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves club dashboard data for the authenticated user, including tier information, benefits, account manager details, offers, downgrade risk, and webinars. # Close or detach a copy relationship Source: https://api-portal.etoro.com/api-reference/copy-trading--demo/close-or-detach-a-copy-relationship /api-reference/openapi.json delete /api/v2/trading/copy/demo **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- This action closes the sub-portfolio of the copy relationship. There are 2 ways to close the sub-portfolio: (a) Close — close all positions and withdraw the funds back to the main portfolio balance; (b) Detach — detach the positions from the sub-portfolio and move them into the main portfolio, and withdraw the sub-portfolio cash balance back into the main portfolio balance. These correspond to the unregisterType values Close and Detach. The relationship is selected by mirrorID; identity is resolved from the authenticated caller. This binding takes all fields as query parameters and rejects any request carrying a body — use POST /api/v2/trading/copy/demo/close for a JSON-body equivalent. The operation is asynchronous and the response token is an acknowledgment only: close completion is not pollable through this API. # Close or detach a copy relationship (JSON body) Source: https://api-portal.etoro.com/api-reference/copy-trading--demo/close-or-detach-a-copy-relationship-json-body /api-reference/openapi.json post /api/v2/trading/copy/demo/close **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- This action closes the sub-portfolio of the copy relationship. There are 2 ways to close the sub-portfolio: (a) Close — close all positions and withdraw the funds back to the main portfolio balance; (b) Detach — detach the positions from the sub-portfolio and move them into the main portfolio, and withdraw the sub-portfolio cash balance back into the main portfolio balance. These correspond to the unregisterType values Close and Detach. Identical semantics to DELETE /api/v2/trading/copy/demo, with the fields carried in a JSON body instead of query parameters — provided because some HTTP clients and proxies handle DELETE requests with bodies unreliably. The response token is an acknowledgment only: close completion is not pollable through this API. # Poll a copy operation's outcome Source: https://api-portal.etoro.com/api-reference/copy-trading--demo/poll-a-copy-operations-outcome /api-reference/openapi.json get /api/v2/trading/copy/demo/{referenceId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the terminal outcome of a copy request for register, add or remove funds, looked up by the referenceID supplied on the copy request. The lookup is case-sensitive and scoped to the authenticated account. On success the response carries the mirrorID used to close the copy later; parentCID and parentUsername are either both present or both absent. This endpoint returns only the status of the copy request, not the status of the mirror sub-portfolio. For sub-portfolio status use a portfolio endpoint. # Pre-check whether a copy registration would be allowed Source: https://api-portal.etoro.com/api-reference/copy-trading--demo/pre-check-whether-a-copy-registration-would-be-allowed /api-reference/openapi.json post /api/v2/trading/copy/demo/eligibility **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- A dry run of the register operation that changes nothing: verifies whether the authenticated account can copy the given investor with the given amount. Request body is the same as starting a new copy (POST /api/v2/trading/copy/demo). A positive verdict is a point-in-time check, not a reservation. When isSuccess is false, errorCode and errorMessage may be absent. # Start copying an investor, or adjust an existing copy Source: https://api-portal.etoro.com/api-reference/copy-trading--demo/start-copying-an-investor-or-adjust-an-existing-copy /api-reference/openapi.json post /api/v2/trading/copy/demo **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Registers a copy relationship with the given investor for the authenticated account. If the copy already exists, funds will be added to or removed from it; if it does not exist, a new copy will be created and funds transferred into it. Every change of funds causes a realignment process that adjusts all the positions inside the sub-portfolio to match the parent portfolio proportions. Investor account ids (parentCID) are the ids surfaced by the platform's public endpoints (for example, the Rankings endpoints). The operation is asynchronous: the response token acknowledges acceptance, and the outcome can be checked via GET /api/v2/trading/copy/demo/{referenceId} using the referenceID supplied here. # Close or detach a copy relationship Source: https://api-portal.etoro.com/api-reference/copy-trading/close-or-detach-a-copy-relationship /api-reference/openapi.json delete /api/v2/trading/copy **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- This action closes the sub-portfolio of the copy relationship. There are 2 ways to close the sub-portfolio: (a) Close — close all positions and withdraw the funds back to the main portfolio balance; (b) Detach — detach the positions from the sub-portfolio and move them into the main portfolio, and withdraw the sub-portfolio cash balance back into the main portfolio balance. These correspond to the unregisterType values Close and Detach. The relationship is selected by mirrorID; identity is resolved from the authenticated caller. This binding takes all fields as query parameters and rejects any request carrying a body — use POST /api/v2/trading/copy/close for a JSON-body equivalent. The operation is asynchronous and the response token is an acknowledgment only: close completion is not pollable through this API. # Close or detach a copy relationship (JSON body) Source: https://api-portal.etoro.com/api-reference/copy-trading/close-or-detach-a-copy-relationship-json-body /api-reference/openapi.json post /api/v2/trading/copy/close **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- This action closes the sub-portfolio of the copy relationship. There are 2 ways to close the sub-portfolio: (a) Close — close all positions and withdraw the funds back to the main portfolio balance; (b) Detach — detach the positions from the sub-portfolio and move them into the main portfolio, and withdraw the sub-portfolio cash balance back into the main portfolio balance. These correspond to the unregisterType values Close and Detach. Identical semantics to DELETE /api/v2/trading/copy, with the fields carried in a JSON body instead of query parameters — provided because some HTTP clients and proxies handle DELETE requests with bodies unreliably. The response token is an acknowledgment only: close completion is not pollable through this API. # Poll a copy operation's outcome Source: https://api-portal.etoro.com/api-reference/copy-trading/poll-a-copy-operations-outcome /api-reference/openapi.json get /api/v2/trading/copy/{referenceId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the terminal outcome of a copy request for register, add or remove funds, looked up by the referenceID supplied on the copy request. The lookup is case-sensitive and scoped to the authenticated account. On success the response carries the mirrorID used to close the copy later; parentCID and parentUsername are either both present or both absent. This endpoint returns only the status of the copy request, not the status of the mirror sub-portfolio. For sub-portfolio status use a portfolio endpoint. # Pre-check whether a copy registration would be allowed Source: https://api-portal.etoro.com/api-reference/copy-trading/pre-check-whether-a-copy-registration-would-be-allowed /api-reference/openapi.json post /api/v2/trading/copy/eligibility **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- A dry run of the register operation that changes nothing: verifies whether the authenticated account can copy the given investor with the given amount. Request body is the same as starting a new copy (POST /api/v2/trading/copy). A positive verdict is a point-in-time check, not a reservation. When isSuccess is false, errorCode and errorMessage may be absent. # Start copying an investor, or adjust an existing copy Source: https://api-portal.etoro.com/api-reference/copy-trading/start-copying-an-investor-or-adjust-an-existing-copy /api-reference/openapi.json post /api/v2/trading/copy **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Registers a copy relationship with the given investor for the authenticated account. If the copy already exists, funds will be added to or removed from it; if it does not exist, a new copy will be created and funds transferred into it. Every change of funds causes a realignment process that adjusts all the positions inside the sub-portfolio to match the parent portfolio proportions. Investor account ids (parentCID) are the ids surfaced by the platform's public endpoints (for example, the Rankings endpoints). The operation is asynchronous: the response token acknowledges acceptance, and the outcome can be checked via GET /api/v2/trading/copy/{referenceId} using the referenceID supplied here. # Get price candles for an instrument Source: https://api-portal.etoro.com/api-reference/data/get-price-candles-for-an-instrument /api-reference/openapi.json get /api/v1/data/instruments/{instrumentId}/candles **Rate limit:** 120 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/data/instruments/{instrumentId}/candles/coverage` --- Full-history OHLC candles for one instrument and interval, from a public view built and kept current by a DataPlatform job. Not user-scoped: identical for every caller for the same instrument and parameters. A range without `from` returns the most recent slice; a slice covers at most 10,080 periods of the interval (7 days of 1m, up to all history for 1d/1w), and a longer range is paged with the keyset `cursor` in `pagination.nextCursor`. An instrument with no data for the interval, or one etoro shows internally only, returns 200 with an empty `results` array, not 404. Call the coverage endpoint first to find a range that has data. # Get the caller's closed position event history counts Source: https://api-portal.etoro.com/api-reference/data/get-the-callers-closed-position-event-history-counts /api-reference/openapi.json get /api/v1/data/positions/closed-events/history **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the calling customer's historical count of closed position events, broken down by close year and asset type, one entry per (closeYear, assetType) combination sorted ascending by year then asset type. This is user-scoped: the caller is identified by their own gateway-issued GCID, not a path or query parameter, so it always answers for 'me'. Results are returned under `results` with a `pagination` block; a customer with no closed-position history returns 200 with an empty `results` array, not 404 - there is no distinguishable 'not found' state for this endpoint. # Get the caller's StockBack/Cashback promo status Source: https://api-portal.etoro.com/api-reference/data/get-the-callers-stockbackcashback-promo-status /api-reference/openapi.json get /api/v1/data/stockback/promo-status **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the calling customer's current StockBack/Cashback promo enrollment and lifetime USD reward figures - opted-in status, selected stock, professional-investor status, reward channel, club tier, country, this month's expected reward, and lifetime StockBack/Cashback/total USD earned. This is user-scoped: the caller is identified by their own gateway-issued GCID, not a path or query parameter, so it always answers for 'me'. A customer who is not (or not yet) enrolled in the promo still returns 200, with every value field null, rather than 404 - a 404 means no row exists for this GCID at all, which is a data-completeness gap, not simply 'not enrolled'. # Get where price candles exist for an instrument Source: https://api-portal.etoro.com/api-reference/data/get-where-price-candles-exist-for-an-instrument /api-reference/openapi.json get /api/v1/data/instruments/{instrumentId}/candles/coverage **Rate limit:** 120 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/data/instruments/{instrumentId}/candles` --- Returns, per interval, the oldest and newest candle, how many exist, and when the daily load last refreshed them. Call it before requesting candles to pick an interval and a range that has data: history can span more than 15 years, and ranges outside it return empty pages. Not user-scoped. An instrument with no data, or one etoro shows internally only, returns an empty `intervals` list, not a 404. # Get authenticated user profile Source: https://api-portal.etoro.com/api-reference/identity/get-authenticated-user-profile /api-reference/openapi.json get /api/v1/me **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the profile of the currently authenticated user, including account identifiers (GCID, real and demo CIDs), profile fields from Scope Data API (username, name, player level, gender, language, date of birth, avatar URL), and the OAuth scopes granted to the current access token. # Get historical closing prices Source: https://api-portal.etoro.com/api-reference/market-data/get-historical-closing-prices /api-reference/openapi.json get /api/v1/market-data/instruments/history/closing-price **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` # Get instrument candle history Source: https://api-portal.etoro.com/api-reference/market-data/get-instrument-candle-history /api-reference/openapi.json get /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount} **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` --- Retrieves historical price data in OHLCV (Open, High, Low, Close, Volume) format for a specified instrument. The data is organized into time-based candles of various intervals, from one minute to one week. # Get instrument display data Source: https://api-portal.etoro.com/api-reference/market-data/get-instrument-display-data /api-reference/openapi.json get /api/v1/market-data/instruments **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` # Get instrument market rates Source: https://api-portal.etoro.com/api-reference/market-data/get-instrument-market-rates /api-reference/openapi.json get /api/v1/market-data/instruments/rates **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` --- Provides real-time market data including bid/ask prices, conversion rates, and execution prices for specified financial instruments. Essential for price discovery and trade execution decisions. # Get stocks industries Source: https://api-portal.etoro.com/api-reference/market-data/get-stocks-industries /api-reference/openapi.json get /api/v1/market-data/stocks-industries **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` # List instrument types Source: https://api-portal.etoro.com/api-reference/market-data/list-instrument-types /api-reference/openapi.json get /api/v1/market-data/instrument-types **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` # List supported exchanges Source: https://api-portal.etoro.com/api-reference/market-data/list-supported-exchanges /api-reference/openapi.json get /api/v1/market-data/exchanges **Rate limit:** 120 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/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` # Retrieve bid/ask rates for one or more instruments Source: https://api-portal.etoro.com/api-reference/market-data/retrieve-bidask-rates-for-one-or-more-instruments /api-reference/openapi.json get /api/v2/market-data/rates **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` --- Returns current bid/ask rates keyed by instrument ID. Each rate carries a `quoteType` indicating whether it is `realtime` or `delayed`. Returns 200 when all requested instruments are found, 206 when only a subset is available. # Search for Instruments Source: https://api-portal.etoro.com/api-reference/market-data/search-for-instruments /api-reference/openapi.json get /api/v1/market-data/search **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` --- Retrieve a paginated list of instruments. Any field in the Instrument response schema can be projected via the required `fields` parameter and/or used as a query-string filter (e.g. `fields=instrumentId,displayname&displayname=Bitcoin`). Use `pageSize`/`pageNumber` to paginate and `sort` to order. Filters that do not match an indexed instrument field are ignored. # Search for securities (instruments) by ID or symbol Source: https://api-portal.etoro.com/api-reference/market-data/search-for-securities-instruments-by-id-or-symbol /api-reference/openapi.json get /api/v2/market-data/instruments **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments/search` - `GET /api/v2/market-data/rates` --- Returns instrument (security) metadata, optionally filtered by instrument IDs or symbols, with cursor-based pagination. `instrumentsIds` and `symbols` are mutually exclusive. All filters are optional and independent; if neither `instrumentsIds` nor `symbols` is provided, results are not filtered by instrument and are simply paginated by `pageSize`. # Search instruments by free-text query Source: https://api-portal.etoro.com/api-reference/market-data/search-instruments-by-free-text-query /api-reference/openapi.json get /api/v2/market-data/instruments/search **Rate limit:** 120 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/market-data/exchanges` - `GET /api/v1/market-data/instrument-types` - `GET /api/v1/market-data/instruments` - `GET /api/v1/market-data/instruments/history/closing-price` - `GET /api/v1/market-data/instruments/rates` - `GET /api/v1/market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}` - `GET /api/v1/market-data/search` - `GET /api/v1/market-data/stocks-industries` - `GET /api/v2/market-data/instruments` - `GET /api/v2/market-data/rates` --- Free-text search of instruments by name or symbol. Results are relevance-ranked by the upstream search index; non-public instruments are filtered out. # Get in-app notifications Source: https://api-portal.etoro.com/api-reference/notifications/get-in-app-notifications /api-reference/openapi.json get /api/v1/notifications/messages **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves all in-app notifications for the authenticated user. Rate limit: 1 request per second. # Mark all notifications as read Source: https://api-portal.etoro.com/api-reference/notifications/mark-all-notifications-as-read /api-reference/openapi.json patch /api/v1/notifications/messages **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Marks all notifications as read for the authenticated user. Rate limit: 20 requests per minute. # Get copiers public info Source: https://api-portal.etoro.com/api-reference/pi-data/get-copiers-public-info /api-reference/openapi.json get /api/v1/pi-data/copiers **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. # Search for trader portfolios or Smart Portfolios by free-text query Source: https://api-portal.etoro.com/api-reference/portfoliosearch/search-for-trader-portfolios-or-smart-portfolios-by-free-text-query /api-reference/openapi.json get /api/v1/portfolios/search **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a relevance-ranked list of publicly visible trader portfolios or Smart Portfolios matching the query string. The required `type` parameter determines which index is searched. Results are capped at `limit`. # Create a price alert Source: https://api-portal.etoro.com/api-reference/price-alerts/create-a-price-alert /api-reference/openapi.json post /api/v1/price-alerts **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a new price alert for the authenticated user. The alert will fire when the market bid price reaches the target price. Provide a symbol to identify the instrument. # Delete a price alert Source: https://api-portal.etoro.com/api-reference/price-alerts/delete-a-price-alert /api-reference/openapi.json delete /api/v1/price-alerts/{alertId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Permanently deletes a price alert owned by the authenticated user. # Get price alerts Source: https://api-portal.etoro.com/api-reference/price-alerts/get-price-alerts /api-reference/openapi.json get /api/v1/price-alerts **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns all active price alerts for the authenticated user. Supports optional filtering by alertIds, instrumentIds, or symbols. The instrumentIds and symbols filters refer to the same dimension and are OR-combined with each other. The resulting instrument filter is AND-combined with alertIds. When no filters are provided, returns all active alerts. # Update a price alert Source: https://api-portal.etoro.com/api-reference/price-alerts/update-a-price-alert /api-reference/openapi.json patch /api/v1/price-alerts/{alertId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Updates the target price of an existing price alert. # Bulk-fetch ranking rows Source: https://api-portal.etoro.com/api-reference/rankings/bulk-fetch-ranking-rows /api-reference/openapi.json post /api/v2/portfolios/rankings/multiple **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns ranking rows for a list of investors identified by username. Missing, private, or unranked users are silently omitted. Maximum 100 usernames per request. # Get paginated investor rankings Source: https://api-portal.etoro.com/api-reference/rankings/get-paginated-investor-rankings /api-reference/openapi.json get /api/v2/portfolios/rankings **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a paged list of investor ranking rows filtered and sorted by query parameters. `period` is required; all filter parameters are optional. # Get ranking row for a single investor Source: https://api-portal.etoro.com/api-reference/rankings/get-ranking-row-for-a-single-investor /api-reference/openapi.json get /api/v2/portfolios/{username}/rankings **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the full ranking row for the specified investor for a given time period. Returns 404 if the user is private, not found, or not ranked. `period` is required because every performance field is computed over a defined time window. # Get ranking universe aggregated by sector or industry Source: https://api-portal.etoro.com/api-reference/rankings/get-ranking-universe-aggregated-by-sector-or-industry /api-reference/openapi.json get /api/v2/portfolios/rankings/summary **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Aggregates ranked investors into tag-bucketed summaries. The required `summary` query parameter must be "industries" or "sectors". TagIds from the internal service are resolved to readable names. # Get rankings by named preset Source: https://api-portal.etoro.com/api-reference/rankings/get-rankings-by-named-preset /api-reference/openapi.json get /api/v2/portfolios/rankings/presets/{type} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Applies a predefined filter preset. Equivalent to GET /rankings with the preset's filters pre-applied. Unknown or non-whitelisted presets return 404 with the verbatim JSON string "Filter Not Found". # List all ranking tags Source: https://api-portal.etoro.com/api-reference/rankings/list-all-ranking-tags /api-reference/openapi.json get /api/v2/portfolios/rankings/tags **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the full catalog of ranking tags (industries and sectors) with resolved names. Optionally filter to a single dimension via the `type` query parameter. No pagination. # List available ranking presets Source: https://api-portal.etoro.com/api-reference/rankings/list-available-ranking-presets /api-reference/openapi.json get /api/v2/portfolios/rankings/presets **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the names of all publicly available ranking presets. Use a preset name as the `{type}` path parameter in GET /portfolios/rankings/presets/{type}. No pagination. # Create a comment on a post Source: https://api-portal.etoro.com/api-reference/social-feeds/create-a-comment-on-a-post /api-reference/openapi.json post /api/v1/posts/{postId}/comments **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a new comment on a specific discussion post. Comments can include text, mentions, tags, and attachments. # Create a new discussion post Source: https://api-portal.etoro.com/api-reference/social-feeds/create-a-new-discussion-post /api-reference/openapi.json post /api/v1/posts **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a new discussion post in the feed system. This endpoint allows users to create posts that can be associated with instruments, users, or general discussions. # Create a poll post Source: https://api-portal.etoro.com/api-reference/social-feeds/create-a-poll-post /api-reference/openapi.json post /api/v1/posts/polls **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a new poll post. The poll must include a title and at least 2 options. Once created the poll is immutable — options and title cannot be changed. The post itself can still be deleted. # Create a reply Source: https://api-portal.etoro.com/api-reference/social-feeds/create-a-reply /api-reference/openapi.json post /api/v1/posts/{postId}/comments/{commentId}/replies **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a reply nested under an existing comment. Replies are 1-level deep — replying to a reply attaches to the same parent comment with an inline @mention to the reply author. Increments parent comment's repliesCount and the post's totalCommentsAndReplies. # Follow a post Source: https://api-portal.etoro.com/api-reference/social-feeds/follow-a-post /api-reference/openapi.json post /api/v1/posts/{postId}/follows **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Subscribes the authenticated user to push notifications when the post receives new comments or replies. Drives requesterContext.isFollowing on subsequent reads. Idempotent — following an already-followed post succeeds silently. This endpoint takes no request body. # Get a single post by ID Source: https://api-portal.etoro.com/api-reference/social-feeds/get-a-single-post-by-id /api-reference/openapi.json get /api/v1/posts/{postId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves a single discussion post by its ID, including comments preview, emotions data, and requester context. Authentication is optional — unauthenticated requests receive the post without personalised requester context. # Get following feed Source: https://api-portal.etoro.com/api-reference/social-feeds/get-following-feed /api-reference/openapi.json get /api/v1/feeds/following **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/feeds/for-you` - `GET /api/v1/feeds/instrument/{marketId}` - `GET /api/v1/feeds/markets/{marketId}` - `GET /api/v1/feeds/news` - `GET /api/v1/feeds/saved` - `GET /api/v1/feeds/user/{userId}` - `GET /api/v1/feeds/users/{userId}` - `GET /api/v1/feeds/users/{userId}/pinned` --- Returns a chronological feed of posts from users the authenticated user follows. Requires authentication. # Get instrument feed posts Source: https://api-portal.etoro.com/api-reference/social-feeds/get-instrument-feed-posts /api-reference/openapi.json get /api/v1/feeds/markets/{marketId} **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/feeds/following` - `GET /api/v1/feeds/for-you` - `GET /api/v1/feeds/instrument/{marketId}` - `GET /api/v1/feeds/news` - `GET /api/v1/feeds/saved` - `GET /api/v1/feeds/user/{userId}` - `GET /api/v1/feeds/users/{userId}` - `GET /api/v1/feeds/users/{userId}/pinned` --- Retrieves feed posts associated with a specific financial instrument. The feed includes discussions, analyses, and other content related to the instrument. # Get news feed Source: https://api-portal.etoro.com/api-reference/social-feeds/get-news-feed /api-reference/openapi.json get /api/v1/feeds/news **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/feeds/following` - `GET /api/v1/feeds/for-you` - `GET /api/v1/feeds/instrument/{marketId}` - `GET /api/v1/feeds/markets/{marketId}` - `GET /api/v1/feeds/saved` - `GET /api/v1/feeds/user/{userId}` - `GET /api/v1/feeds/users/{userId}` - `GET /api/v1/feeds/users/{userId}/pinned` --- Returns a ranked news feed for the authenticated user. Ranking method is resolved via A/B experiment and a configurable default. # Get personalised For You feed Source: https://api-portal.etoro.com/api-reference/social-feeds/get-personalised-for-you-feed /api-reference/openapi.json get /api/v1/feeds/for-you **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/feeds/following` - `GET /api/v1/feeds/instrument/{marketId}` - `GET /api/v1/feeds/markets/{marketId}` - `GET /api/v1/feeds/news` - `GET /api/v1/feeds/saved` - `GET /api/v1/feeds/user/{userId}` - `GET /api/v1/feeds/users/{userId}` - `GET /api/v1/feeds/users/{userId}/pinned` --- Returns a personalised feed for the authenticated user ranked by followed users, followed instruments, prior engagement, and freshness. Ranking method is resolved via A/B experiment (Optimizely) and per-user overrides. Requires authentication — this feed is intrinsically personal. # Get saved feed Source: https://api-portal.etoro.com/api-reference/social-feeds/get-saved-feed /api-reference/openapi.json get /api/v1/feeds/saved **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/feeds/following` - `GET /api/v1/feeds/for-you` - `GET /api/v1/feeds/instrument/{marketId}` - `GET /api/v1/feeds/markets/{marketId}` - `GET /api/v1/feeds/news` - `GET /api/v1/feeds/user/{userId}` - `GET /api/v1/feeds/users/{userId}` - `GET /api/v1/feeds/users/{userId}/pinned` --- Returns a list of posts the authenticated user has bookmarked. Only the requesting user can see their own saved feed. Requires authentication. # Get user feed posts Source: https://api-portal.etoro.com/api-reference/social-feeds/get-user-feed-posts /api-reference/openapi.json get /api/v1/feeds/users/{userId} **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/feeds/following` - `GET /api/v1/feeds/for-you` - `GET /api/v1/feeds/instrument/{marketId}` - `GET /api/v1/feeds/markets/{marketId}` - `GET /api/v1/feeds/news` - `GET /api/v1/feeds/saved` - `GET /api/v1/feeds/user/{userId}` - `GET /api/v1/feeds/users/{userId}/pinned` --- Retrieves feed posts associated with a specific user. The feed includes the user's discussions, analyses, and other content they have posted. # Get user pinned feed posts Source: https://api-portal.etoro.com/api-reference/social-feeds/get-user-pinned-feed-posts /api-reference/openapi.json get /api/v1/feeds/users/{userId}/pinned **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/feeds/following` - `GET /api/v1/feeds/for-you` - `GET /api/v1/feeds/instrument/{marketId}` - `GET /api/v1/feeds/markets/{marketId}` - `GET /api/v1/feeds/news` - `GET /api/v1/feeds/saved` - `GET /api/v1/feeds/user/{userId}` - `GET /api/v1/feeds/users/{userId}` --- Retrieves the posts that the specified user has pinned to the top of their profile feed. The pinned feed surfaces highlighted content the user has explicitly chosen to feature, ordered by pin time. # Like a comment Source: https://api-portal.etoro.com/api-reference/social-feeds/like-a-comment /api-reference/openapi.json post /api/v1/posts/{postId}/comments/{commentId}/likes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Toggles a Like emotion on the specified comment for the authenticated user. emotionType defaults to Like (the only supported emotion type). The call is idempotent — liking an already-liked entity succeeds silently. # Like a post Source: https://api-portal.etoro.com/api-reference/social-feeds/like-a-post /api-reference/openapi.json post /api/v1/posts/{postId}/likes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Toggles a Like emotion on the specified post for the authenticated user. emotionType defaults to Like (the only supported emotion type). The call is idempotent — liking an already-liked entity succeeds silently. # Like a reply Source: https://api-portal.etoro.com/api-reference/social-feeds/like-a-reply /api-reference/openapi.json post /api/v1/posts/{postId}/comments/{commentId}/replies/{replyId}/likes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Toggles a Like emotion on the specified reply for the authenticated user. emotionType defaults to Like (the only supported emotion type). The call is idempotent — liking an already-liked entity succeeds silently. # List comments on a post Source: https://api-portal.etoro.com/api-reference/social-feeds/list-comments-on-a-post /api-reference/openapi.json get /api/v1/posts/{postId}/comments **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a paginated list of top-level comments on a post. Soft-deleted comments are included with isDeleted=true and blanked content so reply trees remain navigable. Authentication is optional — unauthenticated requests omit requesterContext. # List replies on a comment Source: https://api-portal.etoro.com/api-reference/social-feeds/list-replies-on-a-comment /api-reference/openapi.json get /api/v1/posts/{postId}/comments/{commentId}/replies **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a paginated list of replies nested under a specific comment. Authentication is optional. # List shares of a post Source: https://api-portal.etoro.com/api-reference/social-feeds/list-shares-of-a-post /api-reference/openapi.json get /api/v1/posts/{postId}/shares **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a paginated list of shares of the specified post, including both plain reshares and quote shares. Authentication is optional. # Pin post to profile Source: https://api-portal.etoro.com/api-reference/social-feeds/pin-post-to-profile /api-reference/openapi.json post /api/v1/posts/{postId}/pins **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Pins the specified post to the authenticated user's profile so it appears at the top of their feed. Users can pin only their own posts. The call is idempotent — pinning an already-pinned post succeeds silently. # Remove poll vote Source: https://api-portal.etoro.com/api-reference/social-feeds/remove-poll-vote /api-reference/openapi.json delete /api/v1/posts/{postId}/polls/{pollId}/options/{optionId}/votes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Removes the authenticated user's vote from a specific poll option. # Save a post Source: https://api-portal.etoro.com/api-reference/social-feeds/save-a-post /api-reference/openapi.json post /api/v1/posts/{postId}/saves **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Bookmarks a post for the authenticated user. Idempotent — saving an already-saved post succeeds silently. The save is private and visible only to the saving user. This endpoint takes no request body. # Share a post Source: https://api-portal.etoro.com/api-reference/social-feeds/share-a-post /api-reference/openapi.json post /api/v1/posts/shares **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a share post that references an existing post. Two variants are supported: - **Reshare** — send `message` as an empty string (`""`). - **Quote share** — send `message` with your commentary text. Returns 201 on success. See the request body for field-level semantics, including how to collapse share chains. # Soft-delete a comment Source: https://api-portal.etoro.com/api-reference/social-feeds/soft-delete-a-comment /api-reference/openapi.json delete /api/v1/posts/{postId}/comments/{commentId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Soft-deletes the authenticated user's own comment. Sets isDeleted=true and blanks message text and attachments. Replies are preserved and the parent post's totalCommentsAndReplies is decremented only by the deleted node. # Soft-delete a post Source: https://api-portal.etoro.com/api-reference/social-feeds/soft-delete-a-post /api-reference/openapi.json delete /api/v1/posts/{postId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Soft-deletes the authenticated user's own post. Sets isDeleted=true and blanks message text and attachments. Child comments and like/comment counters are preserved. The post is removed from all feed listings. # Soft-delete a reply Source: https://api-portal.etoro.com/api-reference/social-feeds/soft-delete-a-reply /api-reference/openapi.json delete /api/v1/posts/{postId}/comments/{commentId}/replies/{replyId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Soft-deletes the authenticated user's own reply. # Unfollow a post Source: https://api-portal.etoro.com/api-reference/social-feeds/unfollow-a-post /api-reference/openapi.json delete /api/v1/posts/{postId}/follows **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Unsubscribes the authenticated user from notifications on this post. Idempotent — unfollowing a post that was never followed succeeds silently. # Unlike a comment Source: https://api-portal.etoro.com/api-reference/social-feeds/unlike-a-comment /api-reference/openapi.json delete /api/v1/posts/{postId}/comments/{commentId}/likes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Removes the authenticated user's Like from the specified comment. emotionType defaults to Like (the only supported emotion type). The call is idempotent — unliking an entity with no active like succeeds silently. # Unlike a post Source: https://api-portal.etoro.com/api-reference/social-feeds/unlike-a-post /api-reference/openapi.json delete /api/v1/posts/{postId}/likes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Removes the authenticated user's Like from the specified post. emotionType defaults to Like (the only supported emotion type). The call is idempotent — unliking an entity with no active like succeeds silently. # Unlike a reply Source: https://api-portal.etoro.com/api-reference/social-feeds/unlike-a-reply /api-reference/openapi.json delete /api/v1/posts/{postId}/comments/{commentId}/replies/{replyId}/likes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Removes the authenticated user's Like from the specified reply. emotionType defaults to Like (the only supported emotion type). The call is idempotent — unliking an entity with no active like succeeds silently. # Unpin post from profile Source: https://api-portal.etoro.com/api-reference/social-feeds/unpin-post-from-profile /api-reference/openapi.json delete /api/v1/posts/{postId}/pins **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Removes the authenticated user's pin from the specified post. The call is idempotent — unpinning a post that is not currently pinned succeeds silently. # Unsave a post Source: https://api-portal.etoro.com/api-reference/social-feeds/unsave-a-post /api-reference/openapi.json delete /api/v1/posts/{postId}/saves **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Removes a post from the authenticated user's saved bookmarks. Idempotent — unsaving a post that was never saved succeeds silently. # Update a comment Source: https://api-portal.etoro.com/api-reference/social-feeds/update-a-comment /api-reference/openapi.json put /api/v1/posts/{postId}/comments/{commentId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Edits the authenticated user's own comment in-place. Sets editStatus to Edited. Emotion counts, repliesCount, and created are preserved. Owner is derived from the auth token. # Update a reply Source: https://api-portal.etoro.com/api-reference/social-feeds/update-a-reply /api-reference/openapi.json put /api/v1/posts/{postId}/comments/{commentId}/replies/{replyId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Edits the authenticated user's own reply in-place. Same semantics as updating a comment. # Update an existing post Source: https://api-portal.etoro.com/api-reference/social-feeds/update-an-existing-post /api-reference/openapi.json put /api/v1/posts/{postId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Updates the authenticated user's own post in-place. The owner field is derived from the authentication token and must not be supplied in the request body. Editable fields: message, tags, mentions, attachments. # Upload a media attachment Source: https://api-portal.etoro.com/api-reference/social-feeds/upload-a-media-attachment /api-reference/openapi.json post /api/v1/attachments **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Two-step media upload: clients first upload a file here to receive an Attachment object, then pass its url in a POST /feeds/post or POST /reactions/.../comment payload. Accepts multipart/form-data with a binary file field. Supported formats: JPEG and PNG. Maximum file size: 8 MB (8,388,608 bytes). The returned url is a plain CDN URL scoped to the uploading user. # Vote on a poll option Source: https://api-portal.etoro.com/api-reference/social-feeds/vote-on-a-poll-option /api-reference/openapi.json post /api/v1/posts/{postId}/polls/{pollId}/options/{optionId}/votes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Casts the authenticated user's vote on a specific poll option. Each user can vote only once per poll. Poll owners cannot vote on their own poll. # Delete OAuth application Source: https://api-portal.etoro.com/api-reference/sso--applications/delete-oauth-application /api-reference/openapi.json delete /api/v1/sso/applications/{clientId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Permanently deletes an OAuth application. Only the application's admin can delete it. Non-admins receive `404 Not Found` (opaque authorization). The application stops appearing in `GET /api/v1/sso/applications` within a few seconds. # List my OAuth applications Source: https://api-portal.etoro.com/api-reference/sso--applications/list-my-oauth-applications /api-reference/openapi.json get /api/v1/sso/applications **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns every OAuth application where the authenticated user (matched by GCID) is listed as an administrator. The `clientSecret` is never included in this response - it is revealed only when the application is created, or when it is replaced via `POST /api/v1/sso/applications/{clientId}/client-secret`. # Register OAuth application Source: https://api-portal.etoro.com/api-reference/sso--applications/register-oauth-application /api-reference/openapi.json post /api/v1/sso/applications **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a new OAuth application. The authenticated user automatically becomes the application admin. Both `clientId` and `clientSecret` are auto-generated server-side. The `clientSecret` is returned **only in this response** (one-time reveal) - subsequent reads will never expose it again, so callers must store it securely. Auto-populated defaults (audience, applicationType, supported flows, token expirations) come from service configuration. Validation: `applicationName` max 100 chars, `applicationIconUrl` max 500 chars, each `redirectUri` max 500 chars and unique, each `scopeId` positive and recognized in the scope catalog. # Replace OAuth client secret Source: https://api-portal.etoro.com/api-reference/sso--applications/replace-oauth-client-secret /api-reference/openapi.json post /api/v1/sso/applications/{clientId}/client-secret **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Replaces the application's `clientSecret` and returns the new one. Only the application's admin (the caller's GCID must be in `adminGcids`) can rotate. Non-admins receive `404 Not Found` (opaque authorization). **The current secret is not required** - ownership is proven by the access token and the application's `adminGcids`, not by presenting the old secret, which may have been leaked; a leaked secret is the usual reason to rotate. **The previous secret stops working immediately** - there is no overlap window, so anything still using it fails as soon as this call returns. The new secret is returned **only in this response** (one-time reveal) and can never be read again, only replaced. Nothing else about the application changes. An application created moments earlier may briefly answer `404` while it propagates; retry. # Update OAuth application Source: https://api-portal.etoro.com/api-reference/sso--applications/update-oauth-application /api-reference/openapi.json put /api/v1/sso/applications/{clientId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Updates one or more modifiable fields of an existing OAuth application. Only the application's admin (the caller's GCID must be in `adminGcids`) can perform updates. Non-admins receive `404 Not Found` (opaque authorization - the gateway does not disclose whether the application exists). At least one field must be provided in the body; omitted fields are left unchanged. Uniqueness and length constraints match the create endpoint. # List available OAuth scopes Source: https://api-portal.etoro.com/api-reference/sso--scopes/list-available-oauth-scopes /api-reference/openapi.json get /api/v1/sso/scopes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the public catalog of OAuth scopes that can be requested when creating or updating an application. Use this endpoint to render scope pickers and to validate scope ids client-side before calling create/update. # Create Sub-Account Money Transfer Source: https://api-portal.etoro.com/api-reference/sub-accounts--etoro-trading/create-sub-account-money-transfer /api-reference/openapi.json post /api/v1/sub-accounts/etoro-trading/money-transfers **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Executes a money transfer between the authenticated caller and the sub-account identified by the x-sub-account-id header. The amount must be positive with up to two decimal places. Direction ToSubAccount moves funds from the caller to the sub-account; FromSubAccount moves funds from the sub-account back to the caller. # Create Sub-Account User Token Source: https://api-portal.etoro.com/api-reference/sub-accounts--etoro-trading/create-sub-account-user-token /api-reference/openapi.json post /api/v1/sub-accounts/etoro-trading/user-tokens **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Generates a non-interactive user token for the sub-account identified by the x-sub-account-id header. The secret token value is returned only once, in this response. # Get Allowed Sub-Account Token Scopes Source: https://api-portal.etoro.com/api-reference/sub-accounts--etoro-trading/get-allowed-sub-account-token-scopes /api-reference/openapi.json get /api/v1/sub-accounts/etoro-trading/user-tokens/scopes **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the scope names that may be assigned to sub-account non-interactive user tokens (the etoro-trading-subaccount application's scopes). # List Sub-Account User Tokens Source: https://api-portal.etoro.com/api-reference/sub-accounts--etoro-trading/list-sub-account-user-tokens /api-reference/openapi.json get /api/v1/sub-accounts/etoro-trading/user-tokens **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Lists all sub-account non-interactive user tokens owned by the authenticated user, across all their etoro trading sub-accounts. The secret token value is never included in list results. # Revoke Sub-Account User Token Source: https://api-portal.etoro.com/api-reference/sub-accounts--etoro-trading/revoke-sub-account-user-token /api-reference/openapi.json delete /api/v1/sub-accounts/etoro-trading/user-tokens/{userTokenId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Revokes a sub-account user token. Revocation is idempotent, so revoking a token that does not exist also succeeds. # Update Sub-Account User Token Source: https://api-portal.etoro.com/api-reference/sub-accounts--etoro-trading/update-sub-account-user-token /api-reference/openapi.json patch /api/v1/sub-accounts/etoro-trading/user-tokens/{userTokenId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Updates an existing sub-account user token's scopes, IP whitelist, or expiration. At least one field must be provided. # Create My Sub-Account Source: https://api-portal.etoro.com/api-reference/sub-accounts/create-my-sub-account /api-reference/openapi.json post /api/v1/sub-accounts/me/accounts **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Creates a sub-account for the authenticated user with the given provider. Currently the supported provider is `etoro-trading` (creates an etoro trading sub-account); additional sub-account providers will be added over time. For `etoro-trading`, `additionalParams.username` is required. # Get My Sub-Accounts Source: https://api-portal.etoro.com/api-reference/sub-accounts/get-my-sub-accounts /api-reference/openapi.json get /api/v1/sub-accounts/me/accounts **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the authenticated user's sub-accounts. Currently the supported provider is `etoro-trading` (etoro trading sub-accounts); additional sub-account providers will be added over time. # Get top assets for a user Source: https://api-portal.etoro.com/api-reference/top-assets/get-top-assets-for-a-user /api-reference/openapi.json get /api/v1/impressions/topassets/user/{gcid} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves a ranked list of top asset scores associated with a specific user, based on impressions data. # Cancel pending demo close order Source: https://api-portal.etoro.com/api-reference/trading--demo/cancel-pending-demo-close-order /api-reference/openapi.json delete /api/v1/trading/execution/demo/market-close-orders/{orderId} **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint allows traders to cancel a previously placed market order for close before execution. If the order has already been processed, cancellation will not be possible. A 200 response confirms the cancellation request was received, not that the order was cancelled. Confirm with GET /api/v1/trading/info/demo/close-orders/{orderId}, using the orderId of the close order you tried to cancel. If the DELETE response is lost (timeout or network error), do not resend the cancel - poll that GET endpoint with the same orderId. Units reported as executed in its positions[] array were closed before the cancel took effect; the remainder was not closed. No executed entries in positions[] means nothing was closed. Poll until statusID is terminal: 7 (CANCELED) = cancelled with nothing executed, 9 (CANCELED_PARTIALLY_FILLED) = cancelled after a partial fill (executed units in positions[]), 3 (FILLED) = fully executed before the cancel; 1, 2, 5, 6 and 11 are still pending. # Cancels an order before it is executed Source: https://api-portal.etoro.com/api-reference/trading--demo/cancels-an-order-before-it-is-executed /api-reference/openapi.json delete /api/v2/trading/execution/demo/orders/{orderId} **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint sends a cancellation request to cancel an order before execution. An order can be cancelled if it is waiting for the market to open, or for the trigger rate to be published (MIT orders). The cancellation request may be successful, and the order is cancelled, or unsuccessful, and the order is not cancelled. This operation is idempotent when the order is already closed or cancelled. A 200 response confirms the cancellation request was accepted, not that the order was cancelled - it may already have executed. Confirm with GET /api/v2/trading/info/demo/orders:lookup: status.id 7 (Canceled) or 9 (CanceledPartiallyFilled) means the cancellation took effect, while 6 (PendingCancel) means it is still being processed. # Check instrument trading eligibility Source: https://api-portal.etoro.com/api-reference/trading--demo/check-instrument-trading-eligibility /api-reference/openapi.json post /api/v2/trading/info/demo/eligibility **Rate limit:** 20 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- Returns per-instrument trading configuration for the authenticated account - position limits, permitted order types, stop-loss and take-profit boundaries, and available leverage by settlement type and direction. Instruments not found are listed in notFoundInstrumentIds and notFoundSymbols. At least one of instrumentIds or symbols must be supplied; the combined length must not exceed 100 instruments. This configuration changes rarely for a given instrument and account, so call it once and reuse the result for the rest of the session instead of re-querying before every order. # Close demo position by units Source: https://api-portal.etoro.com/api-reference/trading--demo/close-demo-position-by-units /api-reference/openapi.json post /api/v1/trading/execution/demo/market-close-orders/positions/{positionId} **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint allows traders to close an entire position or a portion of it at the current market rate. If `UnitsToDeduct` is provided, only the specified portion will be closed. If `UnitsToDeduct` is omitted or set to null, the full position will be closed. A 200 response means the close order was submitted, not that the position was closed. Confirm the outcome with GET /api/v1/trading/info/demo/close-orders/{orderId}, using the orderID returned under orderForClose. # Create an order Source: https://api-portal.etoro.com/api-reference/trading--demo/create-an-order /api-reference/openapi.json post /api/v2/trading/execution/demo/orders **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint allows traders to place an order. Leverage, stop-loss, and take-profit settings can be applied. Order size must use exactly one of amount, units, or contracts. For open orders the instrument must be identified by exactly one of symbol or instrumentId - providing both is rejected. A stopLossRate is required when leverage is greater than 1, when transaction is sellShort, when settlementType is realFutures, or when stopLossType is trailing. Only the buy and sellShort transactions are currently supported. A unique X-Request-Id header (GUID) is required for idempotency. Currently only orders to open a position are supported. On this v2 create path, settlementType remains optional (stricter settlementType rules apply only on v3). A 200 response means the order was accepted for processing, not that it was executed. Confirm the outcome with GET /api/v2/trading/info/demo/orders:lookup, passing the returned orderId - or referenceId, which echoes your X-Request-Id and is the only handle you have if this response is lost. In that response, status.id 3 (Filled) and 5 (PartiallyFilled) mean the order executed; 4 (Rejected) and 10 (RejectedPartiallyFilled) carry the reason in status.errorCode and status.errorMessage; 1 (Received), 2 (Placed), 11 (WaitingForMarket) and 12 (PendingTriggeredRate) are still in flight and should be polled again. positionExecutions lists the positionId values the order produced. # Get a filtered aggregated portfolio snapshot Source: https://api-portal.etoro.com/api-reference/trading--demo/get-a-filtered-aggregated-portfolio-snapshot /api-reference/openapi.json post /api/v1/trading/info/demo/aggregate-portfolio **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. # Get account PnL and portfolio details Source: https://api-portal.etoro.com/api-reference/trading--demo/get-account-pnl-and-portfolio-details /api-reference/openapi.json get /api/v1/trading/info/demo/pnl **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/portfolio` - `GET /api/v2/trading/info/demo/instrument-breakdown` --- Retrieves the demo account's current portfolio, including credit, open positions, orders, mirrors, and PnL details. # Get aggregated portfolio snapshot Source: https://api-portal.etoro.com/api-reference/trading--demo/get-aggregated-portfolio-snapshot /api-reference/openapi.json get /api/v1/trading/info/demo/aggregate-portfolio **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: - `POST /api/v1/trading/info/demo/aggregate-portfolio` --- Returns a complete snapshot of the authenticated user's demo account investment portfolio, organized by asset. The response includes account-level balances and equity, individually held positions grouped by asset, and any copy-trading relationships the user has active. Use the instrumentIds filter to scope results to a specific set of assets, or mirrorIds to isolate specific copy-trading relationships. Account totals always reflect the full portfolio regardless of filters applied. # Get close order information and closed position details Source: https://api-portal.etoro.com/api-reference/trading--demo/get-close-order-information-and-closed-position-details /api-reference/openapi.json get /api/v1/trading/info/demo/close-orders/{orderId} **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/orders/{orderId}` - `GET /api/v2/trading/info/demo/orders:lookup` --- Retrieves information about a close order, including its execution status and the positions that were closed as a result of the request. Use this to track the outcome of a position-closing order and identify which positions were affected. This is a read-only call and is the supported way to confirm the outcome of POST or DELETE /api/v1/trading/execution/demo/market-close-orders/... - including when the DELETE response was lost: poll this endpoint with the same close orderId instead of resending the cancel. Executed quantity is reported per affected position in positions[] (units and amount, with occurred and rate set once that position was closed); the order-level proceeds field totals what was realized. A close order that was cancelled before anything executed has no executed entries in positions[]. Any requested units that do not appear as executed in positions[] were not closed. errorCode and errorMessage are populated when processing failed. # Get demo portfolio breakdown Source: https://api-portal.etoro.com/api-reference/trading--demo/get-demo-portfolio-breakdown /api-reference/openapi.json get /api/v1/trading/info/demo/portfolio **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/pnl` - `GET /api/v2/trading/info/demo/instrument-breakdown` --- Returns detailed portfolio information including active positions, pending orders, mirror trading details, and account balances. This endpoint provides a complete overview of the user's trading activity and current market exposure. # Get instrument breakdown (demo) Source: https://api-portal.etoro.com/api-reference/trading--demo/get-instrument-breakdown-demo /api-reference/openapi.json get /api/v2/trading/info/demo/instrument-breakdown **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/pnl` - `GET /api/v1/trading/info/demo/portfolio` --- Returns the demo portfolio grouped by instrument, including per-position data, pending orders, and PnL. # Get order information and position details Source: https://api-portal.etoro.com/api-reference/trading--demo/get-order-information-and-position-details /api-reference/openapi.json get /api/v2/trading/info/demo/orders:lookup **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/close-orders/{orderId}` - `GET /api/v1/trading/info/demo/orders/{orderId}` --- Retrieves comprehensive information about a specific order, including the order status, execution details, and all positions that were opened or closed from this order. This endpoint is essential for tracking order execution and identifying which positions were created as a result of a specific order request. The response includes detailed position information with PositionID values that can be used to query position-specific details. Provide exactly one of orderId or referenceId. # Get what-if trading cost breakdown Source: https://api-portal.etoro.com/api-reference/trading--demo/get-what-if-trading-cost-breakdown /api-reference/openapi.json post /api/v2/trading/info/demo/costs **Rate limit:** 20 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- Returns the markup, market spread, transaction fee, overnight fee, over-weekend fee, and tax that would apply if the supplied order were executed now against the demo account. For `action: open`, exactly one of `symbol` or `instrumentId` must be provided and `leverage` must be at least 1. For `action: close`, `positionIds` must be non-empty. # List trading history Source: https://api-portal.etoro.com/api-reference/trading--demo/list-trading-history /api-reference/openapi.json get /api/v1/trading/info/trade/demo/history **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns closed trades for the authenticated account from `minDate` through the present. Keep each request's lookback to less than 1 year (maximum 1 year minus 1 day). For longer history, split the range into successive windows of at most that length (advance `minDate` per batch) and use `page` / `pageSize` within each window. # Modify stop-loss and take-profit settings on an open position Source: https://api-portal.etoro.com/api-reference/trading--demo/modify-stop-loss-and-take-profit-settings-on-an-open-position /api-reference/openapi.json patch /api/v2/trading/demo/positions/{positionId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Submits an asynchronous request to update stop-loss and/or take-profit on an open position. You can set a new stopLossRate, takeProfitRate, stopLossType, or clear either value (clearStopLoss, clearTakeProfit). At least one SL/TP-related field is required. The response returns acceptance and correlation metadata only. # Request cancellation of a pending order Source: https://api-portal.etoro.com/api-reference/trading--demo/request-cancellation-of-a-pending-order /api-reference/openapi.json delete /api/v3/trading/execution/demo/orders/{orderId} **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint sends a cancellation request to cancel an order before execution. An order can be cancelled if it is waiting for the market to open, or for the trigger rate to be published (MIT orders). The cancellation request may be successful, and the order is cancelled, or unsuccessful, and the order is not cancelled. This operation is idempotent when the order is already closed or cancelled. A 202 response confirms the cancellation request was accepted, not that the order was cancelled - it may already have executed. Confirm with GET /api/v2/trading/info/demo/orders:lookup: status.id 7 (Canceled) or 9 (CanceledPartiallyFilled) means the cancellation took effect, while 6 (PendingCancel) means it is still being processed. # Submit an order for asynchronous processing Source: https://api-portal.etoro.com/api-reference/trading--demo/submit-an-order-for-asynchronous-processing /api-reference/openapi.json post /api/v3/trading/execution/demo/orders **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` --- This endpoint allows traders to place an order. Leverage, stop-loss, and take-profit settings can be applied. Order size must use exactly one of amount, units, or contracts. For open orders the instrument must be identified by exactly one of symbol or instrumentId - providing both is rejected. A stopLossRate is required when leverage is greater than 1, when transaction is sellShort, when settlementType is realFutures, or when stopLossType is trailing. Only the buy and sellShort transactions are currently supported. A unique X-Request-Id header (GUID) is required for idempotency. Currently only orders to open a position are supported. On this v3 create path, settlementType is mandatory for non-MIT orders and must be omitted for MIT orders. A 202 response means the order was accepted for processing, not that it was executed. Confirm the outcome with GET /api/v2/trading/info/demo/orders:lookup, passing the returned orderId - or referenceId, which echoes your X-Request-Id and is the only handle you have if this response is lost. In that response, status.id 3 (Filled) and 5 (PartiallyFilled) mean the order executed; 4 (Rejected) and 10 (RejectedPartiallyFilled) carry the reason in status.errorCode and status.errorMessage; 1 (Received), 2 (Placed), 11 (WaitingForMarket) and 12 (PendingTriggeredRate) are still in flight and should be polled again. positionExecutions lists the positionId values the order produced. # Cancel pending close order Source: https://api-portal.etoro.com/api-reference/trading--real/cancel-pending-close-order /api-reference/openapi.json delete /api/v1/trading/execution/market-close-orders/{orderId} **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- This endpoint allows traders to cancel a previously placed market order for close before execution. If the order has already been processed, cancellation will not be possible. A 200 response confirms the cancellation request was received, not that the order was cancelled. Confirm with GET /api/v1/trading/info/real/close-orders/{orderId}, using the orderId of the close order you tried to cancel. If the DELETE response is lost (timeout or network error), do not resend the cancel - poll that GET endpoint with the same orderId. Units reported as executed in its positions[] array were closed before the cancel took effect; the remainder was not closed. No executed entries in positions[] means nothing was closed. Poll until statusID is terminal: 7 (CANCELED) = cancelled with nothing executed, 9 (CANCELED_PARTIALLY_FILLED) = cancelled after a partial fill (executed units in positions[]), 3 (FILLED) = fully executed before the cancel; 1, 2, 5, 6 and 11 are still pending. # Cancels an order before it is executed Source: https://api-portal.etoro.com/api-reference/trading--real/cancels-an-order-before-it-is-executed /api-reference/openapi.json delete /api/v2/trading/execution/orders/{orderId} **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- This endpoint sends a cancellation request to cancel an order before execution. An order can be cancelled if it is waiting for the market to open, or for the trigger rate to be published (MIT orders). The cancellation request may be successful, and the order is cancelled, or unsuccessful, and the order is not cancelled. This operation is idempotent when the order is already closed or cancelled. A 200 response confirms the cancellation request was accepted, not that the order was cancelled - it may already have executed. Confirm with GET /api/v2/trading/info/orders:lookup: status.id 7 (Canceled) or 9 (CanceledPartiallyFilled) means the cancellation took effect, while 6 (PendingCancel) means it is still being processed. # Check instrument trading eligibility Source: https://api-portal.etoro.com/api-reference/trading--real/check-instrument-trading-eligibility /api-reference/openapi.json post /api/v2/trading/info/eligibility **Rate limit:** 20 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- Returns per-instrument trading configuration for the authenticated account - position limits, permitted order types, stop-loss and take-profit boundaries, and available leverage by settlement type and direction. Instruments not found are listed in notFoundInstrumentIds and notFoundSymbols. At least one of instrumentIds or symbols must be supplied; the combined length must not exceed 100 instruments. This configuration changes rarely for a given instrument and account, so call it once and reuse the result for the rest of the session instead of re-querying before every order. # Close position by units Source: https://api-portal.etoro.com/api-reference/trading--real/close-position-by-units /api-reference/openapi.json post /api/v1/trading/execution/market-close-orders/positions/{positionId} **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- This endpoint allows traders to close an entire position or a portion of it at the current market rate. If `UnitsToDeduct` is provided, only the specified portion will be closed. If `UnitsToDeduct` is omitted or set to null, the full position will be closed. A 200 response means the close order was submitted, not that the position was closed. Confirm the outcome with GET /api/v1/trading/info/real/close-orders/{orderId}, using the orderID returned under orderForClose. # Create an order Source: https://api-portal.etoro.com/api-reference/trading--real/create-an-order /api-reference/openapi.json post /api/v2/trading/execution/orders **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v3/trading/execution/orders` --- This endpoint allows traders to place an order. Leverage, stop-loss, and take-profit settings can be applied. Order size must use exactly one of amount, units, or contracts. For open orders the instrument must be identified by exactly one of symbol or instrumentId - providing both is rejected. A stopLossRate is required when leverage is greater than 1, when transaction is sellShort, when settlementType is realFutures, or when stopLossType is trailing. Only the buy and sellShort transactions are currently supported. A unique X-Request-Id header (GUID) is required for idempotency. Currently only orders to open a position are supported. On this v2 create path, settlementType remains optional (stricter settlementType rules apply only on v3). A 200 response means the order was accepted for processing, not that it was executed. Confirm the outcome with GET /api/v2/trading/info/orders:lookup, passing the returned orderId - or referenceId, which echoes your X-Request-Id and is the only handle you have if this response is lost. In that response, status.id 3 (Filled) and 5 (PartiallyFilled) mean the order executed; 4 (Rejected) and 10 (RejectedPartiallyFilled) carry the reason in status.errorCode and status.errorMessage; 1 (Received), 2 (Placed), 11 (WaitingForMarket) and 12 (PendingTriggeredRate) are still in flight and should be polled again. positionExecutions lists the positionId values the order produced. # Get a filtered aggregated portfolio snapshot Source: https://api-portal.etoro.com/api-reference/trading--real/get-a-filtered-aggregated-portfolio-snapshot /api-reference/openapi.json post /api/v1/trading/info/aggregate-portfolio **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/aggregate-portfolio` --- Returns the 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. # Get account PnL and portfolio details Source: https://api-portal.etoro.com/api-reference/trading--real/get-account-pnl-and-portfolio-details /api-reference/openapi.json get /api/v1/trading/info/real/pnl **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/portfolio` - `GET /api/v2/trading/info/instrument-breakdown` --- Retrieves the real account's current portfolio, including credit, open positions, orders, mirrors, and PnL details. # Get aggregated portfolio snapshot Source: https://api-portal.etoro.com/api-reference/trading--real/get-aggregated-portfolio-snapshot /api-reference/openapi.json get /api/v1/trading/info/aggregate-portfolio **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: - `POST /api/v1/trading/info/aggregate-portfolio` --- Returns a complete snapshot of the authenticated user's investment portfolio, organized by asset. The response includes account-level balances and equity, individually held positions grouped by asset, and any copy-trading relationships the user has active. Use the instrumentIds filter to scope results to a specific set of assets, or mirrorIds to isolate specific copy-trading relationships. Account totals always reflect the full portfolio regardless of filters applied. # Get close order information and closed position details Source: https://api-portal.etoro.com/api-reference/trading--real/get-close-order-information-and-closed-position-details /api-reference/openapi.json get /api/v1/trading/info/real/close-orders/{orderId} **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/real/orders/{orderId}` - `GET /api/v2/trading/info/orders:lookup` --- Retrieves information about a close order, including its execution status and the positions that were closed as a result of the request. Use this to track the outcome of a position-closing order and identify which positions were affected. This is a read-only call and is the supported way to confirm the outcome of POST or DELETE /api/v1/trading/execution/market-close-orders/... - including when the DELETE response was lost: poll this endpoint with the same close orderId instead of resending the cancel. Executed quantity is reported per affected position in positions[] (units and amount, with occurred and rate set once that position was closed); the order-level proceeds field totals what was realized. A close order that was cancelled before anything executed has no executed entries in positions[]. Any requested units that do not appear as executed in positions[] were not closed. errorCode and errorMessage are populated when processing failed. # Get instrument breakdown Source: https://api-portal.etoro.com/api-reference/trading--real/get-instrument-breakdown /api-reference/openapi.json get /api/v2/trading/info/instrument-breakdown **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/portfolio` - `GET /api/v1/trading/info/real/pnl` --- Returns the portfolio data grouped by instrument, including per-position data, pending orders, and PnL. # Get order information and position details Source: https://api-portal.etoro.com/api-reference/trading--real/get-order-information-and-position-details /api-reference/openapi.json get /api/v2/trading/info/orders:lookup **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/real/close-orders/{orderId}` - `GET /api/v1/trading/info/real/orders/{orderId}` --- Retrieves comprehensive information about a specific order, including the order status, execution details, and all positions that were opened or closed from this order. This endpoint is essential for tracking order execution and identifying which positions were created as a result of a specific order request. The response includes detailed position information with PositionID values that can be used to query position-specific details. Provide exactly one of orderId or referenceId. # Get portfolio breakdown Source: https://api-portal.etoro.com/api-reference/trading--real/get-portfolio-breakdown /api-reference/openapi.json get /api/v1/trading/info/portfolio **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/real/pnl` - `GET /api/v2/trading/info/instrument-breakdown` --- Returns detailed portfolio information including active positions, pending orders, mirror trading details, and account balances. This endpoint provides a complete overview of the user's trading activity and current market exposure. # Get what-if trading cost breakdown Source: https://api-portal.etoro.com/api-reference/trading--real/get-what-if-trading-cost-breakdown /api-reference/openapi.json post /api/v2/trading/info/costs **Rate limit:** 20 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- Returns the markup, market spread, transaction fee, overnight fee, over-weekend fee, and tax that would apply if the supplied order were executed now. For `action: open`, exactly one of `symbol` or `instrumentId` must be provided and `leverage` must be at least 1. For `action: close`, `positionIds` must be non-empty. # List trading history Source: https://api-portal.etoro.com/api-reference/trading--real/list-trading-history /api-reference/openapi.json get /api/v1/trading/info/trade/history **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns closed trades for the authenticated account from `minDate` through the present. Keep each request's lookback to less than 1 year (maximum 1 year minus 1 day). For longer history, split the range into successive windows of at most that length (advance `minDate` per batch) and use `page` / `pageSize` within each window. # Modify stop-loss and take-profit settings on an open position Source: https://api-portal.etoro.com/api-reference/trading--real/modify-stop-loss-and-take-profit-settings-on-an-open-position /api-reference/openapi.json patch /api/v2/trading/positions/{positionId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Submits an asynchronous request to update stop-loss and/or take-profit on an open position. You can set a new stopLossRate, takeProfitRate, stopLossType, or clear either value (clearStopLoss, clearTakeProfit). At least one SL/TP-related field is required. The response returns acceptance and correlation metadata only. # Request cancellation of a pending order Source: https://api-portal.etoro.com/api-reference/trading--real/request-cancellation-of-a-pending-order /api-reference/openapi.json delete /api/v3/trading/execution/orders/{orderId} **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- This endpoint sends a cancellation request to cancel an order before execution. An order can be cancelled if it is waiting for the market to open, or for the trigger rate to be published (MIT orders). The cancellation request may be successful, and the order is cancelled, or unsuccessful, and the order is not cancelled. This operation is idempotent when the order is already closed or cancelled. A 202 response confirms the cancellation request was accepted, not that the order was cancelled - it may already have executed. Confirm with GET /api/v2/trading/info/orders:lookup: status.id 7 (Canceled) or 9 (CanceledPartiallyFilled) means the cancellation took effect, while 6 (PendingCancel) means it is still being processed. # Submit an order for asynchronous processing Source: https://api-portal.etoro.com/api-reference/trading--real/submit-an-order-for-asynchronous-processing /api-reference/openapi.json post /api/v3/trading/execution/orders **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` --- This endpoint allows traders to place an order. Leverage, stop-loss, and take-profit settings can be applied. Order size must use exactly one of amount, units, or contracts. For open orders the instrument must be identified by exactly one of symbol or instrumentId - providing both is rejected. A stopLossRate is required when leverage is greater than 1, when transaction is sellShort, when settlementType is realFutures, or when stopLossType is trailing. Only the buy and sellShort transactions are currently supported. A unique X-Request-Id header (GUID) is required for idempotency. Currently only orders to open a position are supported. On this v3 create path, settlementType is mandatory for non-MIT orders and must be omitted for MIT orders. A 202 response means the order was accepted for processing, not that it was executed. Confirm the outcome with GET /api/v2/trading/info/orders:lookup, passing the returned orderId - or referenceId, which echoes your X-Request-Id and is the only handle you have if this response is lost. In that response, status.id 3 (Filled) and 5 (PartiallyFilled) mean the order executed; 4 (Rejected) and 10 (RejectedPartiallyFilled) carry the reason in status.errorCode and status.errorMessage; 1 (Received), 2 (Placed), 11 (WaitingForMarket) and 12 (PendingTriggeredRate) are still in flight and should be polled again. positionExecutions lists the positionId values the order produced. # Execute an internal account-to-account transfer Source: https://api-portal.etoro.com/api-reference/transfer/execute-an-internal-account-to-account-transfer /api-reference/openapi.json post /api/v1/money/transfers **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Executes an internal transfer from the source account to the destination account for the authenticated customer. # Get max transferable amount Source: https://api-portal.etoro.com/api-reference/transfer/get-max-transferable-amount /api-reference/openapi.json get /api/v1/money/transferable-balance **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the maximum amount the customer may transfer from the specified source account to the specified destination account. # Get transfer by ID Source: https://api-portal.etoro.com/api-reference/transfer/get-transfer-by-id /api-reference/openapi.json get /api/v1/money/transfers/{transferId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the TransferLookupResult wrapper containing exactly one TransferLookupResponse matching the server transferId. Returns 404 when the transfer does not exist or is not visible to the authenticated customer. # List transfer fees Source: https://api-portal.etoro.com/api-reference/transfer/list-transfer-fees /api-reference/openapi.json get /api/v1/money/transfer-fee-configurations **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns transfer fee configuration for the authenticated customer as a list of rows, one per source/destination account type route. # List transfer limits Source: https://api-portal.etoro.com/api-reference/transfer/list-transfer-limits /api-reference/openapi.json get /api/v1/money/transfer-limits **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns transfer amount limits for each allowed combination of source and destination account types. # List transfers by reference ID Source: https://api-portal.etoro.com/api-reference/transfer/list-transfers-by-reference-id /api-reference/openapi.json get /api/v1/money/transfers:lookup **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a list of transfers for the authenticated customer, keyed by the client requestReferenceId query parameter. # Transfer eligibility (source and destination accounts) Source: https://api-portal.etoro.com/api-reference/transfer/transfer-eligibility-source-and-destination-accounts /api-reference/openapi.json get /api/v1/money/transfer-eligibility **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the full eligibility graph for the authenticated customer: for each source account, the destination accounts allowed for transfers. # Get asset allocation history Source: https://api-portal.etoro.com/api-reference/user-stats/get-asset-allocation-history /api-reference/openapi.json get /api/v2/portfolios/{username}/assets/history **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a daily asset-allocation breakdown for a publicly visible portfolio. Data is only available for investors who have not opted out — opted-out portfolios return 403 for third-party callers. Callers must authenticate with their own token. Use period OR minDate+maxDate (mutually exclusive). All ratio fields use decimal fraction format: 0.5 = 50%. # Get investor gain time-series Source: https://api-portal.etoro.com/api-reference/user-stats/get-investor-gain-time-series /api-reference/openapi.json get /api/v2/portfolios/{username}/gain/{granularity} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a gain time-series scoped by date range, count, or a combination of one date and a count. Gain values are decimal fractions: 0.06 = 6%, -0.03 = -3%. # Get market exposure history Source: https://api-portal.etoro.com/api-reference/user-stats/get-market-exposure-history /api-reference/openapi.json get /api/v2/portfolios/{username}/exposure/history **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns daily directional exposure breakdown per instrument for a publicly visible portfolio. Data is only available for investors who have not opted out - opted-out portfolios return 403 for third-party callers. Callers must authenticate with their own token. Use period OR minDate+maxDate (mutually exclusive). All values are decimal fractions of total daily investment: 0.5 = 50%. Simulated positions are excluded. # Get portfolio copier stats Source: https://api-portal.etoro.com/api-reference/user-stats/get-portfolio-copier-stats /api-reference/openapi.json get /api/v2/portfolios/{username}/copiers **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the investor's live copier count and assets-under-management tier for a public username. Requires `etoro-public:user-info:read`. # Get user daily performance Source: https://api-portal.etoro.com/api-reference/users-info/get-user-daily-performance /api-reference/openapi.json get /api/v1/user-info/people/{username}/daily-gain **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Provides detailed performance analytics including daily gains, cumulative returns, and period-specific metrics within a specified date range. Supports various time-based analyses and performance reporting requirements. # Get user live portfolio Source: https://api-portal.etoro.com/api-reference/users-info/get-user-live-portfolio /api-reference/openapi.json get /api/v1/user-info/people/{username}/portfolio/live **Rate limit:** 60 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. # Get user performance history Source: https://api-portal.etoro.com/api-reference/users-info/get-user-performance-history /api-reference/openapi.json get /api/v1/user-info/people/{username}/gain **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns comprehensive historical monthly and yearly performance data including gain percentages, risk-adjusted returns, and detailed trading statistics. This endpoint provides both aggregated and time-series performance metrics. # Get user profile and account summary Source: https://api-portal.etoro.com/api-reference/users-info/get-user-profile-and-account-summary /api-reference/openapi.json get /api/v1/user-info/people **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns detailed user profile information including account status, verification levels, biographical data, and associated metadata. This endpoint aggregates essential user information from multiple sources to provide a complete user profile overview. # Get user trade info Source: https://api-portal.etoro.com/api-reference/users-info/get-user-trade-info /api-reference/openapi.json get /api/v1/user-info/people/{username}/tradeinfo **Rate limit:** 60 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. # Search users Source: https://api-portal.etoro.com/api-reference/users-info/search-users /api-reference/openapi.json get /api/v1/user-info/people/search **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Powerful search platform that enables advanced user discovery with comprehensive filtering capabilities. Supports complex queries across multiple dimensions including performance metrics, risk profiles, investment patterns, and account characteristics. Ideal for identifying users based on specific trading behaviors and performance criteria. # Add items to watchlist Source: https://api-portal.etoro.com/api-reference/watchlists/add-items-to-watchlist /api-reference/openapi.json post /api/v1/watchlists/{watchlistId}/items **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/newasdefault-watchlist` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Adds new items to an existing watchlist. # Change watchlist rank Source: https://api-portal.etoro.com/api-reference/watchlists/change-watchlist-rank /api-reference/openapi.json put /api/v1/watchlists/rank/{watchlistId} **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/newasdefault-watchlist` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Updates the display rank of a watchlist. # Create a new watchlist Source: https://api-portal.etoro.com/api-reference/watchlists/create-a-new-watchlist /api-reference/openapi.json post /api/v1/watchlists **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/newasdefault-watchlist` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Creates a new watchlist for the authenticated user with the specified name and type. # Create default watchlist with selected items Source: https://api-portal.etoro.com/api-reference/watchlists/create-default-watchlist-with-selected-items /api-reference/openapi.json post /api/v1/watchlists/default-watchlist/selected-items **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/newasdefault-watchlist` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Creates a default watchlist populated with the specified items. # Create watchlist and set as default Source: https://api-portal.etoro.com/api-reference/watchlists/create-watchlist-and-set-as-default /api-reference/openapi.json post /api/v1/watchlists/newasdefault-watchlist **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Creates a new watchlist and immediately sets it as the user's default watchlist. # Delete watchlist Source: https://api-portal.etoro.com/api-reference/watchlists/delete-watchlist /api-reference/openapi.json delete /api/v1/watchlists/{watchlistId} **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/newasdefault-watchlist` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Removes a watchlist and all its items. # Get curated lists Source: https://api-portal.etoro.com/api-reference/watchlists/get-curated-lists /api-reference/openapi.json get /api/v1/curated-lists **Rate limit:** 60 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- Retrieves curated investment lists available to the authenticated user. # Get default watchlist items Source: https://api-portal.etoro.com/api-reference/watchlists/get-default-watchlist-items /api-reference/openapi.json get /api/v1/watchlists/default-watchlists/items **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/watchlists` - `GET /api/v1/watchlists/public/{userId}` - `GET /api/v1/watchlists/public/{userId}/{watchlistId}` - `GET /api/v1/watchlists/{watchlistId}` --- Retrieves items from user's default watchlists with optional pagination. # Get market recommendations Source: https://api-portal.etoro.com/api-reference/watchlists/get-market-recommendations /api-reference/openapi.json get /api/v1/market-recommendations/{itemsCount} **Rate limit:** 60 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- Retrieves personalized market recommendations for the authenticated user. # Get single public watchlist Source: https://api-portal.etoro.com/api-reference/watchlists/get-single-public-watchlist /api-reference/openapi.json get /api/v1/watchlists/public/{userId}/{watchlistId} **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/watchlists` - `GET /api/v1/watchlists/default-watchlists/items` - `GET /api/v1/watchlists/public/{userId}` - `GET /api/v1/watchlists/{watchlistId}` --- Retrieves a specific public watchlist from a user. # Get single watchlist Source: https://api-portal.etoro.com/api-reference/watchlists/get-single-watchlist /api-reference/openapi.json get /api/v1/watchlists/{watchlistId} **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/watchlists` - `GET /api/v1/watchlists/default-watchlists/items` - `GET /api/v1/watchlists/public/{userId}` - `GET /api/v1/watchlists/public/{userId}/{watchlistId}` --- Retrieves a specific watchlist with its items using pagination. # Get user watchlists Source: https://api-portal.etoro.com/api-reference/watchlists/get-user-watchlists /api-reference/openapi.json get /api/v1/watchlists **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/watchlists/default-watchlists/items` - `GET /api/v1/watchlists/public/{userId}` - `GET /api/v1/watchlists/public/{userId}/{watchlistId}` - `GET /api/v1/watchlists/{watchlistId}` --- Retrieves all watchlists for the authenticated user with optional pagination and built-in watchlist management. # Get user watchlists (BFF V2) Source: https://api-portal.etoro.com/api-reference/watchlists/get-user-watchlists-bff-v2 /api-reference/openapi.json post /api/v2/watchlists **Rate limit:** 60 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- Retrieves the authenticated user's watchlists as a BFF component response (V2 facade). The request body selects the userWatchlists component and its params. # Get user's public watchlists Source: https://api-portal.etoro.com/api-reference/watchlists/get-users-public-watchlists /api-reference/openapi.json get /api/v1/watchlists/public/{userId} **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/watchlists` - `GET /api/v1/watchlists/default-watchlists/items` - `GET /api/v1/watchlists/public/{userId}/{watchlistId}` - `GET /api/v1/watchlists/{watchlistId}` --- Retrieves all public watchlists for a specific user. # Remove items from watchlist Source: https://api-portal.etoro.com/api-reference/watchlists/remove-items-from-watchlist /api-reference/openapi.json delete /api/v1/watchlists/{watchlistId}/items **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/newasdefault-watchlist` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Removes specified items from a watchlist. # Rename watchlist Source: https://api-portal.etoro.com/api-reference/watchlists/rename-watchlist /api-reference/openapi.json put /api/v1/watchlists/{watchlistId} **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/newasdefault-watchlist` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Updates the name of an existing watchlist. # Set watchlist as default Source: https://api-portal.etoro.com/api-reference/watchlists/set-watchlist-as-default /api-reference/openapi.json put /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId} **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/newasdefault-watchlist` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}/items` --- Sets the specified watchlist as the user's default watchlist. # Update items in watchlist Source: https://api-portal.etoro.com/api-reference/watchlists/update-items-in-watchlist /api-reference/openapi.json put /api/v1/watchlists/{watchlistId}/items **Rate limit:** 20 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: - `DELETE /api/v1/watchlists/{watchlistId}` - `DELETE /api/v1/watchlists/{watchlistId}/items` - `POST /api/v1/watchlists` - `POST /api/v1/watchlists/default-watchlist/selected-items` - `POST /api/v1/watchlists/newasdefault-watchlist` - `POST /api/v1/watchlists/{watchlistId}/items` - `PUT /api/v1/watchlists/rank/{watchlistId}` - `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` - `PUT /api/v1/watchlists/{watchlistId}` --- Updates existing items in a watchlist (rank, etc.). # SKILL.md Source: https://api-portal.etoro.com/core/ai-agents/etoro-skill Agent Skill for accessing the etoro API This page provides the etoro [Agent Skill](https://agentskills.io). Install it in any skill-capable coding agent to operate the etoro Public API through the MCP server. ## Usage Send this prompt to your agent to install the skill: ``` Please install the skill at https://mcp.public-api.etoro.com/skill and follow the instructions. ``` ## What this skill enables * Discover live Public API routes and read their specs * Market data access (instruments, prices, historical data) * Portfolio and trading information * Social and feed features * Trade execution (demo and real, based on key permissions) ## Skill details * Name: `etoro-public-api-operations` * Skill URL: [https://mcp.public-api.etoro.com/skill](https://mcp.public-api.etoro.com/skill) * MCP server: `https://mcp.public-api.etoro.com` * Authentication: `x-api-key` and `x-user-key`, or an OAuth Bearer token # Core API Changelog Source: https://api-portal.etoro.com/core/changelog New endpoints, capabilities, and breaking changes in the etoro Public API. What changed in the etoro Core API, newest first. Each entry lists the API version the change shipped in, so you can line it up against the version shown in the Core API reference. The Partners API has its own [changelog](/partners/changelog). **October 12, 2026** ## Price alert filters Price alert queries can filter by alert ID, instrument ID, and symbol. * `GET /api/v1/price-alerts` — `alertIds`, `instrumentIds`, and `symbols` added **September 29, 2026** ## Price candles You can now fetch price candles for an instrument and see where candle data is available. * `GET /api/v1/data/instruments/{instrumentId}/candles` — get price candles for an instrument * `GET /api/v1/data/instruments/{instrumentId}/candles/coverage` — get where price candles exist for an instrument **September 9, 2026** ## Closed position event history You can now fetch closed position event history counts for the caller. * `GET /api/v1/data/positions/closed-events/history` — get closed position event history counts **September 6, 2026** ## StockBack promo status You can now check the caller’s StockBack/Cashback promo status. * `GET /api/v1/data/stockback/promo-status` — get StockBack/Cashback promo status ## Instrument search and rates You can now search securities by ID, symbol, or free-text query, and retrieve bid/ask rates. * `GET /api/v2/market-data/instruments` — search for securities by ID or symbol * `GET /api/v2/market-data/instruments/search` — search instruments by free-text query * `GET /api/v2/market-data/rates` — retrieve bid/ask rates for one or more instruments **August 25, 2026** ## Filtered aggregated portfolio You can now request a filtered aggregated portfolio snapshot. The existing GET endpoints also accept `dailyCutoffUtc` and `pnlLevel`. * `POST /api/v1/trading/info/aggregate-portfolio` — get a filtered aggregated portfolio snapshot, with a matching demo endpoint under `/api/v1/trading/info/demo/aggregate-portfolio` * `GET /api/v1/trading/info/aggregate-portfolio` and `GET /api/v1/trading/info/demo/aggregate-portfolio` — `dailyCutoffUtc` and `pnlLevel` added **August 23, 2026** ## Asynchronous order execution You can now submit orders for asynchronous processing and request cancellation of pending orders. * `POST /api/v3/trading/execution/orders` — submit an order for asynchronous processing * `DELETE /api/v3/trading/execution/orders/{orderId}` — request cancellation of a pending order Both have matching demo endpoints under `/api/v3/trading/execution/demo`. ## Demo Copy Trading Copy Trading is available again on demo accounts. You can start copying an investor, adjust an existing copy, check eligibility, poll operation outcomes, and close or detach a copy under `/api/v2/trading/copy/demo`. * `POST /api/v2/trading/copy/demo` — start copying an investor, or adjust an existing copy * `POST /api/v2/trading/copy/demo/eligibility` — pre-check whether a copy registration would be allowed * `DELETE /api/v2/trading/copy/demo` and `POST /api/v2/trading/copy/demo/close` — close or detach a copy relationship * `GET /api/v2/trading/copy/demo/{referenceId}` — poll a copy operation's outcome ## User watchlists You can now fetch a user’s watchlists. * `POST /api/v2/watchlists` — get user watchlists **August 18, 2026** ## Instrument breakdown You can now fetch a per-instrument breakdown of a portfolio’s trading activity, including positions, orders, mirrors, and close-position detail. * `GET /api/v2/trading/info/instrument-breakdown` — real accounts, with a matching demo endpoint under `/api/v2/trading/info/demo/instrument-breakdown` ## Sub-account balances Balance and balance-history queries can include sub-accounts via the `includeSubAccounts` parameter. `includeZeroBalances` is no longer accepted on the single-account balance endpoint. * `GET /api/v1/balances`, `GET /api/v1/balances/history`, `GET /api/v1/balances/{accountType}`, `GET /api/v1/balances/{accountType}/history`, and `GET /api/v1/balances/{accountType}/{accountId}/history` — `includeSubAccounts` added * `GET /api/v1/balances/{accountType}/{accountId}` — `includeZeroBalances` removed ## Application key data You can now fetch key data for a registered application. * `GET /api/v1/keydata/{application}` — get application key data ## Demo Copy Trading endpoints withdrawn The demo Copy Trading endpoints under `/api/v2/trading/copy/demo` have been removed from the API. The live endpoints under `/api/v2/trading/copy` are unaffected. ## v1 trading execution and info endpoints withdrawn The v1 endpoints for placing and canceling market and limit orders, looking up orders by ID, and checking trading eligibility have been removed on both real and demo accounts. ## Social feed endpoints withdrawn The social feed endpoints for reading instrument and user feeds, creating posts, and commenting have been removed. ## Agent portfolio endpoints withdrawn The agent portfolio endpoints for creating portfolios and managing user tokens have been removed. **July 29, 2026** ## Copy Trading API You can now build copy trading into your own application. The new endpoints let you start copying an investor, add or remove funds from an existing copy, and stop copying — either keeping the copied positions open or closing them out. * `POST /api/v2/trading/copy` — start copying an investor, or adjust the amount allocated to a copy you already have * `POST /api/v2/trading/copy/eligibility` — dry run the same request first to check whether the copy would be allowed, without changing anything * `DELETE /api/v2/trading/copy` and `POST /api/v2/trading/copy/close` — stop copying, with the option to close or detach the copied positions * `GET /api/v2/trading/copy/{referenceId}` — copy operations are asynchronous, so poll this with the reference ID you get back to find out how it finished Every endpoint has a matching demo version under `/api/v2/trading/copy/demo`, so you can build and test the whole flow on a demo account before going near real money. ## Rotate your OAuth client secret Applications registered through the SSO endpoints can now replace their client secret without re-registering the application: `POST /api/v1/sso/applications/{clientId}/client-secret`. **July 27, 2026** ## Order lookup is supported again `GET /api/v1/trading/info/real/orders/{orderId}` and its demo counterpart are no longer deprecated. They now return the same modern order-information payload as the v2 lookup, covering the order and its resulting position. If you moved off these endpoints when they were marked deprecated, you can move back — or stay on `GET /api/v2/trading/info/orders:lookup`, which is unaffected. **July 22, 2026** ## Crypto withdrawal endpoints withdrawn The trading-account crypto withdrawal endpoints under `/api/v1/money/withdraw/crypto` were removed from the API a week after first appearing in the reference. Withdrawals are not currently available through the public API. **July 14, 2026** ## Money movement and OAuth apps are now documented These endpoints were already live on the API, but our documentation pipeline had been filtering them out. The reference now publishes the full API surface, so several capabilities became discoverable for the first time: **Internal transfers** — move money between your own accounts and understand the constraints before you do: * `POST /api/v1/money/transfers` — execute an account-to-account transfer * `GET /api/v1/money/transferable-balance` — how much you can actually move * `GET /api/v1/money/transfer-eligibility`, `/transfer-limits`, `/transfer-fee-configurations` — which account pairs are allowed, the limits that apply, and what it costs * `GET /api/v1/money/transfers/{transferId}` and `/transfers:lookup` — track a transfer after you send it **OAuth applications** — register and manage your own OAuth application so other etoro users can authorize it: `GET`/`POST`/`PUT`/`DELETE /api/v1/sso/applications`, plus `GET /api/v1/sso/scopes` to see which scopes you can request. **Top assets** — `GET /api/v1/impressions/topassets/user/{gcid}` returns the assets a user engages with most. **July 9, 2026** ## Investor rankings A full ranking API for discovering and comparing investors, aimed at anyone building leaderboards, screeners, or copy-trading discovery: * `GET /api/v2/portfolios/rankings` — paginated investor rankings * `GET /api/v2/portfolios/rankings/presets` and `/presets/{type}` — ready-made rankings instead of building your own filters * `GET /api/v2/portfolios/rankings/tags` and `/summary` — the available ranking tags, and the ranking universe aggregated by sector or industry * `GET /api/v2/portfolios/{username}/rankings` and `POST /api/v2/portfolios/rankings/multiple` — a single investor's row, or many at once ## Portfolio search `GET /api/v1/portfolios/search` searches trader portfolios and Smart Portfolios by free-text query. ## Close-order details `GET /api/v1/trading/info/real/close-orders/{orderId}` (and its demo equivalent) returns the details of a close order and the position it closed, so you can confirm exit prices and realized results without reconciling against your portfolio. **June 23, 2026** ## Cash accounts pulled back The cash-account endpoints under `/api/v1/money/accounts/cash` — creation, eligibility, status, and listing — were removed two weeks after being introduced, along with the generic `POST`/`DELETE /api/v1/sub-accounts` pair. Sub-account management continues to work through the `/api/v1/sub-accounts/me/accounts` and `/api/v1/sub-accounts/etoro-trading` endpoints introduced the week before. **June 18, 2026** ## Edit stop-loss and take-profit on open positions Previously, changing the risk parameters on a live position meant closing and reopening it. Now you can update them in place: * `PATCH /api/v2/trading/positions/{positionId}` (real) and `PATCH /api/v2/trading/demo/positions/{positionId}` (demo) ## Sub-accounts Run separate accounts under one login, each with its own API credentials — useful for isolating strategies, clients, or environments: * `GET`/`POST /api/v1/sub-accounts/me/accounts` — list and create sub-accounts * `GET`/`POST`/`PATCH`/`DELETE /api/v1/sub-accounts/etoro-trading/user-tokens` — issue, list, update, and revoke API tokens scoped to a sub-account, with `GET .../user-tokens/scopes` listing what you can grant * `POST /api/v1/sub-accounts/etoro-trading/money-transfers` — move funds between sub-accounts **June 17, 2026** ## A more readable API reference Endpoint summaries across market data, trading, portfolios, and watchlists were rewritten to be short and scannable, so the sidebar and search results tell you what an endpoint does at a glance. ## New MCP server URL The etoro MCP server moved to `https://mcp.public-api.etoro.com`. The [vibe coding guides](/core/vibe-code/cursor) and skill install instructions were updated. Update any existing MCP configuration pointing at the old URL. > [!NOTE] > > The first-generation social endpoints — `GET /api/v1/feeds/user/{userId}`, `GET /api/v1/feeds/instrument/{marketId}`, `POST /api/v1/feeds/post`, and `POST /api/v1/reactions/{postId}/comment` — were deprecated in favor of the Posts and Feeds endpoints released on June 9. **June 9, 2026** ## The largest release of the period Roughly 70 endpoints landed at once, opening up several product areas that had no API coverage before. ### Social A complete social API, replacing the read-only feed endpoints that came before it. You can now build a full etoro social experience: * **Posts** — create, edit, and delete posts; pin them to a profile, save them, follow them, and share them * **Polls** — create poll posts and cast or withdraw votes * **Comments and replies** — full threading, with create, edit, and delete on both levels * **Likes** — like and unlike posts, comments, and replies * **Attachments** — `POST /api/v1/attachments` uploads media to attach to a post * **Feeds** — personalized *For You*, *Following*, *News*, *Saved*, per-user, per-instrument, and pinned feeds ### Balances A dedicated balances API that answers "how much do I have, and where" without parsing the portfolio response: aggregated balances, balances by account type, balances for a specific account, and historical snapshots of all three under `/api/v1/balances`. ### Price alerts Create, list, update, and delete price alerts programmatically via `/api/v1/price-alerts`. ### Smarter trading decisions * `POST /api/v2/trading/info/costs` — a what-if cost breakdown for opening or closing a position, so you can show users the full cost before they commit * `POST /api/v2/trading/info/eligibility` — check trading permissions, limits, and available leverage for several instruments at once * `GET /api/v1/trading/info/aggregate-portfolio` — a portfolio snapshot with positions already aggregated by instrument and copy relationship, instead of a flat position list you have to roll up yourself ### Investor statistics `/api/v2/portfolios/{username}` gained asset allocation history, market exposure history, investor gain time-series by granularity, and current copier count with AUM tier. ### Other additions Club dashboard data (`GET /api/v1/clubs`) and a v2 of the Agent Portfolios endpoints with a `user-tokens/scopes` endpoint for discovering grantable scopes. **May 31, 2026** ## One order endpoint instead of six Order placement was consolidated into a single unified endpoint. Instead of choosing between separate endpoints for market vs. limit orders and by-amount vs. by-units sizing, you send one request and specify what you want: * `POST /api/v2/trading/execution/orders` — create any order type, on real or demo * `DELETE /api/v2/trading/execution/orders/{orderId}` — cancel before execution * `GET /api/v2/trading/info/orders:lookup` — order information and position details The [market orders guide](/core/guides/market-orders) covers the new flow. > [!WARNING] > > **Deprecation:** the twelve v1 order endpoints under `/api/v1/trading/execution/market-open-orders` and `/api/v1/trading/execution/limit-orders` were deprecated and moved to a **Deprecated** section at the bottom of the API reference. They continue to work, but new integrations should use the v2 endpoint. ## Also in this release * **In-app notifications** — `GET /api/v1/notifications/messages` and `PATCH` to mark all as read * **Trading history** — `GET /api/v1/trading/info/trade/demo/history` lists historical trades **March 17, 2026** ## Rate limits documented The [rate limits guide](/core/getting-started/rate-limits) explains the quotas that apply to each category of endpoint, how the rolling window works, and how to handle `429` responses. Per-endpoint limits also now appear in the description of each operation in the API reference. The [authentication guide](/core/getting-started/authentication) gained a note clarifying the difference between real and demo environments. **March 15, 2026** ## Agent Portfolios Agent Portfolios let you carve out an isolated portfolio and issue scoped API tokens against it — the foundation for letting an AI agent or a third-party strategy trade on your behalf without handing over your whole account: * `GET`/`POST`/`DELETE /api/v1/agent-portfolios` — list, create, and delete agent portfolios * `POST`/`PATCH`/`DELETE /api/v1/agent-portfolios/{agentPortfolioId}/user-tokens` — issue, update, and revoke tokens for a portfolio **March 12, 2026** ## Portfolio calculation guides Three guides explaining how to derive the numbers users expect to see, from the values the API returns: * [Calculate total invested](/core/guides/calculate-total-invested) * [Calculate profit and loss](/core/guides/calculate-profit-loss) * [Calculate equity](/core/guides/calculate-equity) The [available cash guide](/core/guides/calculate-available-cash) was also updated to clarify how available cash and equity relate. **March 9, 2026** ## Identify the authenticated user `GET /api/v1/me` returns the profile of whoever owns the credentials making the request — a simple way to confirm which account a token belongs to before acting on it. **February 19, 2026** ## Available cash guide [Calculate available cash](/core/guides/calculate-available-cash) explains how to determine how much a user can actually deploy, including how the USD balance factors in. **February 5, 2026** ## etoro skill for AI agents The [etoro skill](/core/ai-agents/etoro-skill) gives coding agents a packaged understanding of the API — endpoints, auth, and conventions — so they can write working etoro integrations without you pasting documentation into a prompt. **February 4, 2026** ## Order information and position details `GET /api/v1/trading/info/real/orders/{orderId}` and its demo counterpart return an order together with the position it produced, so you can confirm an execution without polling your whole portfolio. ## Comment on posts `POST /api/v1/reactions/{postId}/comment` adds a comment to a post — the first write capability on the social side of the API. # Authentication Source: https://api-portal.etoro.com/core/getting-started/authentication How to authenticate to the etoro API Access to the API requires two specific keys to ensure secure interaction between the application and the user account. * **Public API Key**: Identifies the application. * **User Key**: Identifies your user account. ## How to get the keys To access your own account data, you must generate a user-specific key through the etoro platform. Please follow these steps: ### 1. Navigate to Settings > Trading Log in to your etoro account. In the sidebar menu, click on **Settings**. From the settings menu, select the **Trading** option. ![Settings > Trading](https://mintcdn.com/etoro-6fc30280/g0Mti1rBGaHVyfWd/images/api-reference/authentication-1.png?fit=max\&auto=format\&n=g0Mti1rBGaHVyfWd\&q=85\&s=db514689f5770342dd3877108ea79655) ![Trading > API Key Management](https://mintcdn.com/etoro-6fc30280/g0Mti1rBGaHVyfWd/images/api-reference/authentication-2.png?fit=max\&auto=format\&n=g0Mti1rBGaHVyfWd\&q=85\&s=5b9b22599e5ef61f280106303be41263) ### 2. Create a New Key Scroll to the "API Key Management" section and click the **Create New Key** button. ![API Key Management > Create New Key](https://mintcdn.com/etoro-6fc30280/g0Mti1rBGaHVyfWd/images/api-reference/authentication-3.png?fit=max\&auto=format\&n=g0Mti1rBGaHVyfWd\&q=85\&s=d740a3764f43cc534fa79d88b9a2f91e) ### 3. Configure Key Permissions A "Key Generation" modal will appear. Complete the following fields: * **Key Name:** Enter any name you wish to identify this key. * **Environment:** Select either "Demo" or "Real". Each key can only be used for one environment. If you need to use both, please create two keys. * **Permissions:** Select "Read" if you only need to access your portfolio data. Select "Write" if you need to execute trades. * **Security:** You may optionally configure an "IPS Whitelist" or set an "Expiration Date". Click **Generate Key** to proceed. ![API Key Management > Generate Key](https://mintcdn.com/etoro-6fc30280/fF50SDJhiG_GpAWR/images/api-reference/authentication-4.png?fit=max\&auto=format\&n=fF50SDJhiG_GpAWR\&q=85\&s=3506dae12d559629282130eb18d80320) ### 4. Verify Identity For security, you will be prompted to enter a verification code sent to your mobile device. > **Tip:** If you do not receive the SMS code after approximately 10 seconds, use the "Try via Phone Call" option. ![API Key Management > Verify Identity](https://mintcdn.com/etoro-6fc30280/g0Mti1rBGaHVyfWd/images/api-reference/authentication-5.png?fit=max\&auto=format\&n=g0Mti1rBGaHVyfWd\&q=85\&s=164b6c3a909ec0d7e0641750bfe1ca83) ### 5. Copy Your Credentials Once verified, your new key (the ETORO\_USER\_KEY) will appear in the "Generated Keys" list at the bottom of the screen. Click the **Copy** icon on the right side of the key field to copy the string to your clipboard. ![API Key Management > Copy Key](https://mintcdn.com/etoro-6fc30280/g0Mti1rBGaHVyfWd/images/api-reference/authentication-6.png?fit=max\&auto=format\&n=g0Mti1rBGaHVyfWd\&q=85\&s=e83c82c35bb20aa07cfae26efc49ac1d) ## Header Format All requests must include the following headers: * **x-request-id**: A unique UUID for the request. * **x-api-key**: Your Public API Key. * **x-user-key**: Your User Key. ## Example Request ```bash theme={null} curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \ -H "x-request-id: " \ -H "x-api-key: " \ -H "x-user-key: " ``` # Rate Limits Source: https://api-portal.etoro.com/core/getting-started/rate-limits Understand the rate limits applied to the etoro Public API to ensure smooth and reliable integration. To ensure platform stability and fair usage across all applications, the etoro Public API enforces rate limits on its endpoints. Limits are tracked per user key and are measured over a 1-minute rolling window. If you exceed these limits, the API will return a `429 Too Many Requests` status code. We recommend implementing standard retry logic with exponential backoff to handle these gracefully. ## Standard Rate Limits Rate limits generally fall into two categories depending on the performance impact of the request: standard data retrieval (Read) and transactional/heavy operations (Write & Execution). ### 60 Requests per Minute Most standard `GET` requests for retrieving data allow up to **60 requests per minute**. This includes: * **Market Data**: Retrieving instrument rates, historical candles, search, and exchanges. * **Portfolio & Account Info**: Fetching Real and Demo portfolio details, PnL, and general user info. * **Social & Feeds (Read)**: Reading user feeds, instrument feeds, curated lists, and market recommendations. * **Watchlists (Read)**: Retrieving public, private, and default watchlists. ### 20 Requests per Minute Endpoints that execute trades, modify state, or run heavier queries are limited to **20 requests per minute**. This includes: * **Trading Execution**: Opening, closing, or canceling orders in both Real and Demo environments (`POST` and `DELETE` requests). * **Watchlist Management**: Creating, updating, or deleting watchlists and their items (`POST`, `PUT`, `DELETE` requests). * **Social & Feeds (Write)**: Creating new feed posts or posting reactions/comments (`POST` requests). * **User Trade Info**: Fetching detailed historical trade info for a specific user profile. > [!NOTE] > > **Best Practice**: Whenever possible, cache non-volatile data locally (such as Instrument IDs or basic Exchange data) to minimize unnecessary API calls and preserve your rate limit quota for real-time operations like trade execution. # SSO with OAuth 2.0 Source: https://api-portal.etoro.com/core/getting-started/sso-oauth Sign etoro users in to your application with OAuth 2.0 and OpenID Connect, and call the API on their behalf. The [API key pair](/core/getting-started/authentication) authenticates you as yourself: it is generated in your own etoro settings and acts on your own account. This guide covers the other case — an application that signs **other etoro users** in and acts on their behalf, with their consent. Use this flow whenever your application has users of its own: a trading tool, a portfolio dashboard, an agent, a partner platform. The user authenticates with etoro rather than with you, your application never handles their etoro password, and the access your application receives is limited to the scopes the user consented to and revocable by them at any time. > [!NOTE] > > This page documents the authentication and authorization flow, which is common to every integration. Partner-specific steps that follow it — issuing a long-lived non-interactive token, associating a partner account with an etoro account, and reporting events back to etoro — are covered in the [Partner integration flow](/partners/integration). ## Standards conformance This is not an etoro-specific handshake. etoro's SSO service is a conformant OpenID Connect 1.0 provider built on the OAuth 2.0 authorization framework. It is therefore implemented with the same client library used for any other identity provider: the library is configured with the issuer `https://www.etoro.com` and derives its endpoints and signing keys from the discovery document. | What you are implementing | Specification | | - | - | | Authorization code flow, token endpoint, refresh tokens | OAuth 2.0 — [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) | | ID token, `sub`, `nonce`, pairwise subject identifiers | [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) | | The `.well-known/openid-configuration` document | [OpenID Connect Discovery 1.0](https://openid.net/specs/openid-connect-discovery-1_0.html) | | PKCE (`code_challenge`, `code_verifier`) | [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) | | JWKS key set and JWT validation | [RFC 7517](https://datatracker.ietf.org/doc/html/rfc7517), [RFC 7519](https://datatracker.ietf.org/doc/html/rfc7519) | | Bearer token usage | [RFC 6750](https://datatracker.ietf.org/doc/html/rfc6750) | | Token revocation | [RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009) | | Token exchange (per-client, where enabled) | [RFC 8693](https://datatracker.ietf.org/doc/html/rfc8693) | etoro recommends the use of an established, certified client library — for example `openid-client` or `jose` on Node.js, `Microsoft.AspNetCore.Authentication.OpenIdConnect` on .NET, Spring Security OAuth2 Client on Java, or Authlib on Python. A custom protocol implementation is a common source of authentication defects, and none of the steps described below require one. > [!WARNING] > > **etoro does not release personal information about its users to third-party applications.** No email address, name, phone number, date of birth, or address is returned to your application unless that specific data sharing has been approved by etoro for your integration. > > Applications must therefore be designed on a token-only basis: identity is the pseudonymous `sub` claim, and authorization is the scope set on the token. See [Identity and personal data](#identity-and-personal-data). ## Discovery document etoro publishes a standard OpenID Connect discovery document. Endpoint URLs and signing keys should be resolved from it at runtime rather than hardcoded: signing keys are rotated, and the document is the authoritative source. | Resource | URL | | - | - | | OpenID Connect discovery (`.well-known`) | `https://www.etoro.com/.well-known/openid-configuration` | | JWKS (ID token signing keys) | `https://www.etoro.com/.well-known/jwks.json` | | Authorization endpoint | `https://www.etoro.com/sso` | | Token endpoint | `https://www.etoro.com/api/sso/v1/token` | | Token revocation endpoint | `https://www.etoro.com/api/sso/v1/token/revoke` | | UserInfo endpoint | `https://www.etoro.com/api/sso/v1/userinfo` | ```bash theme={null} curl -s https://www.etoro.com/.well-known/openid-configuration curl -s https://www.etoro.com/.well-known/jwks.json ``` What the discovery document commits etoro to, and what it therefore requires of you: **issuer** `https://www.etoro.com` The exact string your ID token validation must require in the `iss` claim. **response\_types\_supported** `code` Authorization code flow only. The implicit and hybrid flows are not offered — never request `token` or `id_token` as a response type. **code\_challenge\_methods\_supported** `S256` PKCE with SHA-256. `plain` is not supported. **id\_token\_signing\_alg\_values\_supported** `RS256` ID tokens are signed with RS256. Reject any token whose header declares a different algorithm, and never accept `alg: none`. **subject\_types\_supported** `pairwise` The `sub` claim is a **pairwise pseudonymous identifier** — it is specific to your client. The same etoro user presents a different `sub` to a different application, and it carries no personal information. This is the identifier to store. **grant\_types\_supported** `authorization_code, refresh_token, client_credentials, urn:ietf:params:oauth:grant-type:token-exchange` Which of these your client may use is decided per application at registration. **token\_endpoint\_auth\_methods\_supported** `client_secret_basic, client_secret_post, private_key_jwt, none` A confidential client — any application with a backend — must authenticate. Use `client_secret_basic` or `private_key_jwt`. `none` exists for public clients that cannot hold a secret. ## Prerequisites **1. Register your application** Registration produces a `clientId` and a `clientSecret`, and establishes the redirect URIs and the scope set the application may request. Register through the [etoro Builders portal](https://builders.etoro.com/app-registration), or programmatically with `POST /api/v1/sso/applications`. The `clientSecret` is returned **exactly once**, at creation. It is never readable again — only replaceable, via `POST /api/v1/sso/applications/{clientId}/client-secret`, which invalidates the previous secret immediately with no overlap window. **2. Pick your scopes** `GET /api/v1/sso/scopes` returns the catalog of scopes the client may request. Request the narrowest set that completes the intended user journey. Each endpoint in the [API reference](/) lists the scopes that grant access to it, and a token requires only **one** of the alternatives listed on an operation, not all of them. **3. Register your redirect URIs** Each redirect URI is matched exactly at authorization time. Register the HTTPS callback served by your backend, rather than a URL that renders the authorization code into a browser page. ## Step 1 — Redirect the user to etoro Generate a distinct PKCE `code_verifier`, `state`, and `nonce` for each authorization attempt, retain them server-side against the browser session, and redirect the user to the authorization endpoint. ```bash theme={null} # code_verifier: 43-128 chars of unreserved characters, cryptographically random # code_challenge = BASE64URL(SHA256(code_verifier)) https://www.etoro.com/sso ?response_type=code &client_id= &redirect_uri=https%3A%2F%2Fmyapp.com%2Foauth%2Fcallback &scope=openid%20etoro-public%3Areal%3Aread &state= &nonce= &code_challenge= &code_challenge_method=S256 ``` | Parameter | Notes | | - | - | | `response_type` | Always `code`. | | `scope` | Include `openid` to receive an ID token. Add the API scopes your application needs. | | `state` | Bound to the browser session and verified on the callback. This is the CSRF control for the flow: a callback presenting a `state` value you did not issue must be rejected. | | `nonce` | Echoed into the ID token as the `nonce` claim. Verification of this value is what prevents an ID token from another sign-in being replayed. | | `code_challenge` | Mandatory. It binds the authorization code to your token request, so an intercepted code cannot be redeemed. | etoro authenticates the user, presents the consent screen for the scopes registered to the application, and redirects to the registered `redirect_uri` with `code` and `state`. ## Step 2 — Exchange the code for tokens This call is made server to server from your backend, authenticated with the client credentials. The authorization code is single-use and short-lived. ```bash cURL theme={null} curl -X POST "https://www.etoro.com/api/sso/v1/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -u ":" \ -d "grant_type=authorization_code" \ -d "code=" \ -d "redirect_uri=https://myapp.com/oauth/callback" \ -d "code_verifier=" ``` ```javascript JavaScript theme={null} const body = new URLSearchParams({ grant_type: 'authorization_code', code, redirect_uri: 'https://myapp.com/oauth/callback', code_verifier: codeVerifier, }); const res = await fetch('https://www.etoro.com/api/sso/v1/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: 'Basic ' + Buffer.from(`${clientId}:${clientSecret}`).toString('base64'), }, body, }); const tokens = await res.json(); ``` The response contains the ID token, the access token used against the API, and a refresh token: ```json theme={null} { "token_type": "Bearer", "expires_in": 3600, "access_token": "", "id_token": "", "refresh_token": "", "scope": "openid etoro-public:real:read" } ``` > [!NOTE] > > The access token authenticates API calls as `Authorization: Bearer `. The ID token is **not** an API credential: it is an assertion of who authenticated, to be verified by your backend and then discarded or retained as a claim record. An ID token must never be sent to the API. ## Step 3 — Validate the ID token The ID token is the only element of this flow that identifies which user signed in, and its validation is therefore the security boundary of the integration. Retrieve the signing keys from the JWKS URI, cache them by `kid`, and refresh on an unknown `kid`. Verify each of the following, and fail closed on any failure: * **Signature** against the JWKS key whose `kid` matches the token header, with `alg` RS256. * **`iss`** equals `https://www.etoro.com` exactly. * **`aud`** contains your `clientId`. * **`exp`** is in the future and **`iat`** is not implausibly old (allow only small clock skew). * **`nonce`** equals the nonce you issued for this authorization attempt. * **`sub`** is present. This is your user key. ```javascript JavaScript theme={null} import { createRemoteJWKSet, jwtVerify } from 'jose'; const JWKS = createRemoteJWKSet( new URL('https://www.etoro.com/.well-known/jwks.json'), ); const { payload } = await jwtVerify(idToken, JWKS, { issuer: 'https://www.etoro.com', audience: clientId, algorithms: ['RS256'], clockTolerance: 30, }); if (payload.nonce !== expectedNonce) { throw new Error('ID token nonce mismatch'); } // payload.sub is a pairwise pseudonymous identifier, stable for this client. const etoroSubject = payload.sub; ``` ```bash cURL theme={null} # Fetch the keys; match the "kid" against the ID token's JWT header, # then verify RS256 with your JWT library of choice. curl -s https://www.etoro.com/.well-known/jwks.json ``` ```json theme={null} { "keys": [ { "kty": "RSA", "alg": "RS256", "use": "sig", "kid": "00043", "n": "", "e": "AQAB" } ] } ``` > [!WARNING] > > Verification must not be omitted on the basis that the token was received over TLS from etoro's token endpoint. Every ID token acted upon is to be validated, and a validation failure is to be treated as a failed sign-in rather than logged as a warning and disregarded. Signing keys are rotated. Resolve `jwks_uri` from the discovery document, cache the key set with a short TTL, and re-fetch it when a token presents an unknown `kid`. Keys must not be pinned by value. ## Calling the API with the token The access token is presented as `Authorization: Bearer `, together with the `x-request-id` header required on every call: ```bash theme={null} curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \ -H "x-request-id: " \ -H "Authorization: Bearer " ``` > [!WARNING] > > The `Authorization: Bearer` header and the `x-api-key` + `x-user-key` pair are **mutually exclusive** authentication methods. A request presenting both is rejected. The scopes carried by the token determine which operations may be executed. Every operation in the API reference lists the scopes that grant access to it as alternative security requirements: a token needs **one** of the listed alternatives, not all of them, and a call whose token carries none of them is rejected. This applies uniformly across both published documents — the [Core API](/) and the [Partners API](/partners-api-reference) — so a single token consented to the right scopes reaches every operation the application is entitled to call. ## Identity and personal data The `sub` claim is the identity anchor for the integration. It is **pairwise**: a given etoro user presents a different `sub` value to each registered client, so the identifier is stable for your application, meaningless to anyone else, and carries no personal information. Design around it: * **Identity is the `sub` claim.** Use it as the primary key associating your user record with the etoro user, and resolve it on every subsequent sign-in. * **Authorization is the scope set** on the token. Never infer entitlement from anything the user typed into your application. * **No PII joins.** Do not build account matching, reconciliation, deduplication, or support lookups on email address, name, or phone number. Beyond being unavailable by default, matching on user-supplied attributes is an account-takeover vector: any party able to register that value in your application would inherit the corresponding etoro account. * **A scope is permission to call, not permission to receive PII.** Where an operation would return personal data, a separate data-sharing approval governs what is returned. Applications that require access to identity or verification data etoro already holds — the KYC and verification operations in the Partners API — are subject to an explicit per-integration approval in addition to the relevant scopes. See [Data sharing and PII](/partners/integration#data-sharing-and-pii). ## Token lifecycle **Access token** `~1 hour` Refresh it with `grant_type=refresh_token` at the token endpoint, using the same client authentication as Step 2. Refresh on a `401`, and pre-emptively before expiry for long-running jobs. **Refresh token** `long-lived` Store it encrypted, one per user per client. Revoke it at `https://www.etoro.com/api/sso/v1/token/revoke` when a user disconnects your application. **Client secret** `until rotated` Rotate with `POST /api/v1/sso/applications/{clientId}/client-secret`. The previous secret stops working the moment the call returns, so deploy the new one in the same window. > [!NOTE] > > An access token is bound to the user's interactive session. For backend work performed while the user is not present, a long-lived **non-interactive token** is issued instead — see [Issue a non-interactive token](/partners/integration#issue-a-non-interactive-token). ## Security checklist The following must be in place before an integration is promoted to production: * PKCE `S256` on every authorization request — no exceptions, including for confidential clients. * `state` verified against the browser session on every callback; `nonce` verified inside every ID token. * Exact-match redirect URIs, HTTPS, pointing at your backend. * ID token signature, `iss`, `aud`, `exp`, and `nonce` all verified, with `alg` restricted to RS256 and JWKS keys fetched by `kid`. * Client secret and refresh tokens held in a secret store — never in source, never in a repository, never in a log line, never in an error payload, never returned to the browser. * A working revocation path for the refresh token, wired to your own user-offboarding flow. * `x-request-id` set to a fresh UUID on every API call, so a failure is traceable end to end across both systems. * No PII in the account association, the logs, or the analytics. ## Reference > **[Partner integration flow](/partners/integration)** > > Non-interactive tokens, account association, event reporting, and the data-sharing rules. > **[API keys and headers](/core/getting-started/authentication)** > > The `x-api-key` / `x-user-key` pair and request header format. > **[Builders portal](https://builders.etoro.com/)** > > Register your application and manage credentials. > **[Rate limits](/core/getting-started/rate-limits)** > > Quotas that apply to every call in this flow. # Calculate Available Cash Source: https://api-portal.etoro.com/core/guides/calculate-available-cash Learn how to calculate your available cash balance in demo or real accounts. Available cash represents the funds you have available to open new positions. It is calculated by taking your total credit and subtracting the sum of all pending order amounts. > [!NOTE] > > Available cash only refers to your USD balance. To retrieve the data needed for this calculation, use the P\&L endpoint for either demo or real accounts. ## The Calculation Process Calculating available cash involves fetching your account data and performing a simple subtraction of all pending order amounts from your total credit. ### 1. Endpoints Use the **P\&L** endpoint to retrieve your account information. **Demo Account:** `GET https://public-api.etoro.com/api/v1/trading/info/demo/pnl` **Real Account:** `GET https://public-api.etoro.com/api/v1/trading/info/real/pnl` ### 2. Header Requirements Remember to include your authentication headers with every request. * `x-api-key` * `x-user-key` * `x-request-id` ### 3. Calculation Formula ```text theme={null} Available Cash = credit - (Σ(ordersForOpen[i].amount where mirrorID = 0) + Σ(orders[i].amount)) ``` Where: * `credit` is the total credit balance in your account * `ordersForOpen` is an array of pending market orders (filtered to only include manual positions where `mirrorID = 0`) * `orders` is an array of pending Market-if-touched orders (similar to Limit orders) * `mirrorID = 0` indicates a manual position; `mirrorID ≠ 0` indicates a mirrored (copy) position * `amount` is the allocated amount for each order ## Examples ```bash cURL theme={null} curl -X GET "https://public-api.etoro.com/api/v1/trading/info/demo/pnl" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} const url = 'https://public-api.etoro.com/api/v1/trading/info/demo/pnl'; fetch(url, options) .then(res => res.json()) .then(data => { const credits = data.credits; // Only include manual positions (mirrorID = 0) from ordersForOpen const ordersForOpenAmount = data.ordersForOpen .filter(order => order.mirrorID === 0) .reduce((sum, order) => sum + order.amount, 0); const ordersAmount = data.orders.reduce((sum, order) => sum + order.amount, 0); const availableCash = credits - (ordersForOpenAmount + ordersAmount); console.log("Available Cash:", availableCash); }) .catch(err => console.error(err)); ``` ```python Python theme={null} import requests import uuid url = "https://public-api.etoro.com/api/v1/trading/info/demo/pnl" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() credits = data['credits'] # Only include manual positions (mirrorID = 0) from ordersForOpen orders_for_open_amount = sum(order['amount'] for order in data['ordersForOpen'] if order['mirrorID'] == 0) orders_amount = sum(order['amount'] for order in data['orders']) available_cash = credits - (orders_for_open_amount + orders_amount) print(f"Available Cash: {available_cash}") else: print(f"Error: {response.status_code}") ``` ### Example Calculation If your account has: * `credit`: 1000 * `ordersForOpen`: Two manual pending orders with `amount` values of 200 each (where `mirrorID = 0`), and one mirrored order with `amount` of 100 (where `mirrorID ≠ 0`) * `orders`: One existing order with `amount` value of 150 Then your available cash would be: ```text theme={null} 1000 - ((200 + 200) + 150) = 450 ``` Note: The mirrored order with amount 100 is excluded from the calculation because `mirrorID ≠ 0`. ### Best Practices 1. **Check Before Trading:** Always verify your available cash before attempting to open new positions to avoid insufficient funds errors. 2. **Account for Manual Orders Only:** Only manual positions (where `mirrorID = 0`) from `ordersForOpen` are included in the calculation. Mirrored (copy) positions are excluded. All items in the `orders` array are included regardless of `mirrorID`. 3. **Use the Correct Environment:** Make sure to use the demo endpoint when testing and the real endpoint for live trading. # Calculate Equity Source: https://api-portal.etoro.com/core/guides/calculate-equity Learn how to calculate your equity in demo or real accounts. Equity represents the total value of your account, including your available cash, invested capital, and unrealized profit/loss. It is calculated by summing your available cash, total invested amount, and unrealized PnL. > [!NOTE] > > Equity only refers to your USD balance. To retrieve the data needed for this calculation, use the P\&L endpoint for either demo or real accounts. ## The Calculation Process Calculating equity involves fetching your account data and combining three key components: available cash, total invested, and unrealized PnL. ### 1. Endpoints Use the **P\&L** endpoint to retrieve your account information. **Demo Account:** `GET https://public-api.etoro.com/api/v1/trading/info/demo/pnl` **Real Account:** `GET https://public-api.etoro.com/api/v1/trading/info/real/pnl` ### 2. Header Requirements Remember to include your authentication headers with every request. * `x-api-key` * `x-user-key` * `x-request-id` ### 3. Calculation Formula ```text theme={null} Equity = Available Cash + Total Invested + Unrealized PnL ``` Where: * **Available Cash** = `credit - (Σ(ordersForOpen[i].amount where mirrorID = 0) + Σ(orders[i].amount))` * **Total Invested** = `Σ(positions[i].amount) + Σ(mirrors[i].positions[j].amount) + Σ(mirrors[i].availableAmount - mirrors[i].closedPositionsNetProfit) + Σ(ordersForOpen[i].amount where mirrorID = 0) + Σ(orders[i].amount) + Σ(ordersForOpen[i].totalExternalCosts where mirrorID = 0)` * **Unrealized PnL** = `Σ(positions[i].unrealizedPnL.pnL) + Σ(mirrors[i].positions[j].unrealizedPnL.pnL) + Σ(mirrors[i].closedPositionsNetProfit)` > [!NOTE] > > For detailed information on calculating each component, see: > > * [Calculate Available Cash](/core/guides/calculate-available-cash) > * [Calculate Total Invested](/core/guides/calculate-total-invested) > * [Calculate Profit/Loss](/core/guides/calculate-profit-loss) ## Examples ```bash cURL theme={null} curl -X GET "https://public-api.etoro.com/api/v1/trading/info/demo/pnl" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} const url = 'https://public-api.etoro.com/api/v1/trading/info/demo/pnl'; fetch(url, options) .then(res => res.json()) .then(data => { // Calculate Available Cash const credits = data.credits; const ordersForOpenAmount = data.ordersForOpen .filter(order => order.mirrorID === 0) .reduce((sum, order) => sum + order.amount, 0); const ordersAmount = data.orders.reduce((sum, order) => sum + order.amount, 0); const availableCash = credits - (ordersForOpenAmount + ordersAmount); // Calculate Total Invested const positionsAmount = data.positions.reduce((sum, pos) => sum + pos.amount, 0); let mirrorsPositionsAmount = 0; let mirrorsAdjustedAmount = 0; data.mirrors.forEach(mirror => { mirrorsPositionsAmount += mirror.positions.reduce((sum, pos) => sum + pos.amount, 0); mirrorsAdjustedAmount += (mirror.availableAmount - mirror.closedPositionsNetProfit); }); const externalCosts = data.ordersForOpen .filter(order => order.mirrorID === 0) .reduce((sum, order) => sum + order.totalExternalCosts, 0); const totalInvested = positionsAmount + mirrorsPositionsAmount + mirrorsAdjustedAmount + ordersForOpenAmount + ordersAmount + externalCosts; // Calculate Unrealized PnL const positionsPnL = data.positions.reduce((sum, pos) => sum + pos.unrealizedPnL.pnL, 0); let mirrorsPnL = 0; let closedPositionsProfit = 0; data.mirrors.forEach(mirror => { mirrorsPnL += mirror.positions.reduce((sum, pos) => sum + pos.unrealizedPnL.pnL, 0); closedPositionsProfit += mirror.closedPositionsNetProfit; }); const unrealizedPnL = positionsPnL + mirrorsPnL + closedPositionsProfit; // Calculate Equity const equity = availableCash + totalInvested + unrealizedPnL; console.log("Equity:", equity); }) .catch(err => console.error(err)); ``` ```python Python theme={null} import requests import uuid url = "https://public-api.etoro.com/api/v1/trading/info/demo/pnl" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() # Calculate Available Cash credits = data['credits'] orders_for_open_amount = sum(order['amount'] for order in data['ordersForOpen'] if order['mirrorID'] == 0) orders_amount = sum(order['amount'] for order in data['orders']) available_cash = credits - (orders_for_open_amount + orders_amount) # Calculate Total Invested positions_amount = sum(pos['amount'] for pos in data['positions']) mirrors_positions_amount = sum( pos['amount'] for mirror in data['mirrors'] for pos in mirror['positions'] ) mirrors_adjusted_amount = sum( mirror['availableAmount'] - mirror['closedPositionsNetProfit'] for mirror in data['mirrors'] ) external_costs = sum( order['totalExternalCosts'] for order in data['ordersForOpen'] if order['mirrorID'] == 0 ) total_invested = (positions_amount + mirrors_positions_amount + mirrors_adjusted_amount + orders_for_open_amount + orders_amount + external_costs) # Calculate Unrealized PnL positions_pnl = sum(pos['unrealizedPnL']['pnL'] for pos in data['positions']) mirrors_pnl = sum( pos['unrealizedPnL']['pnL'] for mirror in data['mirrors'] for pos in mirror['positions'] ) closed_positions_profit = sum( mirror['closedPositionsNetProfit'] for mirror in data['mirrors'] ) unrealized_pnl = positions_pnl + mirrors_pnl + closed_positions_profit # Calculate Equity equity = available_cash + total_invested + unrealized_pnl print(f"Equity: {equity}") else: print(f"Error: {response.status_code}") ``` ### Example Calculation If your account has: * **Available Cash**: 450 * **Total Invested**: 1560 * **Unrealized PnL**: 175 Then your equity would be: ```text theme={null} 450 + 1560 + 175 = 2185 ``` ### Best Practices 1. **Monitor Total Account Value:** Equity gives you a complete picture of your account's total value, including both liquid and invested capital. 2. **Track Performance:** Compare your equity over time to understand your overall trading performance. 3. **Risk Management:** Use equity to calculate position sizes and manage risk appropriately. 4. **Use the Correct Environment:** Make sure to use the demo endpoint when testing and the real endpoint for live trading. # Calculate Profit/Loss Source: https://api-portal.etoro.com/core/guides/calculate-profit-loss Learn how to calculate your profit/loss (unrealized PnL) in demo or real accounts. Profit/Loss represents your unrealized profit and loss across all open positions. It is calculated by summing the unrealized PnL from all your positions, mirror positions, and the net profit from closed positions in your mirror portfolios. > [!NOTE] > > Profit/Loss appears as "Profit/Loss" in the app and represents your unrealized PnL. To retrieve the data needed for this calculation, use the P\&L endpoint for either demo or real accounts. ## The Calculation Process Calculating profit/loss involves fetching your account data and summing all unrealized PnL values from positions and closed position profits. ### 1. Endpoints Use the **P\&L** endpoint to retrieve your account information. **Demo Account:** `GET https://public-api.etoro.com/api/v1/trading/info/demo/pnl` **Real Account:** `GET https://public-api.etoro.com/api/v1/trading/info/real/pnl` ### 2. Header Requirements Remember to include your authentication headers with every request. * `x-api-key` * `x-user-key` * `x-request-id` ### 3. Calculation Formula ``` Profit/Loss = Σ(positions[i].unrealizedPnL.pnL) + Σ(mirrors[i].positions[j].unrealizedPnL.pnL) + Σ(mirrors[i].closedPositionsNetProfit) ``` Where: * `positions` is an array of your open positions * `positions[i].unrealizedPnL.pnL` is the unrealized profit/loss for each position * `mirrors` is an array of your copy trading portfolios * `mirrors[i].positions` is an array of positions within each mirror portfolio * `mirrors[i].positions[j].unrealizedPnL.pnL` is the unrealized profit/loss for each mirror position * `mirrors[i].closedPositionsNetProfit` is the net profit from closed positions in each mirror portfolio ## Examples ```bash cURL theme={null} curl -X GET "https://public-api.etoro.com/api/v1/trading/info/demo/pnl" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} const url = 'https://public-api.etoro.com/api/v1/trading/info/demo/pnl'; fetch(url, options) .then(res => res.json()) .then(data => { // Sum unrealized PnL from all positions const positionsPnL = data.positions.reduce((sum, pos) => sum + pos.unrealizedPnL.pnL, 0); // Sum unrealized PnL from mirror positions and closed positions net profit let mirrorsPnL = 0; let closedPositionsProfit = 0; data.mirrors.forEach(mirror => { mirrorsPnL += mirror.positions.reduce((sum, pos) => sum + pos.unrealizedPnL.pnL, 0); closedPositionsProfit += mirror.closedPositionsNetProfit; }); const profitLoss = positionsPnL + mirrorsPnL + closedPositionsProfit; console.log("Profit/Loss:", profitLoss); }) .catch(err => console.error(err)); ``` ```python Python theme={null} import requests import uuid url = "https://public-api.etoro.com/api/v1/trading/info/demo/pnl" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() # Sum unrealized PnL from all positions positions_pnl = sum(pos['unrealizedPnL']['pnL'] for pos in data['positions']) # Sum unrealized PnL from mirror positions mirrors_pnl = sum( pos['unrealizedPnL']['pnL'] for mirror in data['mirrors'] for pos in mirror['positions'] ) # Sum closed positions net profit closed_positions_profit = sum( mirror['closedPositionsNetProfit'] for mirror in data['mirrors'] ) profit_loss = positions_pnl + mirrors_pnl + closed_positions_profit print(f"Profit/Loss: {profit_loss}") else: print(f"Error: {response.status_code}") ``` ### Example Calculation If your account has: * `positions`: Two positions with `unrealizedPnL.pnL` values of 50 and -20 * `mirrors`: One mirror portfolio with: * Two positions with `unrealizedPnL.pnL` values of 30 and 15 * `closedPositionsNetProfit`: 100 Then your profit/loss would be: ``` (50 + (-20)) + (30 + 15) + 100 = 175 ``` ### Best Practices 1. **Monitor Regularly:** Check your profit/loss frequently to track the performance of your open positions. 2. **Understand Components:** Remember that profit/loss includes both unrealized PnL from open positions and realized profits from closed mirror positions. 3. **Consider Market Volatility:** Unrealized PnL can fluctuate with market conditions, so monitor it alongside your total invested amount. 4. **Use the Correct Environment:** Make sure to use the demo endpoint when testing and the real endpoint for live trading. # Calculate Total Invested Source: https://api-portal.etoro.com/core/guides/calculate-total-invested Learn how to calculate your total invested amount in demo or real accounts. Total invested represents the total amount of capital you have allocated across all positions and pending orders. It is calculated by summing all position amounts, mirror position amounts, mirror available amounts (adjusted for closed positions), and pending order amounts. > [!NOTE] > > Total invested only refers to your USD balance. To retrieve the data needed for this calculation, use the P\&L endpoint for either demo or real accounts. ## The Calculation Process Calculating total invested involves fetching your account data and summing all amounts allocated to positions and orders. ### 1. Endpoints Use the **P\&L** endpoint to retrieve your account information. **Demo Account:** `GET https://public-api.etoro.com/api/v1/trading/info/demo/pnl` **Real Account:** `GET https://public-api.etoro.com/api/v1/trading/info/real/pnl` ### 2. Header Requirements Remember to include your authentication headers with every request. * `x-api-key` * `x-user-key` * `x-request-id` ### 3. Calculation Formula ``` Total Invested = Σ(positions[i].amount) + Σ(mirrors[i].positions[j].amount) + Σ(mirrors[i].availableAmount - mirrors[i].closedPositionsNetProfit) + Σ(ordersForOpen[i].amount where mirrorID = 0) + Σ(orders[i].amount) + Σ(ordersForOpen[i].totalExternalCosts where mirrorID = 0) ``` Where: * `positions` is an array of your open positions * `mirrors` is an array of your copy trading portfolios * `mirrors[i].positions` is an array of positions within each mirror portfolio * `mirrors[i].availableAmount` is the available amount in each mirror portfolio * `mirrors[i].closedPositionsNetProfit` is the net profit from closed positions in each mirror portfolio * `ordersForOpen` is an array of pending market orders (filtered to only include manual positions where `mirrorID = 0`) * `orders` is an array of pending Market-if-touched orders * `totalExternalCosts` is the total external costs for each order * `amount` is the allocated amount for each position or order ## Examples ```bash cURL theme={null} curl -X GET "https://public-api.etoro.com/api/v1/trading/info/demo/pnl" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} const url = 'https://public-api.etoro.com/api/v1/trading/info/demo/pnl'; fetch(url, options) .then(res => res.json()) .then(data => { // Sum all position amounts const positionsAmount = data.positions.reduce((sum, pos) => sum + pos.amount, 0); // Sum all mirror position amounts and adjusted available amounts let mirrorsPositionsAmount = 0; let mirrorsAdjustedAmount = 0; data.mirrors.forEach(mirror => { mirrorsPositionsAmount += mirror.positions.reduce((sum, pos) => sum + pos.amount, 0); mirrorsAdjustedAmount += (mirror.availableAmount - mirror.closedPositionsNetProfit); }); // Sum manual pending orders (mirrorID = 0) const ordersForOpenAmount = data.ordersForOpen .filter(order => order.mirrorID === 0) .reduce((sum, order) => sum + order.amount, 0); // Sum all orders const ordersAmount = data.orders.reduce((sum, order) => sum + order.amount, 0); // Sum external costs for manual pending orders const externalCosts = data.ordersForOpen .filter(order => order.mirrorID === 0) .reduce((sum, order) => sum + order.totalExternalCosts, 0); const totalInvested = positionsAmount + mirrorsPositionsAmount + mirrorsAdjustedAmount + ordersForOpenAmount + ordersAmount + externalCosts; console.log("Total Invested:", totalInvested); }) .catch(err => console.error(err)); ``` ```python Python theme={null} import requests import uuid url = "https://public-api.etoro.com/api/v1/trading/info/demo/pnl" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.get(url, headers=headers) if response.status_code == 200: data = response.json() # Sum all position amounts positions_amount = sum(pos['amount'] for pos in data['positions']) # Sum all mirror position amounts and adjusted available amounts mirrors_positions_amount = sum( pos['amount'] for mirror in data['mirrors'] for pos in mirror['positions'] ) mirrors_adjusted_amount = sum( mirror['availableAmount'] - mirror['closedPositionsNetProfit'] for mirror in data['mirrors'] ) # Sum manual pending orders (mirrorID = 0) orders_for_open_amount = sum( order['amount'] for order in data['ordersForOpen'] if order['mirrorID'] == 0 ) # Sum all orders orders_amount = sum(order['amount'] for order in data['orders']) # Sum external costs for manual pending orders external_costs = sum( order['totalExternalCosts'] for order in data['ordersForOpen'] if order['mirrorID'] == 0 ) total_invested = (positions_amount + mirrors_positions_amount + mirrors_adjusted_amount + orders_for_open_amount + orders_amount + external_costs) print(f"Total Invested: {total_invested}") else: print(f"Error: {response.status_code}") ``` ### Example Calculation If your account has: * `positions`: Two positions with `amount` values of 500 and 300 * `mirrors`: One mirror portfolio with: * Two positions with `amount` values of 200 and 150 * `availableAmount`: 100 * `closedPositionsNetProfit`: 50 * `ordersForOpen`: One manual pending order with `amount` of 200 and `totalExternalCosts` of 10 (where `mirrorID = 0`) * `orders`: One existing order with `amount` value of 150 Then your total invested would be: ``` (500 + 300) + (200 + 150) + (100 - 50) + 200 + 150 + 10 = 1560 ``` ### Best Practices 1. **Monitor Your Investment:** Regularly check your total invested to understand your capital allocation across all positions and orders. 2. **Account for Mirror Portfolios:** Remember that mirror portfolios contribute to your total invested through both their positions and adjusted available amounts. 3. **Include External Costs:** Don't forget to include external costs from manual pending orders in your calculation. 4. **Use the Correct Environment:** Make sure to use the demo endpoint when testing and the real endpoint for live trading. # Find Instrument ID Source: https://api-portal.etoro.com/core/guides/get-instrument-id Learn how to resolve a ticker symbol to an etoro Instrument ID. Most endpoints in the etoro Public API require a numeric `instrumentId` to identify the asset you wish to access, rather than the text-based ticker symbol (e.g., 'AAPL'). To bridge this gap, you must use the Search endpoint to resolve a symbol into its corresponding ID. ## The Resolution Process Resolving a symbol involves sending a specific query to the market data search endpoint and parsing the result to find the matching instrument record. ### 1. Endpoint Use the **Search** endpoint to query for the instrument. `GET https://public-api.etoro.com/api/v1/market-data/search` ### 2. Query Parameters While the search endpoint accepts general search text, the most precise way to find a specific ID is to filter by the `internalSymbolFull` field. | Parameter | Value | Description | | :- | :- | :- | | `internalSymbolFull` | `AAPL` | The specific ticker symbol you want to resolve. | ### 3. Header Requirements Remember to include your authentication headers with every request. * `x-api-key` * `x-user-key` * `x-request-id` ## Examples ```bash cURL theme={null} curl -X GET "https://public-api.etoro.com/api/v1/market-data/search?internalSymbolFull=AAPL" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} const symbol = 'AAPL'; const url = `https://public-api.etoro.com/api/v1/market-data/search?internalSymbolFull=${symbol}`; fetch(url, options) .then(res => res.json()) // Find the exact match in the returned items list .then(res => { const instrument = res.items.find(i => i.internalSymbolFull === symbol); console.log("Instrument ID:", instrument.instrumentId); }) .catch(err => console.error(err)); ``` ```python Python theme={null} import requests import uuid symbol = "AAPL" url = "https://public-api.etoro.com/api/v1/market-data/search" # Use internalSymbolFull to filter specifically for the symbol params = { "internalSymbolFull": symbol } headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.get(url, headers=headers, params=params) if response.status_code == 200: data = response.json() # Find the exact match in the returned items list instrument = next((item for item in data['items'] if item['internalSymbolFull'] == symbol), None) if instrument: print(f"Instrument ID: {instrument['instrumentId']}") else: print("Instrument not found") else: print(f"Error: {response.status_code}") ``` ### Best Practices 1. **Verify the Match:** The search might return partial matches or related assets. Always verify that the `internalSymbolFull` property of the returned item exactly matches your requested symbol. 2. **Cache your IDs**: Instrument IDs are immutable: They never change, even if a company rebrands or changes its ticker symbol. While symbols rarely change, relying on the permanent instrumentId ensures your application remains robust against such events. We strongly recommend fetching these IDs once and caching the mapping (e.g., AAPL -> 1001) locally. # Transfer money between your accounts Source: https://api-portal.etoro.com/core/guides/internal-transfers Learn the call sequence for moving funds between your own etoro accounts: check what is allowed, execute the transfer, and track it. An internal transfer moves funds between accounts that belong to the same customer, for example from a trading account to a cash account. This guide shows the order in which to call the Money API. For the full request and response fields of each endpoint, see the API reference. * **Account types:** `trading`, `options` and `cash` * **Headers:** every call requires a unique `x-request-id` header. * **Customer context:** the customer is derived from your credentials. You never send a `gcid`. ## The Flow ```mermaid theme={null} sequenceDiagram participant App participant API as Money API App->>API: 1. GET /transfer-eligibility API-->>App: allowed source → destination pairs App->>API: 2. GET /transferable-balance API-->>App: maximum amount for the chosen pair App->>API: 3. GET /transfer-limits and /transfer-fee-configurations (optional) API-->>App: min / max and fee per route App->>API: 4. POST /transfers API-->>App: transferId App->>API: 5. GET /transfers/{transferId} API-->>App: status ``` All paths are relative to `https://public-api.etoro.com/api/v1/money`. ## Step 1: Find the Allowed Transfers Call `GET /transfer-eligibility`. It returns, for each of the customer's source accounts, the destination accounts it can transfer to. Let the user pick from this list, and use the `accountType` and `accountId` values exactly as returned in the next steps. A source with no `destinationAccounts` cannot transfer anywhere. ## Step 2: Get the Maximum Amount Once the user has chosen a source and a destination, call `GET /transferable-balance` with both accounts. It returns the most the customer can move right now, so you do not need to combine balances and limits yourself. A `404` means the pair is not available. ## Step 3: Show Limits and Fees (Optional) To show the user the policy bounds and the cost before they confirm, call: * `GET /transfer-limits` for the minimum and maximum amount per route * `GET /transfer-fee-configurations` for the fee per route Both return one row per route, so pick the row that matches the chosen account types. ## Step 4: Execute the Transfer Call `POST /transfers` with the source account, destination account, `amount`, `currency` (the source account currency), and a `requestReferenceId` of your own. ```json theme={null} { "requestReferenceId": "client-ref-8f3a-001", "sourceAccount": { "accountType": "trading", "accountId": "1001" }, "destinationAccount": { "accountType": "cash", "accountId": "x-5501" }, "amount": 250.0, "currency": "USD" } ``` The response contains `transferId` and `requestReferenceId`. A successful response means the transfer was **accepted**, not that it has completed, so continue to Step 5. `requestReferenceId` is also your idempotency key. If a request times out, retry with the **same** value. Never reuse it for a different transfer. ## Step 5: Track the Transfer Read the outcome with one of: * `GET /transfers/{transferId}` when you hold the `transferId` * `GET /transfers:lookup?requestReferenceId=...` when you only hold your own reference Poll until `status` is final. | `status` | Meaning | Final | | - | - | - | | `InProcess` | Still being processed. Poll again. | No | | `Success` | The transfer completed. | Yes | | `Decline` | The transfer was declined. | Yes | | `Technical` | The transfer failed with a technical error. | Yes | | `Canceled` | The transfer was canceled. | Yes | If you receive a value you don't recognise, treat it as not final and poll again. ## Good to Know * **No demo environment:** the transfer endpoints have no demo variants, so test with small real amounts on your own accounts. * **Trading sub-accounts:** this transfer flow is not for trading sub-accounts. # Open and close market orders Source: https://api-portal.etoro.com/core/guides/market-orders Learn how to programmatically execute trades to enter and exit positions using the etoro API. Once you have resolved your target asset's `instrumentId`, you can begin executing trades. The etoro API separates trading logic into two distinct phases: opening a new position and closing an existing one. ## Opening a Position Use the v2 order endpoint to open a market position. You can specify exactly one sizing field: `amount`, `units`, or `contracts`. ### Method 1: By Amount (Cash) This is the most common method for dollar-cost averaging or fixed-budget strategies. You specify the cash value (e.g., \$1,000) and the API calculates the units based on the current market price. **Endpoint:** `POST /api/v2/trading/execution/orders` > **Note:** You can apply additional settings such as leverage, stop-loss, and take-profit during this request. ### Method 2: By Units (Volume) Use this method when you need to control the exact volume of the asset (e.g., buying exactly 1.5 Bitcoin or 10 shares of Apple). **Endpoint:** `POST /api/v2/trading/execution/orders` ### Example Request (Open by Amount) The following examples demonstrate the full flow: **Search** for 'BTC' to get its ID, then **Buy** \$1,000 worth of it. ```bash cURL theme={null} # 1. Search for the Instrument ID (Symbol: BTC) # Returns a JSON object containing the "InstrumentID" (e.g., 100000) curl -X GET "https://public-api.etoro.com/api/v1/market-data/search?internalSymbolFull=BTC" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " # 2. Use the ID from step 1 (e.g., 100000) to place the order curl -X POST "https://public-api.etoro.com/api/v2/trading/execution/orders" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " \ -H "Content-Type: application/json" \ -d '{ "action": "open", "transaction": "buy", "symbol": "BTC", "instrumentId": 100000, "orderType": "mkt", "leverage": 1, "amount": 1000, "orderCurrency": "usd" }' ``` ```javascript JavaScript theme={null} const crypto = require('crypto'); const placeOrder = async () => { const symbol = 'BTC'; const headers = { 'x-api-key': '', 'x-user-key': '', 'x-request-id': crypto.randomUUID(), // or 'your-unique-uuid' 'Content-Type': 'application/json' }; try { // 1. Get Instrument ID const searchUrl = `https://public-api.etoro.com/api/v1/market-data/search?internalSymbolFull=${symbol}`; const searchRes = await fetch(searchUrl, { headers }); const searchData = await searchRes.json(); // Find exact match const instrument = searchData.items.find(i => i.internalSymbolFull === symbol); if (!instrument) throw new Error(`Instrument ${symbol} not found`); const instrumentId = instrument.instrumentId; console.log(`Resolved ${symbol} to ID: ${instrumentId}`); // 2. Place Order const orderUrl = 'https://public-api.etoro.com/api/v2/trading/execution/orders'; const orderBody = { action: 'open', transaction: 'buy', symbol, instrumentId, orderType: 'mkt', leverage: 1, amount: 1000, orderCurrency: 'usd' }; const orderRes = await fetch(orderUrl, { method: 'POST', headers, body: JSON.stringify(orderBody) }); console.log("Order Response:", await orderRes.json()); } catch (err) { console.error(err); } }; placeOrder(); ``` ```python Python theme={null} import requests import uuid symbol = "BTC" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()), "Content-Type": "application/json" } # 1. Get Instrument ID search_url = "https://public-api.etoro.com/api/v1/market-data/search" search_res = requests.get(search_url, headers=headers, params={"internalSymbolFull": symbol}) search_data = search_res.json() # Find exact match instrument = next((i for i in search_data['items'] if i['internalSymbolFull'] == symbol), None) if instrument: instrument_id = instrument['instrumentId'] print(f"Resolved {symbol} to ID: {instrument_id}") # 2. Place Order order_url = "https://public-api.etoro.com/api/v2/trading/execution/orders" payload = { "action": "open", "transaction": "buy", "symbol": symbol, "instrumentId": instrument_id, "orderType": "mkt", "leverage": 1, "amount": 1000, "orderCurrency": "usd" } order_res = requests.post(order_url, json=payload, headers=headers) print("Order Response:", order_res.json()) else: print(f"Instrument {symbol} not found") ``` ## Closing a Position To close a trade, you must reference the specific `positionId` of the open position. You cannot simply "sell" the instrument; you must close the specific line item in your portfolio. **Endpoint:** `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` ### Full vs. Partial Close You can choose to close the entire position or just a portion of it. * **Full Close:** Omit the `UnitsToDeduct` parameter or set it to `null`. This liquidates the entire position. * **Partial Close:** Provide a specific value for `UnitsToDeduct`. Only that portion of the position will be closed, leaving the remainder active. ### Example Request (Close Position) ```bash cURL theme={null} # Closing position ID 12345678 curl -X POST "https://public-api.etoro.com/api/v1/trading/execution/market-close-orders/positions/12345678" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " \ -H "Content-Type: application/json" \ -d '{ "InstrumentId": 100000, "UnitsToDeduct": null }' ``` ```javascript JavaScript theme={null} const positionId = '12345678'; const url = `https://public-api.etoro.com/api/v1/trading/execution/market-close-orders/positions/${positionId}`; fetch(url, { method: 'POST', headers: { 'x-api-key': '', 'x-user-key': '', 'x-request-id': 'your-uuid-here', 'Content-Type': 'application/json' }, body: JSON.stringify({ InstrumentId: 100000, UnitsToDeduct: null }) }) .then(res => res.json()) .then(console.log) .catch(console.error); ``` ```python Python theme={null} import requests import uuid position_id = "12345678" url = f"https://public-api.etoro.com/api/v1/trading/execution/market-close-orders/positions/{position_id}" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()), "Content-Type": "application/json" } payload = { "InstrumentId": 100000, "UnitsToDeduct": None } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ## Important Considerations 1. **Instrument IDs:** You must know the numeric `instrumentId` before placing an order. Use the Search endpoint to resolve tickers (e.g., AAPL) to IDs. 2. **Demo Environment:** When testing, use `POST /api/v2/trading/execution/demo/orders` to avoid risking real capital. 3. **Market Rates:** It is recommended to check current rates using `GET /api/v1/market-data/instruments/rates` before executing orders to ensure price accuracy. # Manage your Watchlists Source: https://api-portal.etoro.com/core/guides/watchlists Learn how to create custom watchlists, populate them with assets, and sync your preferences across the etoro ecosystem. Watchlists are the primary way to organize and track groups of assets on etoro. By managing watchlists via the API, you can programmatically sync your external favorites, create custom sectors (e.g., "My AI Picks"), and control what appears on your main trading dashboard. ## 1. Get Your Watchlists First, retrieve the list of watchlists currently associated with your account. This will provide you with the `watchlistId` needed for further management actions. **Endpoint:** `GET /api/v1/watchlists` ```bash cURL theme={null} curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} fetch('https://public-api.etoro.com/api/v1/watchlists', { headers: { 'x-api-key': '', 'x-user-key': '', 'x-request-id': 'your-uuid-here' } }) .then(res => res.json()) .then(console.log) .catch(console.error); ``` ```python Python theme={null} import requests import uuid url = "https://public-api.etoro.com/api/v1/watchlists" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.get(url, headers=headers) print(response.json()) ``` > **Note:** You can use the `ensureBuiltinWatchlists` parameter to make sure system default lists are included in the response. ## 2. Create a New Watchlist You can create a custom watchlist by specifying a name. **Endpoint:** `POST /api/v1/watchlists` | Parameter | Type | Description | | - | - | - | | `name` | Query | The display name for your new watchlist (e.g., "Tech Stocks"). | ```bash cURL theme={null} curl -X POST "https://public-api.etoro.com/api/v1/watchlists?name=Tech%20Stocks" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} const name = 'Tech Stocks'; const url = `https://public-api.etoro.com/api/v1/watchlists?name=${encodeURIComponent(name)}`; fetch(url, { method: 'POST', headers: { 'x-api-key': '', 'x-user-key': '', 'x-request-id': 'your-uuid-here' } }) .then(res => res.json()) .then(console.log) .catch(console.error); ``` ```python Python theme={null} import requests import uuid url = "https://public-api.etoro.com/api/v1/watchlists" params = {"name": "Tech Stocks"} headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.post(url, params=params, headers=headers) print(response.json()) ``` ## 3. Add Instruments to a Watchlist Once a watchlist is created, you can add instruments to it using its `watchlistId`. **Endpoint:** `POST /api/v1/watchlists/{watchlistId}/items` ```bash cURL theme={null} curl -X POST "https://public-api.etoro.com/api/v1/watchlists/{watchlistId}/items" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " \ -H "Content-Type: application/json" \ -d '[1001, 1002]' ``` ```javascript JavaScript theme={null} const watchlistId = '12345'; const url = `https://public-api.etoro.com/api/v1/watchlists/${watchlistId}/items`; fetch(url, { method: 'POST', headers: { 'x-api-key': '', 'x-user-key': '', 'x-request-id': 'your-uuid-here', 'Content-Type': 'application/json' }, body: JSON.stringify([1001, 1002]) }) .then(res => res.json()) .then(console.log) .catch(console.error); ``` ```python Python theme={null} import requests import uuid watchlist_id = "12345" url = f"https://public-api.etoro.com/api/v1/watchlists/{watchlist_id}/items" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()), "Content-Type": "application/json" } payload = [1001, 1002] # payload is a list of instrument IDs response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` ## 4. Set a Default Watchlist The "Default" watchlist is the one that appears immediately when you log in. **Endpoint:** `PUT /api/v1/watchlists/setUserSelectedUserDefault/{watchlistId}` ```bash cURL theme={null} curl -X PUT "https://public-api.etoro.com/api/v1/watchlists/setUserSelectedUserDefault/12345" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} const watchlistId = '12345'; const url = `https://public-api.etoro.com/api/v1/watchlists/setUserSelectedUserDefault/${watchlistId}`; fetch(url, { method: 'PUT', headers: { 'x-api-key': '', 'x-user-key': '', 'x-request-id': 'your-uuid-here' } }) .then(res => res.json()) .then(console.log) .catch(console.error); ``` ```python Python theme={null} import requests import uuid watchlist_id = "12345" url = f"https://public-api.etoro.com/api/v1/watchlists/setUserSelectedUserDefault/{watchlist_id}" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.put(url, headers=headers) print(response.json()) ``` ## 5. Delete a Watchlist Remove a watchlist and all its contained items permanently. **Endpoint:** `DELETE /api/v1/watchlists/{watchlistId}` ```bash cURL theme={null} curl -X DELETE "https://public-api.etoro.com/api/v1/watchlists/12345" \ -H "x-api-key: " \ -H "x-user-key: " \ -H "x-request-id: " ``` ```javascript JavaScript theme={null} const watchlistId = '12345'; const url = `https://public-api.etoro.com/api/v1/watchlists/${watchlistId}`; fetch(url, { method: 'DELETE', headers: { 'x-api-key': '', 'x-user-key': '', 'x-request-id': 'your-uuid-here' } }) .then(res => res.json()) .then(console.log) .catch(console.error); ``` ```python Python theme={null} import requests import uuid watchlist_id = "12345" url = f"https://public-api.etoro.com/api/v1/watchlists/{watchlist_id}" headers = { "x-api-key": "", "x-user-key": "", "x-request-id": str(uuid.uuid4()) } response = requests.delete(url, headers=headers) print(response.json()) ``` # Antigravity Source: https://api-portal.etoro.com/core/vibe-code/antigravity Integrate the etoro Public API into Antigravity IDE Antigravity is an agent-first IDE designed for autonomous execution and vibe coding. You can connect its agents to the **etoro Public API MCP server** so they can discover routes and execute API calls. ## Configuration ### Recommended — install the skill The skill handles MCP registration, auth, and the demo-vs-real safety rules. In Antigravity, ask the agent: ```text theme={null} Please install the skill at https://mcp.public-api.etoro.com/skill and follow the instructions. ``` The skill at [mcp.public-api.etoro.com/skill](https://mcp.public-api.etoro.com/skill) walks Antigravity through the exact `mcp_config.json` entry, authentication, and the rules for money-moving routes. ### Manual setup **1. Locate MCP Configuration** Navigate to your home directory and find the `.antigravity` folder. Look for (or create) the `mcp_config.json` file. **2. Configure mcp\_config.json** Paste the following configuration into the file: ```json theme={null} { "mcpServers": { "etoro-public-api": { "url": "https://mcp.public-api.etoro.com" } } } ``` **3. Restart Antigravity** Restart the IDE to apply the changes. ## Usage Once configured, you can issue natural language commands to your agents involving the etoro Public API. **Examples:** * "Create a Python script that connects to the etoro WebSocket API using the authentication method described in the docs." * "Explain the JSON structure for a market order from the etoro API reference." The agents will use the MCP server's `get-all-routes` and `get-route-spec` tools to read the live OpenAPI document and implement the requested features. # Base44 Source: https://api-portal.etoro.com/core/vibe-code/base44 Create custom etoro apps using Base44's no-code platform Base44 is a powerful no-code development platform that partners with etoro to allow you to build custom trading applications and tools without writing extensive code. > [!NOTE] > > We are currently rolling out Base44 integration to our users in stages. If you don't see this feature yet, stay tuned as we expand availability! ## Getting Started If you have access to Base44, please contact your **Account Manager** to help you create your first application. **1. Access etoro App Store** Navigate to the [etoro App Store](https://www.etoro.com/marketplace) to begin. ## Features * **Visual Builder**: Design your app's interface and logic using Base44's drag-and-drop tools. * **Native Integration**: Access etoro's real-time market data and portfolio features directly within Base44 components. * **Vibe Coding**: Use natural language prompts to generate complex logic and workflows. # Claude Code Source: https://api-portal.etoro.com/core/vibe-code/claude-code Integrate the etoro Public API into Claude Code using MCP Claude Code is an agentic coding tool that lives in your terminal. You can connect it to the **etoro Public API MCP server** so it can discover routes and execute API calls while you build. ## Configuration ### Recommended — install the skill Easiest path. The skill handles MCP registration, auth, and the demo-vs-real safety rules. In a Claude Code session, paste: ```text theme={null} Please install the skill at https://mcp.public-api.etoro.com/skill and follow the instructions. ``` The skill at [mcp.public-api.etoro.com/skill](https://mcp.public-api.etoro.com/skill) walks Claude Code through the exact `claude mcp add` command, authentication headers, and the rules for money-moving routes. ### Manual setup Run the following command in your terminal to add the etoro Public API MCP server: ```bash theme={null} claude mcp add --transport http etoro-public-api https://mcp.public-api.etoro.com ``` > [!NOTE] > > This command registers the MCP server with Claude Code, allowing it to query the live OpenAPI document and execute Public API calls during your coding sessions. ## Verification To confirm that the MCP server has been added successfully, run: ```bash theme={null} claude mcp list ``` You should see `etoro-public-api` in the list of available MCP servers. ## Usage Once configured, you can ask Claude Code questions about the etoro Public API directly from your terminal. **Examples:** * `claude "How do I authenticate with the etoro WebSocket API?"` * `claude "Generate a Python script to place a market order using the etoro API"` Claude Code will use the MCP connection's `get-all-routes` and `get-route-spec` tools to read the live OpenAPI document and provide accurate answers and code snippets. # Cursor Source: https://api-portal.etoro.com/core/vibe-code/cursor Integrate the etoro Public API into Cursor using MCP You can connect Cursor to the **etoro Public API MCP server** so its AI can discover routes, read the live OpenAPI schema, and execute API calls while you build. ## Configuration ### Recommended — install the skill The fastest way is to let the skill handle MCP registration, authentication, and the demo-vs-real safety rules for you. In Cursor's chat or composer, send: ```text theme={null} Please install the skill at https://mcp.public-api.etoro.com/skill and follow the instructions. ``` The skill at [mcp.public-api.etoro.com/skill](https://mcp.public-api.etoro.com/skill) walks Cursor through the exact `mcp.json` entry, auth headers, and the rules for money-moving routes (open/close trades, transfers, etc.). ### One-click install [Install on Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=etoro-public-api\&config=eyJ1cmwiOiJodHRwczovL21jcC5wdWJsaWMtYXBpLmV0b3JvLmNvbSJ9) ### Manual setup **1. Open Cursor Settings** Navigate to **Cursor Settings** > **Tools & MCP** > **Installed MCP Servers**. **2. Add New MCP Server** Click on **Add Custom MCP**. This will open the `mcp.json` configuration file. **3. Configure mcp.json** Paste the following configuration into the file: ```json theme={null} { "mcpServers": { "etoro-public-api": { "url": "https://mcp.public-api.etoro.com" } } } ``` ## Usage Once configured, ask Cursor anything about the etoro Public API. For example: * "What are the parameters for placing a market order?" * "How do I authenticate with the WebSocket API?" Cursor will use the MCP server's `get-all-routes` and `get-route-spec` tools to read the live OpenAPI document and respond with accurate code. # Windsurf Source: https://api-portal.etoro.com/core/vibe-code/windsurf Integrate the etoro Public API into Windsurf IDE Windsurf is an AI-powered IDE by Codeium that allows for "flow" state coding. You can connect the Cascade assistant to the **etoro Public API MCP server** so it can discover routes and execute API calls. ## Configuration ### Recommended — install the skill The skill handles MCP registration, auth, and the demo-vs-real safety rules. Ask Cascade: ```text theme={null} Please install the skill at https://mcp.public-api.etoro.com/skill and follow the instructions. ``` The skill at [mcp.public-api.etoro.com/skill](https://mcp.public-api.etoro.com/skill) walks Cascade through the exact `mcp_config.json` entry, authentication, and the rules for money-moving routes. ### Manual setup **1. Locate MCP Configuration** Navigate to your home directory and find the `.windsurf` folder. Look for (or create) the `mcp_config.json` file. **2. Configure mcp\_config.json** Paste the following configuration into the file: ```json theme={null} { "mcpServers": { "etoro-public-api": { "url": "https://mcp.public-api.etoro.com" } } } ``` **3. Restart Windsurf** Restart the IDE to apply the changes. ## Usage You can reference the documentation in your conversation with Cascade. **Example queries:** * "How do I subscribe to real-time quotes using the etoro WebSocket?" * "@etoro Docs What are the rate limits for the REST API?" Cascade will use the MCP server's `get-all-routes` and `get-route-spec` tools to read the live OpenAPI document and help generate code. # Authentication Source: https://api-portal.etoro.com/core/websocket/authentication Authentication of the etoro WebSocket API To use certain WebSocket channels, you must authenticate with your User and API keys. ### Request ```json theme={null} { "id": "ed72693c-1545-4fa1-8a10-aca7cf5419a6", "operation": "Authenticate", "data": { "userKey": "", "apiKey": "" } } ``` ### Successful Response ```json theme={null} { "id": "ed72693c-1545-4fa1-8a10-aca7cf5419a6", "success": true, "operation": "Authenticate" } ``` ### Unsuccessful Response ```json theme={null} { "id": "ed72693c-1545-4fa1-8a10-aca7cf5419a6", "success": false, "operation": "Authenticate", "errorMessage": "", "errorCode": "" } ``` ### Error Codes **SessionAlreadyAuthenticated** `Error Code` Session is already authenticated **DataRequired** `Error Code` Data is required **ApiKeyRequired** `Error Code` ApiKey is required **UserKeyRequired** `Error Code` UserKey is required **TooManyRequests** `Error Code` Too many requests **Forbidden** `Error Code` Access to this resource is forbidden. Please contact customer support for assistance **UnhandledException** `Error Code` Global Error **InvalidKey** `Error Code` Key is invalid **Unauthorized** `Error Code` Unauthorized # Example code Source: https://api-portal.etoro.com/core/websocket/example-code Example code for the etoro WebSocket API The API is **one connection plus messages over it**. A topic is a string inside a `Subscribe` message, not a URL path — you always connect to `wss://ws.etoro.com/ws` and then subscribe. > [!NOTE] > > Every message must be sent **after** the socket opens. A `send()` call made > straight after `new WebSocket(...)` throws `InvalidStateError`, because the > connection is still in the `CONNECTING` state — hence the `onopen` handler below. ## Connect and subscribe ```javascript theme={null} const ws = new WebSocket("wss://ws.etoro.com/ws"); // `crypto.randomUUID()` is available in all modern browsers and in Node 19+. // The server echoes the id back, which is how a reply is matched to its request. const newId = () => crypto.randomUUID(); const send = (payload) => ws.send(JSON.stringify(payload)); ws.onopen = () => { // Authenticate FIRST if you need private topics. Public topics such as // `instrument:` do not require it. send({ id: newId(), operation: "Authenticate", data: { userKey: "", apiKey: "" } }); }; ws.onmessage = (event) => { const message = JSON.parse(event.data); // A reply to one of your requests carries `operation` and `success`. // A data push carries `messages`. if (message.operation === "Authenticate") { if (!message.success) { console.error("Auth failed:", message.errorCode, message.errorMessage); return; } // Only subscribe to private topics once Authenticate is acknowledged: // a Subscribe that arrives first is rejected. send({ id: newId(), operation: "Subscribe", data: { topics: ["instrument:100000", "private"], snapshot: true } }); return; } if (message.messages) { for (const m of message.messages) { // `content` is a JSON-encoded STRING, so it needs a second parse. console.log(m.topic, m.type, JSON.parse(m.content)); } } }; ws.onerror = (event) => console.error("WebSocket error:", event); ws.onclose = (event) => console.log("Closed:", event.code, event.reason); ``` ## Unsubscribe ```javascript theme={null} const topic = "instrument:100000"; send({ id: newId(), operation: "Unsubscribe", data: { topics: [topic] } }); ``` ## Close the connection ```javascript theme={null} // 1000 is the WebSocket "normal closure" code. ws.close(1000, "Done"); ``` # Private portfolio updates Source: https://api-portal.etoro.com/core/websocket/notifications/account-&-portfolio-feeds-orders/private-portfolio-updates Subscribe with topic `private` (or its alias `private:real`) for your real account and `private:demo` for your demo account (requires a prior successful Authenticate). The two accounts are separate streams - a demo-account update never arrives on `private` / `private:real`, nor a real-account one on `private:demo` - and each push's `topic` is the name you subscribed to (a session holding both `private` and `private:real` receives a real-account update once under each). Each push carries a `content` field that is a JSON-encoded string of a trading order update (e.g. `Trading.OrderForOpen.Update`, `Trading.OrderForCloseMultiple.Update`). # Instrument candles Source: https://api-portal.etoro.com/core/websocket/notifications/market-data-feeds-candles/instrument-candles Subscribe with topic `candle:` (e.g. `candle:100000`). Each push carries a `content` field that is a JSON-encoded string of a `Trading.Instrument.Candle` object (see schema). No authentication required. # Instrument rates Source: https://api-portal.etoro.com/core/websocket/notifications/market-data-feeds-status/instrument-rates Subscribe with topic `instrument:` (e.g. `instrument:100000`). Each push carries a `content` field that is a JSON-encoded string of a `Trading.Instrument.Rate` object (see schema). # Authenticate (control channel) Source: https://api-portal.etoro.com/core/websocket/notifications/session-&-subscriptions/authenticate-control-channel All client requests share one JSON envelope: `{ "id": "", "operation": "", "data": { ... } }`. The server answers each request on the same connection with an acknowledgement that echoes the `id` and the `operation`. The `id` is a client-generated GUID used to correlate the request with its acknowledgement. # Subscribe (control channel) Source: https://api-portal.etoro.com/core/websocket/notifications/session-&-subscriptions/subscribe-control-channel All client requests share one JSON envelope: `{ "id": "", "operation": "", "data": { ... } }`. The server answers each request on the same connection with an acknowledgement that echoes the `id` and the `operation`. The `id` is a client-generated GUID used to correlate the request with its acknowledgement. # Unsubscribe (control channel) Source: https://api-portal.etoro.com/core/websocket/notifications/session-&-subscriptions/unsubscribe-control-channel All client requests share one JSON envelope: `{ "id": "", "operation": "", "data": { ... } }`. The server answers each request on the same connection with an acknowledgement that echoes the `id` and the `operation`. The `id` is a client-generated GUID used to correlate the request with its acknowledgement. # Overview Source: https://api-portal.etoro.com/core/websocket/overview Overview of the etoro WebSocket API ### What is the WebSocket API The etoro WebSocket API provides real-time streaming access to market data and trading events through a persistent connection. This API enables developers to build responsive applications that react instantly to market changes, order updates, and portfolio events without the overhead of constant HTTP polling. The API uses JSON message format over WebSocket protocol, supporting both public market data streams and private authenticated feeds for personalized trading information. ### Key Features * **Real-time Market Data:** Live price feeds for instruments with bid/ask prices * **Trading Notifications:** Instant updates for order executions, position changes, and portfolio events * **Flexible Subscriptions:** Subscribe to specific instruments or private data feeds based on your needs * **Snapshot Support:** Optional initial snapshots when subscribing to topics for current state * **Authentication Integration:** Secure access to private data using your etoro API credentials # Topics Source: https://api-portal.etoro.com/core/websocket/topics Topics for the etoro WebSocket API ## Instrument Topics Subscribe to real-time market price updates for various instruments. ### Request ```json theme={null} { "id": "ed72693c-1545-4fa1-8a10-aca7cf5419a6", "operation": "Subscribe", "data": { "topics": ["instrument:","instrument:",...], "snapshot": } } ``` ### Response ```json theme={null} { "messages": [ { "topic": "instrument:100000", "content": "{\"Ask\":\"84917.73\",\"Bid\":\"83232.21\",\"LastExecution\":\"84072.94\",\"Date\":\"2025-04-01T08:36:02.8305456Z\",\"NewUnitMargin\":\"83232.21\",\"UnitMarginAsk\":\"84917.73\",\"UnitMarginBid\":\"83232.21\",\"PriceRateID\":\"106439224591\",\"BidDiscounted\":\"84072.94\",\"AskDiscounted\":\"84076.96\",\"UnitMarginBidDiscounted\":\"84072.94\",\"UnitMarginAskDiscounted\":\"84076.96\"}", "id": "f1992278-2c4a-4b8f-92d6-8b99f5e1cb00", "type": "Trading.Instrument.Rate" } ] } ``` ### Prettified Content Field ```json theme={null} { "Ask": "84917.73", "Bid": "83232.21", "LastExecution": "84072.94", "Date": "2025-04-01T08:36:02.8305456Z", "NewUnitMargin": "83232.21", "UnitMarginAsk": "84917.73", "UnitMarginBid": "83232.21", "PriceRateID": "106439224591", "BidDiscounted": "84072.94", "AskDiscounted": "84076.96", "UnitMarginBidDiscounted": "84072.94", "UnitMarginAskDiscounted": "84076.96" } ``` ### Rate Object Schema **Ask** `number \` Current asking price (offer) for the instrument. This is the price at which you can buy the asset. **Bid** `number \` Current bid price for the instrument. This is the price at which you can sell the asset. **LastExecution** `number \` Price of the most recent trade execution for this instrument. **Date** `string \` The date-time of the price in the system. **NewUnitMargin** `number \` *deprecated* USD equivalent of the instrument price. **UnitMarginAsk** `number \` *deprecated* USD equivalent of the instrument ask price. **UnitMarginBid** `number \` *deprecated* USD equivalent of the instrument bid price. **PriceRateID** `integer` Unique identifier of the rate. **BidDiscounted** `number \` *deprecated* Obsolete. **AskDiscounted** `number \` *deprecated* Obsolete. **UnitMarginBidDiscounted** `number \` *deprecated* Obsolete. **UnitMarginAskDiscounted** `number \` *deprecated* Obsolete. ## Transaction Updates Receive real-time updates on transactions and orders from your portfolio. ### Request ```json theme={null} { "id": "ed72693c-1545-4fa1-8a10-aca7cf5419a6", "operation": "Subscribe", "data": { "topics": ["private"], "snapshot": } } ``` ### Response ```json theme={null} { "messages": [ { "topic": "private", "content": "{\"OrderID\":981286176,\"OrderType\":20,\"CID\":32612044,\"StatusID\":11,\"InstrumentID\":1111,\"UnitsToDeduct\":0.0,\"RequestGuid\":\"fca38698-1fcf-407d-b930-3222e57274fa\",\"RequestOccurred\":\"2025-04-01T08:55:53.6910145Z\",\"RequestToken\":\"fca38698-1fcf-407d-b930-3222e57274fa\",\"ErrorCode\":0,\"RequestedUnits\":13.859902,\"ExecutedUnits\":0.0,\"EndRate\":0.0,\"NetProfit\":0.0,\"CloseReason\":0,\"PendingClosePositionIDs\":[2980225895],\"OpenDateTime\":\"2025-04-01T08:55:53.6910145Z\",\"IsInMirror\":false,\"StatusId\":11,\"TotalExternalFees\":0.0,\"TotalExternalTaxes\":0.0,\"LotsToDeduct\":0.0,\"RequestedLots\":13.859902,\"ExecutedLots\":0.0}", "id": "5263070a-c52f-436b-8ca8-10b3bd6d2970", "type": "Trading.OrderForCloseMultiple.Update" } ] } ``` ### Prettified Content Field ```json theme={null} { "OrderID": 981286176, "OrderType": 20, "CID": 32612044, "StatusID": 11, "InstrumentID": 1111, "UnitsToDeduct": 0, "RequestGuid": "fca38698-1fcf-407d-b930-3222e57274fa", "RequestOccurred": "2025-04-01T08:55:53.6910145Z", "RequestToken": "fca38698-1fcf-407d-b930-3222e57274fa", "ErrorCode": 0, "RequestedUnits": 13.859902, "ExecutedUnits": 0, "EndRate": 0, "NetProfit": 0, "CloseReason": 0, "PendingClosePositionIDs": [ 2980225895 ], "OpenDateTime": "2025-04-01T08:55:53.6910145Z", "IsInMirror": false, "StatusId": 11, "TotalExternalFees": 0, "TotalExternalTaxes": 0, "LotsToDeduct": 0, "RequestedLots": 13.859902, "ExecutedLots": 0 } ``` # Create Agent Portfolio Source: https://api-portal.etoro.com/deprecated-api-reference/agent-portfolios/create-agent-portfolio /api-reference/deprecated-openapi.json post /api/v1/agent-portfolios Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- [DEPRECATED — use POST /api/v2/agent-portfolios (scope names) instead] Creates a new agent-portfolio — a dedicated user account that receives its own fixed virtual balance (returned in agentPortfolioVirtualBalance). IMPORTANT: investmentAmountInUsd is the amount deducted from YOUR (the caller's) account balance to copy-trade this agent-portfolio — it is NOT the agent-portfolio's own balance. Positions are mirrored proportionally: e.g. if you invest $2,000 and agentPortfolioVirtualBalance is $10,000, each position is copied at 20% of its size into your account. # Create User Token Source: https://api-portal.etoro.com/deprecated-api-reference/agent-portfolios/create-user-token /api-reference/deprecated-openapi.json post /api/v1/agent-portfolios/{agentPortfolioId}/user-tokens Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- [DEPRECATED — use POST /api/v2/agent-portfolios/{agentPortfolioId}/user-tokens (scope names) instead] Creates a new user token for the specified agent-portfolio. # Update User Token Source: https://api-portal.etoro.com/deprecated-api-reference/agent-portfolios/update-user-token /api-reference/deprecated-openapi.json patch /api/v1/agent-portfolios/{agentPortfolioId}/user-tokens/{userTokenId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- [DEPRECATED — use PATCH /api/v2/agent-portfolios/{agentPortfolioId}/user-tokens/{userTokenId} (scope names) instead] Updates the settings of an existing user token for a agent-portfolio. At least one field must be provided. # Create a comment on a post Source: https://api-portal.etoro.com/deprecated-api-reference/social-feeds/create-a-comment-on-a-post /api-reference/deprecated-openapi.json post /api/v1/reactions/{postId}/comment Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- [DEPRECATED — use POST /api/v1/posts/{postId}/comments instead] Creates a new comment on a specific discussion post. Comments can include text, mentions, tags, and attachments. # Create a new discussion post Source: https://api-portal.etoro.com/deprecated-api-reference/social-feeds/create-a-new-discussion-post /api-reference/deprecated-openapi.json post /api/v1/feeds/post Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 requests per 60 seconds. This is a **dedicated** limit for this endpoint — it is **not shared** with (pooled across) any other endpoint, so the full rate is available to this endpoint alone. --- [DEPRECATED — use POST /api/v1/posts instead] Creates a new discussion post in the feed system. This endpoint allows users to create posts that can be associated with instruments, users, or general discussions. # Get instrument feed posts Source: https://api-portal.etoro.com/deprecated-api-reference/social-feeds/get-instrument-feed-posts /api-reference/deprecated-openapi.json get /api/v1/feeds/instrument/{marketId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **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/feeds/following` - `GET /api/v1/feeds/for-you` - `GET /api/v1/feeds/markets/{marketId}` - `GET /api/v1/feeds/news` - `GET /api/v1/feeds/saved` - `GET /api/v1/feeds/user/{userId}` - `GET /api/v1/feeds/users/{userId}` - `GET /api/v1/feeds/users/{userId}/pinned` --- [DEPRECATED — use GET /api/v1/feeds/markets/{marketId} instead] Retrieves feed posts associated with a specific financial instrument. The feed includes discussions, analyses, and other content related to the instrument. # Get user feed posts Source: https://api-portal.etoro.com/deprecated-api-reference/social-feeds/get-user-feed-posts /api-reference/deprecated-openapi.json get /api/v1/feeds/user/{userId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **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/feeds/following` - `GET /api/v1/feeds/for-you` - `GET /api/v1/feeds/instrument/{marketId}` - `GET /api/v1/feeds/markets/{marketId}` - `GET /api/v1/feeds/news` - `GET /api/v1/feeds/saved` - `GET /api/v1/feeds/users/{userId}` - `GET /api/v1/feeds/users/{userId}/pinned` --- [DEPRECATED — use GET /api/v1/feeds/users/{userId} instead] Retrieves feed posts associated with a specific user. The feed includes the user's discussions, analyses, and other content they have posted. # Cancel pending demo limit order Source: https://api-portal.etoro.com/deprecated-api-reference/trading--demo/cancel-pending-demo-limit-order /api-reference/deprecated-openapi.json delete /api/v1/trading/execution/demo/limit-orders/{orderId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint allows traders to cancel a Market-if-touched order before it is executed. Once canceled, the order will no longer be processed. A 200 response confirms the cancellation request was received, not that the order was cancelled. Confirm with GET /api/v1/trading/info/demo/orders/{orderId}, using the orderId you tried to cancel. # Cancel pending demo open order Source: https://api-portal.etoro.com/deprecated-api-reference/trading--demo/cancel-pending-demo-open-order /api-reference/deprecated-openapi.json delete /api/v1/trading/execution/demo/market-open-orders/{orderId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint allows traders to cancel a market order for open before execution. If the order has already been processed, cancellation will not be possible. A 200 response confirms the cancellation request was received, not that the order was cancelled - it may already have been executed. Confirm with GET /api/v1/trading/info/demo/orders/{orderId}, using the orderId you tried to cancel. # Get order information Source: https://api-portal.etoro.com/deprecated-api-reference/trading--demo/get-order-information /api-reference/deprecated-openapi.json get /api/v1/trading/info/demo/orders/{orderId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **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/close-orders/{orderId}` - `GET /api/v2/trading/info/demo/orders:lookup` --- Retrieves the current state and execution details of an order submitted for the authenticated demo account. Use this endpoint to track whether the order was received, placed, filled, rejected, cancelled, expired, or is still waiting for execution conditions. # Open demo market order by units Source: https://api-portal.etoro.com/deprecated-api-reference/trading--demo/open-demo-market-order-by-units /api-reference/deprecated-openapi.json post /api/v1/trading/execution/demo/market-open-orders/by-units Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint allows traders to place a market order to open a position by specifying the number of units (rather than an amount in cash). The trade is executed at the current market price, and optional settings like leverage, stop-loss, and take-profit can be applied. A 200 response means the order was submitted, not that the position was opened. Confirm the outcome with GET /api/v1/trading/info/demo/orders/{orderId}, using the orderID returned under orderForOpen. # Open demo order by amount Source: https://api-portal.etoro.com/deprecated-api-reference/trading--demo/open-demo-order-by-amount /api-reference/deprecated-openapi.json post /api/v1/trading/execution/demo/market-open-orders/by-amount Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/limit-orders` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- This endpoint allows traders to place a market order to open a position by specifying the investment amount instead of specifying the number of units. The trade will be executed at the market price, and leverage, stop-loss, and take-profit settings can be applied. A 200 response means the order was submitted, not that the position was opened. Confirm the outcome with GET /api/v1/trading/info/demo/orders/{orderId}, using the orderID returned under orderForOpen. # Place demo limit order (market-if-touched) Source: https://api-portal.etoro.com/deprecated-api-reference/trading--demo/place-demo-limit-order-market-if-touched /api-reference/deprecated-openapi.json post /api/v1/trading/execution/demo/limit-orders Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/demo/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/demo/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/demo/orders/{orderId}` - `DELETE /api/v3/trading/execution/demo/orders/{orderId}` - `POST /api/v1/trading/execution/demo/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/demo/market-open-orders/by-amount` - `POST /api/v1/trading/execution/demo/market-open-orders/by-units` - `POST /api/v2/trading/execution/demo/orders` - `POST /api/v3/trading/execution/demo/orders` --- A Market-if-touched order is an order to open a new long or short position when a specific price or better appears in the Market. The price threshold is used to trigger a Market Order. This endpoint allows traders to set up Market-if-touched orders with parameters like leverage, stop-loss, and take-profit settings. A 200 response means the order was submitted successfully, not that it was created successfully, triggered, or executed: a market-if-touched order rests until the threshold rate is reached. Confirm the outcome with GET /api/v1/trading/info/demo/orders/{orderId}, using the returned orderId. # Cancel pending limit order Source: https://api-portal.etoro.com/deprecated-api-reference/trading--real/cancel-pending-limit-order /api-reference/deprecated-openapi.json delete /api/v1/trading/execution/limit-orders/{orderId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- This endpoint allows traders to cancel a Market-if-touched order before it is executed. Once canceled, the order will no longer be processed. A 200 response confirms the cancellation request was received, not that the order was cancelled. Confirm with GET /api/v1/trading/info/real/orders/{orderId}, using the orderId you tried to cancel. # Cancel pending open order Source: https://api-portal.etoro.com/deprecated-api-reference/trading--real/cancel-pending-open-order /api-reference/deprecated-openapi.json delete /api/v1/trading/execution/market-open-orders/{orderId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- This endpoint allows traders to cancel a market order for open before execution. If the order has already been processed, cancellation will not be possible. A 200 response confirms the cancellation request was received, not that the order was cancelled - it may already have been executed. Confirm with GET /api/v1/trading/info/real/orders/{orderId}, using the orderId you tried to cancel. # Get order information Source: https://api-portal.etoro.com/deprecated-api-reference/trading--real/get-order-information /api-reference/deprecated-openapi.json get /api/v1/trading/info/real/orders/{orderId} Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **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/real/close-orders/{orderId}` - `GET /api/v2/trading/info/orders:lookup` --- Retrieves the current state and execution details of an order submitted for the authenticated real account. Use this endpoint to track whether the order was received, placed, filled, rejected, cancelled, expired, or is still waiting for execution conditions. # Open market order by cash amount Source: https://api-portal.etoro.com/deprecated-api-reference/trading--real/open-market-order-by-cash-amount /api-reference/deprecated-openapi.json post /api/v1/trading/execution/market-open-orders/by-amount Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- This endpoint allows traders to place a market order to open a position by specifying the investment amount instead of specifying the number of units. The trade will be executed at the market price, and leverage, stop-loss, and take-profit settings can be applied. A 200 response means the order was submitted, not that the position was opened. Confirm the outcome with GET /api/v1/trading/info/real/orders/{orderId}, using the orderID returned under orderForOpen. # Open market order by units Source: https://api-portal.etoro.com/deprecated-api-reference/trading--real/open-market-order-by-units /api-reference/deprecated-openapi.json post /api/v1/trading/execution/market-open-orders/by-units Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/limit-orders` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- This endpoint allows traders to place a market order to open a position by specifying the number of units (rather than an amount in cash). The trade is executed at the current market price, and optional settings like leverage, stop-loss, and take-profit can be applied. A 200 response means the order was submitted, not that the position was opened. Confirm the outcome with GET /api/v1/trading/info/real/orders/{orderId}, using the orderID returned under orderForOpen. # Place limit order (market-if-touched) Source: https://api-portal.etoro.com/deprecated-api-reference/trading--real/place-limit-order-market-if-touched /api-reference/deprecated-openapi.json post /api/v1/trading/execution/limit-orders Deprecated: This endpoint is marked deprecated in the etoro Public API Swagger. Prefer the current replacement endpoints where available. **Rate limit:** 20 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: - `DELETE /api/v1/trading/execution/limit-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-close-orders/{orderId}` - `DELETE /api/v1/trading/execution/market-open-orders/{orderId}` - `DELETE /api/v2/trading/execution/orders/{orderId}` - `DELETE /api/v3/trading/execution/orders/{orderId}` - `POST /api/v1/trading/execution/market-close-orders/positions/{positionId}` - `POST /api/v1/trading/execution/market-open-orders/by-amount` - `POST /api/v1/trading/execution/market-open-orders/by-units` - `POST /api/v2/trading/execution/orders` - `POST /api/v3/trading/execution/orders` --- A Market-if-touched order is an order to open a new long or short position when a specific price or better appears in the Market. The price threshold is used to trigger a Market Order. This endpoint allows traders to set up Market-if-touched orders with parameters like leverage, stop-loss, and take-profit settings. A 200 response means the order was submitted successfully, not that it was created successfully, triggered, or executed: a market-if-touched order rests until the threshold rate is reached. Confirm the outcome with GET /api/v1/trading/info/real/orders/{orderId}, using the returned orderId. # Introduction Source: https://api-portal.etoro.com/index Welcome to the etoro Developer Portal Welcome to the etoro Public API. Whether you are building an algorithmic trading bot, a custom portfolio dashboard, or integrating etoro data into your fintech app, our API provides the tools you need to access real-time market data, manage orders, and tap into our unique social trading features. > [!NOTE] > > Note: To access the API, your etoro account must be verified. If the API key isn't showing in your settings, please finish the verification process. ### What can you build? * **Algorithmic Trading:** Execute trades programmatically with low-latency order placement. * **Social Analytics:** Analyze the performance of Pro Investors and Smart Portfolios. * **Market Monitors:** Stream real-time price data for Crypto, Stocks, ETFs, Commodities, and more. * **Portfolio Management:** Automate rebalancing and track P\&L across your portfolio. * **Watchlists:** Retrieve and manage private and public watchlists. * **Feeds:** Access user and instrument feed posts and write your own posts. ### Explore the Documentation > **[Find Instrument ID](/core/guides/get-instrument-id)** > > Learn how to resolve ticker symbols (e.g. 'BTC') to Instrument IDs. > **[Open & Close Orders](/core/guides/market-orders)** > > Programmatically execute trades and manage your positions. > **[Manage Watchlists](/core/guides/watchlists)** > > Create, update, and organize your custom watchlists. > **[API Reference](/api-reference)** > > Explore the full OpenAPI specification and endpoint details. # Create a cash account Source: https://api-portal.etoro.com/partners-api-reference/cash-accounts/create-a-cash-account /api-reference/partners-openapi.json post /api/v1/money/accounts/cash **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Initiates the creation of a cash account. The user must be eligible (IbanEligible or CardAndIbanEligible). Returns 202 Accepted with a requestReferenceId for polling status. # Get cash account by id Source: https://api-portal.etoro.com/partners-api-reference/cash-accounts/get-cash-account-by-id /api-reference/partners-openapi.json get /api/v1/money/accounts/cash/{accountId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a single cash account. The response body is identical in shape to one element of `accounts` from GET /api/v1/money/accounts/cash (CashAccount). Path accountId must match CashAccount.id for that element. # Get cash account creation eligibility Source: https://api-portal.etoro.com/partners-api-reference/cash-accounts/get-cash-account-creation-eligibility /api-reference/partners-openapi.json get /api/v1/money/accounts/cash/eligibility **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the user's eligibility to create a cash account, along with prerequisites (T&C), contact info, and basic user info needed for account creation. # Get cash account creation status Source: https://api-portal.etoro.com/partners-api-reference/cash-accounts/get-cash-account-creation-status /api-reference/partners-openapi.json get /api/v1/money/accounts/cash/status **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Polls the creation status of a previously submitted cash account creation request. Returns the account details when status is Success. # Get user cash accounts Source: https://api-portal.etoro.com/partners-api-reference/cash-accounts/get-user-cash-accounts /api-reference/partners-openapi.json get /api/v1/money/accounts/cash **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the eligibility of a user to create a cash account, and lists the existing cash accounts including the related bank account details and the cards related to each account. The user is identified from the OAuth token. # Crypto deposit eligibility Source: https://api-portal.etoro.com/partners-api-reference/crypto-deposit/crypto-deposit-eligibility /api-reference/partners-openapi.json get /api/v1/money/deposit/crypto/eligibility **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns deposit eligibility and the supported assets with per-asset min/max amounts for the authenticated user. Users who are not allowed to deposit receive eligibilityStatus=Ineligible and an empty asset list. # Initiate a crypto deposit intent Source: https://api-portal.etoro.com/partners-api-reference/crypto-deposit/initiate-a-crypto-deposit-intent /api-reference/partners-openapi.json post /api/v1/money/deposit/crypto/intent **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Initiates a crypto deposit intent for the authenticated user. Returns a wallet address to send crypto to, or triggers wallet creation if one does not exist. The user is identified from the OAuth token. # Lookup crypto deposit by request reference ID Source: https://api-portal.etoro.com/partners-api-reference/crypto-deposit/lookup-crypto-deposit-by-request-reference-id /api-reference/partners-openapi.json get /api/v1/money/deposit/crypto:lookup **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Looks up a previously initiated crypto deposit intent by its caller-provided reference identifier. Returns the current status and destination wallet address when available. # Submit trading account withdrawal Source: https://api-portal.etoro.com/partners-api-reference/crypto-withdrawals/submit-trading-account-withdrawal /api-reference/partners-openapi.json post /api/v1/money/withdraw/crypto/accounts/trading **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Initiates a withdrawal from the trading account for the given wallet. Processing is asynchronous; poll status with requestReferenceId. # Trading account withdrawal approval process eligibility Source: https://api-portal.etoro.com/partners-api-reference/crypto-withdrawals/trading-account-withdrawal-approval-process-eligibility /api-reference/partners-openapi.json get /api/v1/money/withdraw/crypto/accounts/trading/approval-process-eligibility **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns whether the withdrawal for the given wallet type, amount, and currency requires instant or manual approval processing. # Trading account withdrawal eligibility Source: https://api-portal.etoro.com/partners-api-reference/crypto-withdrawals/trading-account-withdrawal-eligibility /api-reference/partners-openapi.json get /api/v1/money/withdraw/crypto/accounts/trading/eligibility **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns withdrawal eligibility, withdrawable amount, min/max limits, and any prerequisites (e.g. T&C to accept) for the authenticated user's trading account. # Trading account withdrawal status Source: https://api-portal.etoro.com/partners-api-reference/crypto-withdrawals/trading-account-withdrawal-status /api-reference/partners-openapi.json get /api/v1/money/withdraw/crypto/accounts/trading/status **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns Pending, Success, or Failure for the withdrawal identified by requestReferenceId. # Direct email verification (trusted partner) Source: https://api-portal.etoro.com/partners-api-reference/email-verification/direct-email-verification-trusted-partner /api-reference/partners-openapi.json post /api/v1/users/email/verifications/direct-confirmations **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: - `POST /api/v1/users/email/verifications` - `POST /api/v1/users/email/verifications/confirmations` --- Allows trusted partners to directly verify a user's email without OTP. **SECURITY - Partner Ownership Validation:** The system validates that the user was created by this partner (affiliateId match). A partner can ONLY verify emails for users originally created by that partner. # Send email verification code Source: https://api-portal.etoro.com/partners-api-reference/email-verification/send-email-verification-code /api-reference/partners-openapi.json post /api/v1/users/email/verifications **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: - `POST /api/v1/users/email/verifications/confirmations` - `POST /api/v1/users/email/verifications/direct-confirmations` --- Sends a verification code to the user's registered email address. Returns an otpId to use when verifying the code. **SECURITY:** This endpoint can ONLY be used to verify the email address set during registration. Changing an existing verified email is NOT permitted through this endpoint. # Verify email with OTP code Source: https://api-portal.etoro.com/partners-api-reference/email-verification/verify-email-with-otp-code /api-reference/partners-openapi.json post /api/v1/users/email/verifications/confirmations **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: - `POST /api/v1/users/email/verifications` - `POST /api/v1/users/email/verifications/direct-confirmations` --- Verifies the email address using the OTP code sent to the user's email. The otpId from the send step is required. # Get account-specific first-time deposit(s) Source: https://api-portal.etoro.com/partners-api-reference/ftd/get-account-specific-first-time-deposits /api-reference/partners-openapi.json get /api/v1/money/accounts/{accountType}/first-time-deposit **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the FTD record(s) for the given account type. A user may have multiple accounts of the same type so the response is an array. Optionally filter by accountId. # Get global first-time deposit Source: https://api-portal.etoro.com/partners-api-reference/ftd/get-global-first-time-deposit /api-reference/partners-openapi.json get /api/v1/money/first-time-deposit **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the global FTD record for the authenticated user - their first-ever deposit across all etoro account types. # Notify deposit from partner (async) Source: https://api-portal.etoro.com/partners-api-reference/ftd/notify-deposit-from-partner-async /api-reference/partners-openapi.json post /api/v1/money/deposit/notify **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Partners call this endpoint to notify etoro about an approved deposit made by a user. The system processes the deposit in the background and determines FTD status. # Get Contact Info Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-contact-info /api-reference/partners-openapi.json get /api/v1/users/contact-info **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the authenticated user's contact information (email and phone number, read-only). # Get customer KYC gaps Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-customer-kyc-gaps /api-reference/partners-openapi.json get /api/v1/kyc/gaps **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the authenticated user's compliance gaps (requirements and user interactions), ordered by priority. Requirements are filtered to only include those with status Required or Expired. # Get KYC Address Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-address /api-reference/partners-openapi.json get /api/v1/users/address/{addressType} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the authenticated user's KYC address for the specified address type. # Get KYC Fields Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-fields /api-reference/partners-openapi.json post /api/v1/kyc-fields **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieve KYC fields for a user based on their userId. # Get KYC Fields (V2) Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-fields-v2 /api-reference/partners-openapi.json post /api/v2/kyc-fields **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieve KYC fields for a user based on their userId. V2 version of the endpoint. # Get KYC Metadata Mappings Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-metadata-mappings /api-reference/partners-openapi.json get /api/v2/kyc/mappers **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves all KYC metadata ID-to-name lookup mappings. Response cached 60s. Supports ETag caching via If-None-Match; returns 304 if unchanged. # Get KYC Personal Details Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-personal-details /api-reference/partners-openapi.json get /api/v1/users/personaldetails **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the authenticated user's KYC personal details, including identification, citizenship and tax information. # Get KYC question-answers mapping by question ID Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-question-answers-mapping-by-question-id /api-reference/partners-openapi.json get /api/v1/kyc/questions/{questionId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves a single KYC question and its associated answer identifiers by question ID, including whether the question supports multiple answer selection. Response cached 60s. Supports ETag caching via If-None-Match; returns 304 if unchanged. # Get KYC Questionnaire Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-questionnaire /api-reference/partners-openapi.json get /api/v1/kyc-data/questionnaire **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the KYC questionnaire for the authenticated user. # Get KYC questions-answers mapping Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-questions-answers-mapping /api-reference/partners-openapi.json get /api/v1/kyc/questions **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves the mapping of KYC question identifiers to their associated answer identifiers, including whether each question supports multiple answer selection. Response cached 60s. Supports ETag caching via If-None-Match; returns 304 if unchanged. # Get KYC Regulations Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-kyc-regulations /api-reference/partners-openapi.json get /api/v1/kyc/regulations **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Retrieves all KYC regulation definitions, including the countries and regions each regulation applies to. # Get requirement categories dictionary Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-requirement-categories-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/requirements/category **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the list of supported requirement categories as id/name pairs. # Get requirement overview statuses dictionary Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-requirement-overview-statuses-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/requirements/overviewStatus **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the list of supported requirement overview statuses as id/name pairs. # Get requirement status reasons dictionary Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-requirement-status-reasons-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/requirements/statusReason **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the list of supported requirement status reasons as id/name pairs. # Get requirement types dictionary Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-requirement-types-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/requirements/type **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the list of supported requirement types as id/name pairs. # Get Single KYC Questionnaire Question Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-single-kyc-questionnaire-question /api-reference/partners-openapi.json get /api/v1/kyc-data/questionnaire/{questionId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns a single question (with its possible answers and the user's current selection state) from the KYC questionnaire by question ID. Use GET /api/v1/kyc-data/questionnaire to fetch the full questionnaire in one call. # Get user interaction types dictionary Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-user-interaction-types-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/userInteractions/type **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the list of supported user interaction types as id/name pairs. # Get Verification Level 3 Gaps Source: https://api-portal.etoro.com/partners-api-reference/kyc/get-verification-level-3-gaps /api-reference/partners-openapi.json get /api/v2/kyc/verification-level-gaps **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the user's current verification level and the list of missing requirements needed to reach verification level 3. # Submit KYC Questionnaire Answers Source: https://api-portal.etoro.com/partners-api-reference/kyc/submit-kyc-questionnaire-answers /api-reference/partners-openapi.json post /api/v1/kyc-data/questionnaire **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Submits the authenticated user's answers to the KYC questionnaire in a single request. Each answer is applied individually upstream. Returns 200 when every answer is accepted; returns 422 when one or more answers are rejected (partial or full), with a per-question breakdown serialized as a JSON string into error.details. A 207 Multi-Status response is never returned. # Submit Single KYC Questionnaire Answer Source: https://api-portal.etoro.com/partners-api-reference/kyc/submit-single-kyc-questionnaire-answer /api-reference/partners-openapi.json post /api/v1/kyc-data/questionnaire/{questionId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Submits the authenticated user's answer for a single question in the KYC questionnaire. Use this when answering one question at a time; use POST /api/v1/kyc-data/questionnaire to submit multiple answers in one request. # Update KYC Address Source: https://api-portal.etoro.com/partners-api-reference/kyc/update-kyc-address /api-reference/partners-openapi.json put /api/v1/users/address/{addressType} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Updates the authenticated user's KYC address for the specified address type. Required fields: countryCode, city, address. # Update KYC Personal Details Source: https://api-portal.etoro.com/partners-api-reference/kyc/update-kyc-personal-details /api-reference/partners-openapi.json put /api/v1/users/personaldetails **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Updates the authenticated user's KYC personal details. Supports partial updates - any subset of the fields may be supplied and omitted fields are left unchanged. Tax identifications are supplied via taxIds[] and support multiple jurisdictions; when present, taxIds[] replaces the full set of tax identifications on the user record. The deprecated single taxId/taxIdCountry fields are still accepted for backward compatibility and are used only when taxIds[] is absent. Tax-id number format is validated per country by the upstream KYC service. # Add document classification Source: https://api-portal.etoro.com/partners-api-reference/ops/add-document-classification /api-reference/partners-openapi.json post /api/v1/kyc/documents/{documentId}/classifications **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Adds a classification (e.g. Proof of Address, Proof of Identity) to an existing document. # Download document Source: https://api-portal.etoro.com/partners-api-reference/ops/download-document /api-reference/partners-openapi.json get /api/v1/kyc/document/{documentId} **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Downloads a document file by document ID. # Get application identifiers dictionary Source: https://api-portal.etoro.com/partners-api-reference/ops/get-application-identifiers-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/documents/applicationIdentifier **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. # Get customer documents Source: https://api-portal.etoro.com/partners-api-reference/ops/get-customer-documents /api-reference/partners-openapi.json get /api/v1/kyc/documents **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the authenticated user's compliance documents and document status. # Get document sides dictionary Source: https://api-portal.etoro.com/partners-api-reference/ops/get-document-sides-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/documents/side **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. # Get document subtypes dictionary Source: https://api-portal.etoro.com/partners-api-reference/ops/get-document-subtypes-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/documents/subType **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. # Get document types dictionary Source: https://api-portal.etoro.com/partners-api-reference/ops/get-document-types-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/documents/type **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. # Get electronic verification status Source: https://api-portal.etoro.com/partners-api-reference/ops/get-electronic-verification-status /api-reference/partners-openapi.json get /api/v1/kyc/ev **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the authenticated user's electronic verification (EV) status. # Get EV statuses dictionary Source: https://api-portal.etoro.com/partners-api-reference/ops/get-ev-statuses-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/ev/status **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the list of supported electronic verification (EV) match statuses as id/name pairs. # Get screening status Source: https://api-portal.etoro.com/partners-api-reference/ops/get-screening-status /api-reference/partners-openapi.json get /api/v1/kyc/screening **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the authenticated user's screening status. # Get screening statuses dictionary Source: https://api-portal.etoro.com/partners-api-reference/ops/get-screening-statuses-dictionary /api-reference/partners-openapi.json get /api/v1/kyc/dictionary/screening/status **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns the list of supported screening statuses as id/name pairs. # Initiate GDPR user deletion Source: https://api-portal.etoro.com/partners-api-reference/ops/initiate-gdpr-user-deletion /api-reference/partners-openapi.json delete /api/v1/gdpr/users **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Initiates a public GDPR deletion request for the authenticated user. The user's GCID is resolved from the token and forwarded to the GDPR service; the request body must include GCID and the target account CID. # Send user to electronic verification Source: https://api-portal.etoro.com/partners-api-reference/ops/send-user-to-electronic-verification /api-reference/partners-openapi.json post /api/v1/kyc/ev **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Initiates sending the authenticated user to electronic verification (EV). # Send user to screening Source: https://api-portal.etoro.com/partners-api-reference/ops/send-user-to-screening /api-reference/partners-openapi.json post /api/v1/kyc/screening **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Initiates sending the authenticated user to screening. # Upload document Source: https://api-portal.etoro.com/partners-api-reference/ops/upload-document /api-reference/partners-openapi.json post /api/v1/kyc/document **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Uploads a compliance document for the authenticated user. # Direct phone verification (trusted partner) Source: https://api-portal.etoro.com/partners-api-reference/phone-verification/direct-phone-verification-trusted-partner /api-reference/partners-openapi.json post /api/v1/users/phone/verifications/direct-confirmations **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: - `POST /api/v1/users/phone/verifications` - `POST /api/v1/users/phone/verifications/confirmations` --- Allows trusted partners to directly verify a user's phone number without OTP. **SECURITY - Partner Ownership Validation:** The system validates that the user was created by this partner (affiliateId match). A partner can ONLY verify phone numbers for users originally created by that partner. # Initiate phone verification Source: https://api-portal.etoro.com/partners-api-reference/phone-verification/initiate-phone-verification /api-reference/partners-openapi.json post /api/v1/users/phone/verifications **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: - `POST /api/v1/users/phone/verifications/confirmations` - `POST /api/v1/users/phone/verifications/direct-confirmations` --- Sends a verification code to the specified phone number. Returns a referenceId to use when verifying the code. **SECURITY:** This endpoint can ONLY be used to set a phone number for users who do not yet have a verified phone number. Changing an existing verified phone number is NOT permitted through this endpoint. To change an existing phone number, users must contact Customer Support. # Verify phone with verification code Source: https://api-portal.etoro.com/partners-api-reference/phone-verification/verify-phone-with-verification-code /api-reference/partners-openapi.json post /api/v1/users/phone/verifications/confirmations **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: - `POST /api/v1/users/phone/verifications` - `POST /api/v1/users/phone/verifications/direct-confirmations` --- Verifies the phone number using the verification code sent during initiation. The referenceId from the initiate step is required. # Get registration eligibility Source: https://api-portal.etoro.com/partners-api-reference/registration/get-registration-eligibility /api-reference/partners-openapi.json get /api/v1/registration/users/eligibility **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Returns eligibility, regulation id, the list of documents that must be signed, and the affiliate id resolved from the calling partner. # Partner registers a new etoro user Source: https://api-portal.etoro.com/partners-api-reference/registration/partner-registers-a-new-etoro-user /api-reference/partners-openapi.json post /api/v1/registration/users **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Registers a user on behalf of the partner. No password is supplied; etoro generates one. The synchronous response includes a user-scoped token bundle (access token, plus an ID token for the registration flow) issued by sts-idp with claims scoped by the SSO client_id resolved from X-ClientId, so the partner can chain the rest of the flow without an interactive login. # Create Account Source: https://api-portal.etoro.com/partners-api-reference/sub-accounts/create-account /api-reference/partners-openapi.json post /api/v1/sub-accounts **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Create an account, back office operation # Delete Accounts Source: https://api-portal.etoro.com/partners-api-reference/sub-accounts/delete-accounts /api-reference/partners-openapi.json delete /api/v1/sub-accounts **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Deletes all accounts by Gcid + ProviderName # Submit trusted partner verification Source: https://api-portal.etoro.com/partners-api-reference/verification/submit-trusted-partner-verification /api-reference/partners-openapi.json post /api/v1/users/verification **Rate limit:** 60 requests per 60 seconds. This is the **default shared quota** — it is shared with every other endpoint that has no dedicated limit, so requests across those endpoints all draw from the same budget. --- Submits trusted partner verification for the authenticated user. When the user is already at verification level 3, returns an idempotent success response without re-processing. Otherwise requires verification level 2, uploads POI/POA trusted-partner documents, and upgrades the user to level 3. # Partners API Changelog Source: https://api-portal.etoro.com/partners/changelog New endpoints, capabilities, and breaking changes in the etoro Partners API. What changed in the etoro Partners API, newest first. Each entry lists the API version the change shipped in, so you can line it up against the version shown in the Partners API reference. The Partners API versions independently of the Core API, which has its own [changelog](/core/changelog). **October 21, 2026** ## Events from etoro Partners that consume outbound account events can now follow the delivery contract and message schema for the Azure Event Hub etoro publishes to. * [Events from etoro](/partners/events-from-etoro) — Event Hub delivery, envelope, and operational rules * [KYC](/partners/events/kyc-updates) — payload and field names for the KycUpdates event **October 8, 2026** ## Check crypto deposit eligibility You can now query whether an account is eligible to deposit crypto. * `GET /api/v1/money/deposit/crypto/eligibility` — crypto deposit eligibility **August 6, 2026** ## The Partners API reference is published The Partners API now has its own reference section, generated from the same pipeline as the Core API and versioned independently of it. Entries here cover the Partners API only. Changes to the Core API stay in the [Core API changelog](/core/changelog). # Overview Source: https://api-portal.etoro.com/partners/events-from-etoro How etoro delivers account events to your Azure Event Hub. Each event payload is documented under Events. ## Purpose and scope When an associated user's data changes on etoro, etoro can publish an event to your platform. Delivery is **push onto Azure Event Hub**: etoro writes the message, and your consumer reads it. This is the opposite direction from [Reporting events to etoro](/partners/integration#reporting-events-to-etoro), where your backend calls the Partners API. Event delivery is provisioned per partner. If your integration agreement does not include outbound events, this page does not apply until etoro enables it for your application. > [!NOTE] > > Connection details — Event Hub namespace, hub name, consumer group, and access material — are issued by your etoro contact when the integration is provisioned. They are not self-service and are not listed in this portal. ## Delivery | Item | Contract | | - | - | | Transport | Azure Event Hub | | Direction | etoro publishes; the partner consumes | | Hub | One Event Hub per partner application, dedicated to that partner | | Payload | JSON body on each Event Hub message | | User identity | `eventMetadata.externalUserId` — the same opaque handle used elsewhere in the partner integration. Never a customer id from etoro | etoro publishes an event only when the user has an associated account on your platform **and** the change is relevant to the field set approved for your application. If neither condition holds, no message is written to your hub. ## Message envelope Every message body is a JSON object with two properties: | Field | Type | Description | | - | - | - | | `eventData` | string | A **JSON-encoded string** of the event-specific payload. Parse the outer object first, then parse this string a second time. | | `eventMetadata` | object | Delivery metadata shared by every event type | ### `eventMetadata` | Field | Type | Description | | - | - | - | | `correlationId` | string (UUID) | Stable identifier for this event. Retain it for support and reconciliation. | | `eventType` | string | Discriminator for the payload inside `eventData`. Each type is documented under Events. The current one is [KYC](/partners/events/kyc-updates). | | `createdAt` | string (date-time) | When etoro created the event, UTC, ISO 8601 | | `eventDataVersion` | string | Version of the `eventData` contract for this `eventType`. Treat unknown versions as unsupported until your etoro contact confirms them. | | `externalUserId` | string | The associated user on your side | ### Example ```json theme={null} { "eventData": "", "eventMetadata": { "correlationId": "8f1c2a40-6b2e-4d1a-9c3e-1a2b3c4d5e6f", "eventType": "", "createdAt": "2026-10-21T08:03:00.0000000Z", "eventDataVersion": "", "externalUserId": "" } } ``` Keys are camelCase. Consumers should keep advancing the partition when they see an unknown `eventType` or `eventDataVersion`, and confirm support with their etoro contact before handling new ones. Additional optional fields may appear in later versions. The payload inside `eventData` depends on `eventType` and is documented on that event's page under Events. ## Operational rules **1. Parse the envelope, then parse eventData** `eventData` is a string. A single `JSON.parse` (or equivalent) leaves you with a string, not an object. Deserialize it again before reading the payload for that `eventType`. **2. Branch on eventType** Route handling by `eventMetadata.eventType`. Ignore event types your integration does not implement, and keep the consumer advancing so an unknown type does not block the partition. **3. Key users by externalUserId** Match the event to your user record with `eventMetadata.externalUserId`. Do not expect an etoro customer id in the payload. **4. Treat the message as a change signal** An event names what changed. It is not a full snapshot of the user, and it does not include the new values. Read those through the Partners API only where your integration is approved to. **5. Retain correlationId** Store `correlationId` with your processing record. It is the reference etoro uses when tracing whether a given change was delivered. ## Related > **[Reporting events to etoro](/partners/integration#reporting-events-to-etoro)** > > The partner-to-etoro direction: deposit notifications and related reporting over the Partners API. > **[Partner integration flow](/partners/integration)** > > Non-interactive tokens, account association, and data-sharing rules. > **[Data sharing and PII](/partners/integration#data-sharing-and-pii)** > > What personal data a partner may receive, and under which approval. > **[KYC](/partners/events/kyc-updates)** > > Payload and field names for the KycUpdates event. > **[Partners API reference](/partners-api-reference)** > > REST operations for reading approved KYC and account data after an event. # KycUpdates Source: https://api-portal.etoro.com/partners/events/kyc-updates Payload and field names for the KycUpdates event, under Events / KYC. Published when one or more KYC-related fields change for an associated user. Delivery, the shared envelope, and how to consume the Event Hub are in [Overview](/partners/events-from-etoro). `eventMetadata.eventType` is `KycUpdates`. `eventMetadata.eventDataVersion` for this payload is `1`. ```json theme={null} { "eventData": "{\"updatedKycFields\":[{\"name\":\"\"}]}", "eventMetadata": { "correlationId": "8f1c2a40-6b2e-4d1a-9c3e-1a2b3c4d5e6f", "eventType": "KycUpdates", "createdAt": "2026-10-21T08:03:00.0000000Z", "eventDataVersion": "1", "externalUserId": "" } } ``` ## `eventData` `eventData` is a JSON string. Parse it after the envelope. ```json theme={null} { "updatedKycFields": [ { "name": "" } ] } ``` | Field | Type | Description | | - | - | - | | `updatedKycFields` | array | Fields that changed in this event | | `updatedKycFields[].name` | string | Field name agreed for your application. **Names only** — the new value is not included | The notification tells you *that* a field changed. It does not carry the new value. Where your integration is approved to read the current value, fetch it through the Partners API with the scopes granted for that purpose. See [Data sharing and PII](/partners/integration#data-sharing-and-pii). The set of `name` values is configured per application. A message is published to your hub only when at least one changed field is in that set. The array lists every changed field in the source event; handle the names your agreement covers and ignore the rest. Your etoro contact provides the allow-list. ## Field names These are the names a `KycUpdates` event can carry today. Your allow-list is a subset of this catalog, set per application. Do not assume every row is enabled for you. > [!NOTE] > > Names can be added. Ignore a name you do not handle, and keep the consumer moving. | Name | | - | | `firstName` | | `middleName` | | `lastName` | | `dateOfBirth` | | `gender` | | `email` | | `phone` | | `address` | | `buildingNumber` | | `city` | | `zip` | | `state` | | `countryOfBirth` | | `countryOfResidence` | | `countryOfCitizenship` | | `designatedRegulation` | | `playerStatus` | | `verificationLevel` | | `weekendFeePercentage` | Some names are not a fixed list. The prefix is stable; the suffix comes from the underlying field or question. | Prefix | `name` | | - | - | | `extendedUserField_` | `extendedUserField_` | | `customerAnswer_` | `customerAnswer_` | # Register users, submit KYC, and sign them in Source: https://api-portal.etoro.com/partners/guides/user-onboarding End-to-end guide for a partner that creates etoro users from its own product, completes KYC and verification on their behalf, and opens etoro for them already signed in. ## Overview This guide covers the journey for a partner that owns the customer relationship in its own product and uses etoro as the brokerage and identity layer underneath. The user never has to register on etoro first. The journey has two parts, and they run on different channels: | Part | Channel | What it achieves | | - | - | - | | **A. Account and KYC** | Partner backend to etoro APIs | Create the etoro user, prepare the profile, and submit verification evidence | | **B. Silent login** | User's browser, with the partner backend in the middle | Open etoro in the user's browser already signed in, with no password prompt | ```text theme={null} Partner backend etoro 1. Obtain a partner token ----------------------> client credentials 2. Check eligibility and consent documents ------> GET /registration/users/eligibility 3. Register the user ----------------------------> POST /registration/users 4. Issue a non-interactive token (NIT) ----------> user credential for later calls 5. Submit profile, KYC and verification ---------> personal details, email, phone, verification Browser + partner backend etoro 6. Browser POSTs silent-login initiate ----------> etoro sets a short-lived cookie 7. Browser follows redirectUrl back with tid 8. Partner backend exchanges tid for a one-time token 9. Browser opens the returned verify URL --------> user is signed in ``` > [!NOTE] > > Access is provisioned per partner. Before you start, your etoro contact must have set up your application (client credentials and redirect URIs), the scopes below, your API key, and the allow-listing of your egress IP addresses. See [Before you start](#before-you-start). All endpoints in this guide are production endpoints. The authorization server is `https://www.etoro.com`; the API is `https://public-api.etoro.com`. ## Before you start Ask your etoro contact to confirm each of the following: **1. Application and credentials** A `client_id` and `client_secret` for your application, and the exact redirect URI or URIs you will use for silent login. Keep the secret on your backend only. **2. Scopes** The scopes this journey uses are listed below; the full scope map is in [Permitted operations and scopes](/partners/integration#permitted-operations-and-scopes). A scope outside your grant is rejected. | Used for | Scope | | - | - | | Registration | `etoro-public:partner:registration:read`, `etoro-public:partner:registration:write` | | Personal details and address | `etoro-public:verification.personaldetails:read` / `:write`, `etoro-public:verification.address:read` / `:write` | | KYC questionnaire | `etoro-public:kyc:read`, `etoro-public:kyc:write`, `etoro-public:kyc:questions:read`, `etoro-public:kyc:answers:read` / `:write`, `etoro-public:kyc:regulations:read` | | Trusted verification | `etoro-public:verification.trusted.email:write`, `etoro-public:verification.trusted.phone:write`, `etoro-public:verification:trusted:user:write` | | Silent login | No scope on the call. The application must be enabled for cookie-bound silent login, and the callback URI must be registered | **3. API key and IP allow-listing** An `x-api-key` for your application, and your egress addresses registered with etoro, as described in the [integration prerequisites](/partners/integration#prerequisites). **4. Trusted-partner entitlement** Direct email and phone confirmation, and trusted user verification, are available only to partners etoro has approved as trusted, and only for users your application created. ## Part A: Create the user and submit KYC ### 1. Obtain a partner token Authenticate your application with the OAuth 2.0 client credentials grant. No end user is involved at this stage. ```bash theme={null} curl -X POST "https://www.etoro.com/api/sso/v1/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ --data-urlencode "grant_type=client_credentials" \ --data-urlencode "client_id=" \ --data-urlencode "client_secret=" ``` The response contains an `access_token` and the scopes granted to your application. Send the client secret in the form body, as above, or as HTTP Basic — not both. Request a new token when it expires. ### 2. Check eligibility and get the consent documents Which legal documents a user must accept depends on their country. Always fetch them for the country you are onboarding; never hard-code document identifiers. ```bash theme={null} curl -X GET "https://public-api.etoro.com/api/v1/registration/users/eligibility?countryIso=AU" \ -H "x-request-id: " \ -H "Authorization: Bearer " ``` ```json Response 200 theme={null} { "countryIso": "AU", "eligibility": { "blocked": false, "restricted": false }, "documents": [ { "documentId": 279, "type": "PrivacyPolicy" }, { "documentId": 280, "type": "CookiePolicy" } ] } ``` If `blocked` or `restricted` is `true`, do not continue to registration for that country. Present every returned document to the user, and record the time they accepted it and their IP address. ### 3. Register the user Send one `consents` entry for **every** document returned in step 2. ```bash theme={null} curl -X POST "https://public-api.etoro.com/api/v1/registration/users" \ -H "x-request-id: " \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "username": "", "email": "", "countryIso": "AU", "languageIso": "en", "partnerCorrelationId": "", "consents": [ { "documentId": 279, "signedAt": "", "clientIp": "" }, { "documentId": 280, "signedAt": "", "clientIp": "" } ] }' ``` | Field | Required | Notes | | - | - | - | | `username` | Yes | 4 to 20 characters, unique | | `email` | Yes | Unique | | `countryIso` | Yes | ISO 3166 country code | | `consents` | Yes | One entry per document from step 2. `signedAt` is UTC ISO 8601, within the last 24 hours and not more than 10 minutes in the future. `clientIp` is the end user's IPv4 address, not your server's | | `partnerCorrelationId` | No | Your own reference for the user, up to 100 characters. Keep it; it is useful for support and audit | | `languageIso`, `regionIsoCode` | No | Preferred language, and sub-national region where it applies (for example `US-TX`) | No password is supplied; etoro generates one. A successful call returns `201` and a token bundle for the new user: ```json Response 201 theme={null} { "success": true, "data": { "username": "", "partnerCorrelationId": "", "loginInfo": { "id_token": "", "access_token": "", "token_type": "bearer", "expires_in": 600, "scope": "" }, "loginSucceeded": true } } ``` Persist two values from this response: * The `sub` claim of the `id_token`. On a partner application this is the user's **`externalUserId`**, and you need it for [silent login](#part-b-sign-the-user-in-silently). It is not an etoro customer id. * The `access_token`. It is short-lived; honor `expires_in`. Use it as a bearer token for the next user-scoped calls, then replace it with a non-interactive token. Common errors: `409` for a username, email, or `partnerCorrelationId` that is already in use (use new values); `422` for an invalid or missing consent, or a stale `signedAt`. See [Errors and rate limits](#errors-and-rate-limits) for the rest. ### 4. Issue a non-interactive token The registration `access_token` expires. To keep calling user-scoped endpoints from your backend after that, issue a **non-interactive token (NIT)** for the user. The NIT published in this portal is the sub-account user token in [Issue a non-interactive token](/partners/integration#issue-a-non-interactive-token). That call needs the registration `access_token` and an `x-sub-account-id`, and it returns the secret only once. Store it in a secret store, and set `expiresAt` and `ipsWhitelist`. > [!NOTE] > > That path applies when the user is an etoro trading sub-account of your application. If your application registers a user directly and you do not have a sub-account id, confirm the issuance path with your etoro contact before you build it. Do not call an internal host. Until a NIT exists, user-scoped calls use `Authorization: Bearer` and the registration `access_token`. After it exists, they use your `x-api-key` and the user's `x-user-key`. The two are mutually exclusive; see [Issue a non-interactive token](/partners/integration#issue-a-non-interactive-token). The examples below show the key pair. ```bash theme={null} curl -X GET "https://public-api.etoro.com/api/v1/users/personaldetails" \ -H "x-request-id: " \ -H "x-api-key: " \ -H "x-user-key: " ``` ### 5. Prepare the profile and submit KYC Call the operations below for the new user. Each lists the scopes it needs in the [Partners API reference](/partners-api-reference). | Step | Operation | Purpose | | - | - | - | | Read the profile | `GET /api/v1/users/personaldetails`, `GET /api/v1/users/address/{addressType}` | A newly registered user usually holds only the country. Read before you write | | Update personal details | `PUT /api/v1/users/personaldetails` | Partial update: send only the fields you have, such as name, date of birth, citizenship, and tax identifications | | Update the address | `PUT /api/v1/users/address/{addressType}` | The user's residential address | | Read the questionnaire | `GET /api/v1/kyc-data/questionnaire` | A new user returns no answers yet | | Submit answers | `POST /api/v1/kyc-data/questionnaire`, or `POST /api/v1/kyc-data/questionnaire/{questionId}` | All answers at once, or one question at a time | | Check what is missing | `GET /api/v1/kyc/gaps` | Outstanding KYC requirements for the user | Where your own provider has already verified the user, you can supply that evidence instead of asking the user to repeat it. #### Confirm email and phone with your own evidence Direct confirmation records that **you** verified the email or phone, so etoro does not send a one-time code. Both calls take a `verificationEvidence` object: | Field | Required | Notes | | - | - | - | | `partnerReferenceId` | Yes | Your reference for the verification. Reusing the registration `partnerCorrelationId` keeps one reference per user | | `verificationMethod` | Yes | One of `sms`, `voiceCall`, `inPerson`, `videoCall`, `documentCheck`, `documentVerification`, `bankVerification`, `governmentDb`, `other` | | `verifiedAt` | Yes | When you verified it, in UTC | | `externalProviderId` | When the method is `documentVerification` | Your verification provider | | `externalReferenceId`, `additionalDetails` | No | The provider's reference and free-text context | ```bash Email theme={null} curl -X POST "https://public-api.etoro.com/api/v1/users/email/verifications/direct-confirmations" \ -H "x-request-id: " \ -H "x-api-key: " \ -H "x-user-key: " \ -H "Content-Type: application/json" \ -d '{ "email": "", "verificationEvidence": { "partnerReferenceId": "", "verificationMethod": "documentVerification", "verifiedAt": "", "externalProviderId": "" } }' ``` ```bash Phone theme={null} curl -X POST "https://public-api.etoro.com/api/v1/users/phone/verifications/direct-confirmations" \ -H "x-request-id: " \ -H "x-api-key: " \ -H "x-user-key: " \ -H "Content-Type: application/json" \ -d '{ "phoneCountryCode": "+61", "phoneNumber": "", "verificationEvidence": { "partnerReferenceId": "", "verificationMethod": "sms", "verifiedAt": "" }, "enable2Fa": false }' ``` `phoneNumber` is digits only, without the country code, and must be a valid national number for that country. A `409` means the email or phone is already verified, or is in use by another user; where the verification was intentional, treat an "already verified" response as done. #### Submit trusted user verification When the user has reached the required verification level, submit your verification evidence to complete trusted verification: ```bash theme={null} curl -X POST "https://public-api.etoro.com/api/v1/users/verification" \ -H "x-request-id: " \ -H "x-api-key: " \ -H "x-user-key: " \ -H "Content-Type: application/json" \ -d '{ "verificationEvidence": { "partnerReferenceId": "", "verificationMethod": "document_verification", "verifiedAt": "", "externalProviderId": "" } }' ``` This operation requires the user to be at verification level 2 and then upgrades them to level 3. It is idempotent for a user already at level 3. If the user has not reached level 2, the call returns `400`; complete the earlier profile and verification steps and check `GET /api/v1/kyc/gaps` rather than retrying. Use the `verificationMethod` value `document_verification` on this operation; the enumeration in the table above applies to the email and phone confirmations. > [!WARNING] > > Trusted verification asserts that **you** verified the user. It is only accepted for users your application created, and you are accountable for the evidence you submit. Never send evidence for a verification that did not take place. ## Part B: Sign the user in silently Silent login opens etoro in the user's browser already signed in. It is a handshake between the browser, your backend, and etoro, and the order matters. ```text theme={null} Your app (user clicks "Open etoro") | v The user's browser POSTs initiate <- etoro sets the login cookie here | v The same browser follows redirectUrl <- your callback receives tid and state | v Your backend calls partner-login-token -> returns { ott, redirectUrl } | v Browser opens that redirectUrl <- cookie + ott establish the session | v User is signed in on etoro ``` > [!WARNING] > > **Only etoro's own response may set the login cookie.** The cookie is created when the user's browser calls initiate. Your application must never create, copy, forge, or proxy it. A call from your server plants the cookie on the server, the browser never receives it, and verify fails. That is expected behavior, not a defect. ### 1. The user's browser calls initiate There is no initiate page to open with query parameters. The user's browser sends: ```bash theme={null} curl -X POST "https://www.etoro.com/api/sso/v2/silent-login/initiate" \ -H "Content-Type: application/json" \ -H "X-STS-DeviceId: " \ -d '{ "fromClientId": "", "redirectUri": "", "state": "" }' ``` The `curl` shows the contract. Run it in the user's browser (so the `Set-Cookie` is stored there), not on your server. `X-STS-DeviceId` is a GUID you generate for this handshake. `fromClientId` is your application's client id and must be a GUID. `redirectUri` must match a registered redirect URI character for character, including scheme and path. `state` is optional. A successful call returns `201` and sets `etoro-silent-login-tid` (`HttpOnly`, `Secure`, domain `.etoro.com`, about five minutes): ```json Response 201 theme={null} { "redirectUrl": "?tid=&state=" } ``` Navigate that same browser to `redirectUrl`. `tid` is a GUID with no dashes. When you sent `state`, it is appended and URL-encoded; when you omitted it, the callback has `tid` only. An unregistered `redirectUri` is rejected with `403`. ### 2. Exchange the tid for a one-time token On your backend, read `tid` from the callback and identify the user. Authenticate with a partner token (see [step 1 of Part A](#1-obtain-a-partner-token)) and send the user's `externalUserId`, which is the `sub` claim saved at registration: ```bash theme={null} curl -X POST "https://www.etoro.com/api/sso/v2/silent-login/partner-login-token" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "tid": "", "externalUserId": "" }' ``` ```json Response 201 theme={null} { "ott": "", "redirectUrl": "https://www.etoro.com/accounts/partners/silent-login/verify?ott=" } ``` `tid` must be the GUID from the callback. `externalUserId` must be the value saved from registration and must belong to your application; a value minted for another application is rejected. ### 3. Open the verify URL in the same browser Redirect the browser to the `redirectUrl` **exactly as returned**. Do not change its host, path, or query string. The etoro page combines the cookie from step 1 with the one-time token, establishes the session, and lands the user on etoro signed in. You do not call the verify endpoint yourself. ### Timing and single use * The cookie lives for about five minutes. Complete steps 1 to 3 promptly. * The one-time token (`ott`) is single use. If a sign-in fails, start again from step 1; do not reuse an `ott` or a `tid`. * The cookie must come from the **same browser** that opens the verify URL. ### Silent login errors | Symptom | Likely cause | What to do | | - | - | - | | Verify fails with `SilentLoginCookieMissing` | The cookie is absent: the initiate call was not made by this browser, or the cookie expired | Run initiate in the user's browser again | | Verify fails with `403` | The cookie does not match the one-time token, or was altered | Start a new handshake | | Initiate returns `403` | `redirectUri` is not registered for `fromClientId` | Use a registered URI, or ask etoro to register it | | Initiate returns `400` | `X-STS-DeviceId` or `fromClientId` is missing or not a GUID, or the body is empty | Send a GUID device id and a GUID client id | | `partner-login-token` returns `400` | `tid` or `externalUserId` is missing, or `tid` is not a GUID | Send the `tid` from the callback and the saved `externalUserId` | | Verify fails after a retry | The `ott` was already used or has expired | Start a new handshake | ## Errors and rate limits Each operation's rate limit is stated in the [Partners API reference](/partners-api-reference); most share a default of 60 requests per 60 seconds, and exceeding it returns `429`. See [Rate limits](/core/getting-started/rate-limits). Common causes of failure across the guide: | Symptom | Cause | Fix | | - | - | - | | `401` | Missing or invalid token, or key pair | Check the token has not expired and that you are not mixing bearer and key-pair authentication | | `403` with `InsufficientPermissions` | The token lacks a required scope | Ask your etoro contact to add the scope to your application | | `403` with `IpNotAllowed` | The caller's address is not allow-listed | Register your egress addresses with etoro | | `403` with `UserNotOwnedByPartner` | The user was not created by your application | Only act on users you registered | | `409` | Duplicate username, email, phone, or reference | Use unique values | | `422` | Invalid or missing field, or consent | Inspect the error body for the offending field | ## Go-live checklist * Consent documents fetched per country at registration time, never hard-coded, with an accurate `signedAt` and the end user's own `clientIp`. * `externalUserId` (the `sub` claim) and `partnerCorrelationId` stored against your own user record. * Every item in the [partner security checklist](/partners/integration#security-checklist): NIT storage, expiry and IP restriction, egress allow-listing, and no personal data in logs or events. * Silent login initiated only from the user's browser, with `partner-login-token` called only from your backend. * A full dry run of Part A and Part B in a non-production environment, agreed with your etoro contact, before any customer sees it. ## Reference > **[Partners API reference](/partners-api-reference)** > > Every Partners API endpoint, with the scopes each one requires. > **[Partner integration flow](/partners/integration)** > > Non-interactive tokens, account association, scopes, and event reporting. > **[SSO with OAuth 2.0](/core/getting-started/sso-oauth)** > > The standard sign-in flow for users who already hold an etoro account. > **[API keys and headers](/core/getting-started/authentication)** > > The `x-api-key` / `x-user-key` pair and request header format. # Partner integration flow Source: https://api-portal.etoro.com/partners/integration Onboard users with their etoro credentials, issue non-interactive tokens, associate accounts, report events back to etoro, and consume events etoro publishes to you. ## Purpose and scope This integration enables a partner platform to authenticate end users against their existing etoro credentials, and — where etoro has granted the corresponding approval — to reuse identity and verification data that etoro already holds for those users. Two outcomes follow from it. First, the partner does not operate a separate credential store for users who already hold an etoro account: authentication is delegated to etoro, and the partner receives a verified assertion of the user's identity. Second, onboarding data the user has already supplied to etoro need not be requested again, which shortens the partner's registration journey and reduces the volume of data the partner is required to collect, validate, and retain. ### Capability tiers The integration is delivered in three tiers. They are incremental and independently provisioned: a partner may adopt the first alone, and each subsequent tier requires additional authorization from etoro. | Tier | Provides | Requires | | - | - | - | | **Authentication** | A verified assertion that the end user holds a specific etoro account, together with a stable pseudonymous identifier (the `sub` claim) by which the partner recognizes that user on subsequent sign-ins. Sufficient on its own to implement sign-in and account association. | A registered application | | **Authorization** | The ability to invoke etoro API operations on the user's behalf, limited to the scopes the user consented to at sign-in. See [Permitted operations and scopes](#permitted-operations-and-scopes). | Scopes granted to the client and consented to by the user | | **Data reuse** | Access to identity and verification data etoro already holds for the user — KYC responses, verification status, and outstanding requirements — enabling the partner to pre-populate its own onboarding rather than re-collecting the same information. | An explicit data-sharing approval for the integration, in addition to the relevant scopes | > [!NOTE] > > The first tier requires nothing beyond application registration. Data reuse is subject to a separate approval by etoro and is not self-service — see [Data sharing and PII](#data-sharing-and-pii) for the applicable constraints. Where all three tiers are in place, an existing etoro user can complete registration on the partner platform in a single journey, with the two accounts associated by an etoro-issued token rather than by correlation of personal attributes. ## Integration flow The partner journey comprises five stages: 1. The user authenticates with their etoro account (OAuth 2.0 authorization code flow with PKCE). 2. The partner backend exchanges the authorization code for an access token, a refresh token, and an **ID token**. 3. The partner backend validates the ID token against etoro's JWKS and extracts the user's identifier from it. 4. The partner backend issues a **non-interactive token (NIT)**, enabling continued API access when the user is not present. 5. The partner backend associates its own user record with the etoro account, keyed on the token identifier. **Stages 1 to 3 are not partner-specific** — they are the standard OpenID Connect sign-in flow, documented once in [SSO with OAuth 2.0](/core/getting-started/sso-oauth), which covers application registration, the discovery document, the authorization request, the code exchange, and ID token validation. Complete that flow first; this page covers everything that follows it. All endpoints referenced below are production endpoints. The authorization server is `https://www.etoro.com`; the API is `https://public-api.etoro.com`. > **[SSO with OAuth 2.0](/core/getting-started/sso-oauth)** > > Stages 1 to 3: registration, discovery, PKCE authorization, code exchange, and ID token validation. ## Issue a non-interactive token The access token obtained in stage 2 expires within approximately one hour and is bound to the user's interactive session. For operations the partner backend performs while the user is not present — portfolio synchronization, order placement, reconciliation, event reporting — a **non-interactive token (NIT)** is required. A non-interactive token is a long-lived, scope-limited user credential. It is presented in the `x-user-key` header together with the application's `x-api-key`: ```bash theme={null} curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \ -H "x-request-id: " \ -H "x-api-key: " \ -H "x-user-key: " ``` > [!WARNING] > > The `x-api-key` + `x-user-key` pair and `Authorization: Bearer` are **mutually exclusive** authentication methods. A request presenting both is rejected. The token is issued using the user's access token from stage 2. Retrieve the assignable scopes first, then create the token: ```bash cURL theme={null} # 1. Which scopes may this token carry? curl -X GET "https://public-api.etoro.com/api/v1/sub-accounts/etoro-trading/user-tokens/scopes" \ -H "x-request-id: " \ -H "Authorization: Bearer " # 2. Issue the non-interactive token for the user's sub-account curl -X POST "https://public-api.etoro.com/api/v1/sub-accounts/etoro-trading/user-tokens" \ -H "x-request-id: " \ -H "x-sub-account-id: " \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "userTokenName": "myapp-prod", "scopeNames": [ "etoro-public:trade.real:read", "etoro-public:trade.real:write" ], "ipsWhitelist": ["203.0.113.10"], "expiresAt": "2026-12-31T23:59:59Z" }' ``` ```json Response 201 theme={null} { "userTokenId": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "userToken": "", "userTokenName": "myapp-prod", "clientId": "7c9e6679-7425-40de-944b-e07fc1f90ae7", "ipsWhitelist": ["203.0.113.10"], "scopes": [{ "scopeName": "etoro-public:trade.real:read" }], "expiresAt": "2026-12-31T23:59:59Z", "createdAt": "2026-06-06T10:15:00Z" } ``` The `userToken` value is returned **only in this response**. It must be persisted to a secret store on receipt; no endpoint returns it subsequently. | Operation | Endpoint | | - | - | | List a user's tokens (secret never included) | `GET /api/v1/sub-accounts/etoro-trading/user-tokens` | | Allowed scopes for these tokens | `GET /api/v1/sub-accounts/etoro-trading/user-tokens/scopes` | | Issue a token | `POST /api/v1/sub-accounts/etoro-trading/user-tokens` | | Change scopes, IP allow-list, or expiry | `PATCH /api/v1/sub-accounts/etoro-trading/user-tokens/{userTokenId}` | | Revoke a token (idempotent) | `DELETE /api/v1/sub-accounts/etoro-trading/user-tokens/{userTokenId}` | > [!NOTE] > > The authorization server additionally advertises the RFC 8693 token-exchange grant, `urn:ietf:params:oauth:grant-type:token-exchange`. Eligibility for this grant is determined per partner at registration. Confirm with your etoro contact which non-interactive token provisioning path applies to your integration before implementing against it. `expiresAt` and `ipsWhitelist` should be set on every non-interactive token issued. A long-lived user credential with neither an expiry nor an address restriction represents the highest-value target in the integration, and both fields remain modifiable afterwards via `PATCH`. Rotate the token on a schedule with `POST`-then-`DELETE`, and revoke it immediately on user disconnect, suspected compromise, or offboarding. ## Associate the accounts The association is a mapping maintained by the partner backend between its own user record and the etoro subject. The etoro side of that mapping is retrieved with `GET /api/v1/sub-accounts/me/accounts`, using either the access token or the non-interactive token: ```bash theme={null} curl -X GET "https://public-api.etoro.com/api/v1/sub-accounts/me/accounts" \ -H "x-request-id: " \ -H "Authorization: Bearer " ``` ```json theme={null} { "accounts": [ { "subAccountId": "ZXRvcm8tdHJhZGluZw", "status": "Approved", "providerName": "etoro-trading", "accountId": "123456789", "accountType": "Trading", "accountVisibility": "Visible", "externalUserId": "123456789", "additionalData": { "gcid": 123456789, "username": "my-trading-account" } } ] } ``` * `subAccountId` — the account handle presented in `x-sub-account-id` on sub-account operations, including issuance of the non-interactive token above. * `externalUserId` — the identifier mapping an etoro account to the partner's own user record, making the association explicit on both sides. * `status` — `Pending`, `MissingKyc`, `InvalidKyc`, `RejectedByThirdParty`, or `Approved`. Only an `Approved` account should be acted upon. The KYC-related states indicate an incomplete onboarding journey rather than a failure, and should be handled accordingly. Where the user does not yet hold an account with the provider, one is created with `POST /api/v1/sub-accounts/me/accounts`: ```bash theme={null} curl -X POST "https://public-api.etoro.com/api/v1/sub-accounts/me/accounts" \ -H "x-request-id: " \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "providerName": "etoro-trading", "additionalParams": { "username": "my-trading-account" } }' ``` Persist the association as `(partner user id, sub claim, subAccountId, externalUserId)` and resolve it from the `sub` claim on each subsequent sign-in. Because `sub` is pairwise and stable for a given client, a returning user resolves to the same record without the partner holding an email address or a name. > [!WARNING] > > Accounts must never be associated by matching an email address, phone number, or name across systems. Such attributes are not available by default, and matching on user-supplied values constitutes an account-takeover vector: any party able to register that value on the partner platform would inherit the corresponding etoro account. The association must be established solely by a token issued by etoro. ## Permitted operations and scopes Once a validated token has been obtained for an associated user, the scopes carried by that token determine which operations the partner may execute. The operations available are those published in the [Partners API reference](/partners-api-reference); there is no separate partner endpoint list, and the reference is the authoritative contract. The same rule applies to either credential type: * An **access token** or a **NIT** carries a set of scopes, fixed at consent time or at issuance time. * Every operation in the reference lists the scopes that grant it. A token needs **one** of the listed alternatives, not all of them. * A call whose token lacks any of an operation's scopes is rejected. Nothing is granted implicitly by being an approved partner. A token consented to the KYC and money scopes is therefore sufficient to execute the complete user journey exposed by the Partners API on the user's behalf: | Scope family | What it unlocks in the reference | | - | - | | `etoro-public:partner:registration:read` / `:write` | Registration eligibility checks and registering the user (`/api/v1/registration/users`) | | `etoro-public:kyc:*` — `read`, `write`, `questions:read`, `answers:read` / `:write`, `regulations:read` | The KYC journey: questionnaire, required fields, documents, screening, electronic verification, gaps | | `etoro-public:verification.*` — `personaldetails`, `address`, `email`, `phone`, and the `trusted` variants | Personal details and address, and email/phone verification and confirmation | | `etoro-public:money.accounts:read` / `:write` | Cash account creation, eligibility, and status | | `etoro-public:money.ftd:read` / `:write` | First-time deposit records, and the deposit notifications described in [Reporting events to etoro](#reporting-events-to-etoro) | | `etoro-public:money.deposit.crypto:*`, `money.withdraw.crypto:*` | Crypto deposit intents and crypto withdrawals | | `etoro-public:sub-accounts:read` / `:write` / `:delete` | Sub-accounts, and the non-interactive tokens described above | | `etoro-public:real:read`, `etoro-public:trade.real:*`, `etoro-public:demo:read` | Portfolio and trading operations in the [Core API](/) with the same token | Two further constraints apply in addition to the per-operation scope check, and should be accounted for at design time: 1. **Scopes are granted per partner.** `GET /api/v1/sso/scopes` returns the catalog your client may request — a scope outside it is rejected at registration, not at call time. 2. **A scope is permission to call, not permission to receive PII.** Where an operation would return personal data, the data-sharing approval below governs what comes back. Holding `etoro-public:kyc:read` is not by itself entitlement to a user's personal details. Partners should request the narrowest scope set that completes the journey being implemented, and extend it only deliberately. The scopes held by a stored non-interactive token define the impact of any compromise of that credential. ## Reporting events to etoro The integration is bidirectional. Alongside the operations a partner invokes on a user's behalf, etoro requires the partner to **report events that occur on the partner platform** but that etoro must know about — currently, deposits made by an associated user. Event reporting uses the same authenticated API surface as the rest of the integration. It is a partner-to-etoro call, not a webhook: the partner is the caller, the event is the request body, and the user the event concerns is identified by the credential presented. The other direction — etoro notifying the partner when associated-user data changes — is delivered over Azure Event Hub. See [Events from etoro](/partners/events-from-etoro). ### Deposit notification `POST /api/v1/money/deposit/notify` reports an approved deposit. etoro processes the notification asynchronously and determines from it whether the deposit is the user's first — the first-time deposit (FTD) — at both account and global level. **Scope** `etoro-public:money.ftd:write` Required on the token presented. The user the deposit belongs to is the user the credential identifies — the `x-user-key` non-interactive token issued for that user. ```bash cURL theme={null} curl -X POST "https://public-api.etoro.com/api/v1/money/deposit/notify" \ -H "X-Request-ID: " \ -H "x-api-key: " \ -H "x-user-key: " \ -H "Content-Type: application/json" \ -d '{ "accountId": "ACC-14540678", "transactionId": "TXN-4783212", "externalTransactionId": "STRIPE-4e7dc7ff246b44af9907", "transactionDate": "2026-09-14T10:05:08Z", "inputAmount": { "amount": 850.0, "currency": "EUR" }, "feeAmount": { "amount": 5.0, "currency": "USD", "amountInUsd": 5.0 }, "convertedAmount": { "amount": 1000.0, "currency": "USD" }, "paymentMethodType": "ach", "depositType": "regular" }' ``` ```json Response 202 theme={null} { "success": true, "data": { "transactionId": "TXN-4783212", "message": "Deposit notification accepted for processing" } } ``` | Field | Required | Notes | | - | - | - | | `accountId` | Yes | The account identifier within the partner system | | `transactionId` | Yes | The partner's own unique identifier for the deposit. Echoed back in the acknowledgement, and the key for any later reconciliation | | `externalTransactionId` | No | The payment provider's reference, where one exists | | `transactionDate` | Yes | When the deposit was **approved**, in UTC | | `inputAmount` | Yes | `amount` and ISO 4217 `currency` as the user paid them | | `convertedAmount` | Yes | `amount` and `currency` after conversion, typically USD | | `feeAmount` | No | Transaction fee, with an optional `amountInUsd`; calculated by etoro when omitted | | `paymentMethodType` | No | The method used — `creditCard`, `wireTransfer`, `ach`, `openBanking`, `eToroMoney`, and others; see the reference for the full enumeration | | `depositType` | No | `regular` (default) or `recurring` | | `extraData` | No | Free-form key-value data specific to the partner or account type | ### Operational rules **1. Report on approval, not on initiation** `transactionDate` is the approval timestamp. A deposit that is pending, declined, or subsequently reversed is not an approved deposit and should not be reported as one. **2. Report every approved deposit** Do not attempt to determine locally which deposit is the first. Report each approved deposit; etoro evaluates FTD status — account-level and global — from the notifications it receives. **3. Treat 202 as accepted, not as recorded** The response acknowledges that the notification was accepted for background processing. It is not a statement that FTD status has been assigned. Read the outcome back through the FTD endpoints below. **4. Send x-request-id on every call** The header is optional on this operation and required on the FTD read operations. Send a fresh UUID on all of them: it is what makes a notification traceable across both systems when a partner and etoro disagree about whether an event arrived. **5. Keep personal data out of extraData** `extraData` accepts arbitrary keys, which makes it the easiest place to leak PII into an integration that is otherwise token-only. Restrict it to the operational values etoro has agreed with you. Error responses carry a structured body — `success: false` with an `error` object containing `code`, `message`, `details`, and the offending `field`: | Status | Meaning | | - | - | | `400` | Malformed request | | `401` | Missing or invalid `x-api-key` / `x-user-key` | | `403` | The partner is not authorized for this account type | | `422` | The request is well-formed but semantically rejected — inspect `error.field` | | `429` | The shared rate limit (60 requests / 60 seconds) was exceeded | ### Reading first-time deposit status Two read operations expose what etoro concluded, both requiring `etoro-public:money.ftd:read`: | Operation | Returns | | - | - | | `GET /api/v1/money/first-time-deposit` | The user's global FTD — their first-ever deposit across all etoro account types, with the account type and identifier it occurred on | | `GET /api/v1/money/accounts/{accountType}/first-time-deposit` | The FTD record or records for one account type (`trading`, `options`, `cash`, `moneyFarm`), optionally filtered by `accountId`. A user may hold several accounts of one type, so the response is an array | The account-level response distinguishes `isAccountFtd` from `isGlobalFtd`, so a deposit can be the first on a given account while not being the user's first at etoro. Reconcile on `transactionId` — the same value the partner sent in the notification. > [!NOTE] > > Deposit notification is the event type currently published for partner-to-etoro reporting. Additional event types are provisioned per partner; where your integration agreement covers reporting beyond deposits, confirm the applicable contract with your etoro contact rather than inferring one. ## Data sharing and PII **etoro does not release personal information about its users to partners.** That includes, and is not limited to, email address, full name, phone number, date of birth, national identifiers, and address. None of it is available to your application by default, and the absence is deliberate rather than an omission in this guide. Where a specific integration requires a specific field, that field is released only after the data sharing has been **explicitly approved by etoro for the integration**, and only through the scopes granted to the client for that purpose. The KYC, verification, and personal-details operations in the [Partners API reference](/partners-api-reference) are gated exactly this way: registered scope, approved purpose, per-partner grant. Absent that approval, calling them returns nothing you are not entitled to see. The consequence for integration design is that the integration is **token-only**: * **Identity is the `sub` claim.** Pairwise, pseudonymous, stable for your client, and meaningless to anyone else. Use it as the primary key of the association. * **Authorization is the scope set** on the access token or NIT. Never infer entitlement from anything a user typed. * **Linkage is `externalUserId` and `subAccountId`.** Opaque handles, both sides of the mapping. * **No PII joins.** Do not build reconciliation, deduplication, or support lookups on email, name, or phone. If your platform needs a display value, use one your own user supplied to you directly. * **Do not request claims you have not been approved for**, and do not treat any claim that does appear as licence to store it beyond the purpose it was approved for. * **Do not push PII to etoro either** unless the endpoint's contract calls for it, in which case it is covered by that endpoint's scope and approval. This applies to reported events as much as to requests: `extraData` on a deposit notification is not a channel for personal data. Where a product requirement cannot be satisfied on a token-only basis, it must be raised with your etoro contact as a data-sharing request before implementation begins. It is not to be addressed by working around the constraint in code. ## Security checklist In addition to the [SSO security checklist](/core/getting-started/sso-oauth#security-checklist), the following must be in place before a partner integration is promoted to production: * Non-interactive tokens issued with the narrowest scope set, an `expiresAt`, and an `ipsWhitelist`. * NITs held in a secret store — never in source, never in a repository, never in a log line, never in an error payload, never returned to the browser. * A working revocation path for every NIT, wired to your own user-offboarding flow. * Egress addresses of every environment that calls the API provided to etoro for allow-listing. * Account association established solely by etoro-issued tokens, never by matching personal attributes. * Deposit notifications sent on approval only, with a stable `transactionId` retained for reconciliation. * No PII in the account association, the reported events, the logs, or the analytics. ## Reference > **[SSO with OAuth 2.0](/core/getting-started/sso-oauth)** > > The sign-in flow this guide builds on: registration, PKCE, code exchange, ID token validation. > **[Events from etoro](/partners/events-from-etoro)** > > Outbound Event Hub delivery and the `KycUpdates` message contract. > **[Partners API reference](/partners-api-reference)** > > Every Partners API endpoint, with the scopes each one requires. > **[API keys and headers](/core/getting-started/authentication)** > > The `x-api-key` / `x-user-key` pair and request header format. > **[Rate limits](/core/getting-started/rate-limits)** > > Quotas that apply to every call in this flow. # Introduction Source: https://api-portal.etoro.com/partners/introduction Welcome to the etoro Partners API The etoro Partners API lets approved partners onboard and manage end users on etoro. Where the [Core API](/) covers trading and market data for your own account, the Partners API covers the lifecycle around a user: registering them, taking them through KYC and verification, opening accounts, and moving money. > [!NOTE] > > Access to the Partners API is granted per partner. If you are not yet onboarded as an etoro partner, contact your etoro representative — these endpoints are not available with standard API keys. ## What you can build > **User registration** > > Register new etoro users on behalf of your platform, and check registration eligibility before you start. > **KYC & verification** > > Drive the full KYC flow — questionnaires, required fields, document upload, screening, and electronic verification. > **Accounts** > > Create and inspect cash accounts and sub-accounts, and check creation eligibility and status. > **Money movement** > > Handle first-time deposits, crypto deposit intents, and crypto withdrawals for your users. > **Events from etoro** > > Consume account change events from the Azure Event Hub etoro publishes to your application. ## Authentication The Partners API uses the same authentication as the rest of the etoro Public API. Every request is authenticated one of two ways: * **API key pair** — send both `x-api-key` (identifies your application) and `x-user-key` (identifies the user) headers. The two are always sent together. * **OAuth 2.0** — a bearer token obtained through the authorization code flow, scoped to the operations you need (for example `etoro-public:kyc:write` or `etoro-public:money.accounts:read`). The two methods are alternatives — never send a bearer token alongside the key pair. Each endpoint in the reference lists the scopes it requires. > [!NOTE] > > etoro does not share personal information — including email addresses — with partners unless that data sharing has been explicitly approved for the integration. Integrations must be designed on a token-only basis: see [Data sharing and PII](/partners/integration#data-sharing-and-pii). > **[Partner integration flow](/partners/integration)** > > Issue non-interactive tokens, associate a partner account with an etoro account, and report events back to etoro. > **[Events from etoro](/partners/events-from-etoro)** > > Message envelope, `KycUpdates` payload, and how to consume your dedicated Event Hub. > **[SSO with OAuth 2.0](/core/getting-started/sso-oauth)** > > The sign-in flow every integration starts from: PKCE authorization, code exchange, and ID token validation. > **[API keys and headers](/core/getting-started/authentication)** > > How to generate keys and format your request headers. ## Base URL All Partners API endpoints are served from: ``` https://public-api.etoro.com ``` ## Next steps > **[API Reference](/partners-api-reference)** > > Browse every Partners API endpoint, grouped by capability. > **[Events from etoro](/partners/events-from-etoro)** > > Outbound event delivery and the `KycUpdates` schema. > **[Changelog](/partners/changelog)** > > New endpoints and breaking changes in the Partners API.