Etoro Apps
Enables agents to interact with the eToro API to access market data, portfolio and social features,
- Rating
- 4.8 (105 reviews)
- Downloads
- 7,115 downloads
- Version
- 1.0.0
Overview
Enables agents to interact with the eToro API to access market data, portfolio and social features, and execute.
Complete Documentation
View Source →
eToro Public API
Base URL: https://public-api.etoro.com/api/v1
About
This skill allows to interact with the user's eToro account programatically, including executing trades.
Authentication & Required Headers
The eToro API supports two authentication methods. Both use the same base URL and endpoints — only the auth headers differ.
Method 1 — OAuth SSO (Bearer Token)
If the user authenticated via "Login with eToro" (SSO/OAuth), an access_token is available from the token exchange.
Headers (every request):
x-request-id: unique UUID per requestAuthorization:Bearer
access_token comes from:
- User clicks "Login with eToro" → redirects to
https://www.etoro.com/sso/with PKCE challenge. - User authenticates on eToro's side.
- eToro redirects back with an authorization
code. - The code is exchanged for tokens via
POST https://www.etoro.com/sso/oidc/token: grant_type=authorization_codecode=redirect_uri=code_verifier=- Plus
Authorization: Basicheader - Response contains:
access_token— this is the Bearer token for API calls (~2130 chars, JWT)id_token— JWT with user identity (subclaim = 128-char encoded user ID)token_type:"Bearer"expires_in: (varies)
curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \
-H "x-request-id: <UUID>" \
-H "Authorization: Bearer <access_token>"
Method 2 — Manual API Keys
If the user provides API keys manually (no OAuth), use key-based auth.
Keys (request from the user on install)
- Public API Key: application
- User Key: user account
- Environment: Real Portfolio or Virtual Portfolio (real/demo)
- Log in to eToro.
- Settings > Trading.
- Create New Key.
- Choose Environment (Real or Virtual/Demo) and Permissions (Read or Write).
- Verify identity and copy the generated User Key.
x-request-id: unique UUID per requestx-api-key: Public API Key ()x-user-key: User Key ()
curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \
-H "x-request-id: <UUID>" \
-H "x-api-key: <PUBLIC_KEY>" \
-H "x-user-key: <USER_KEY>"
Choosing the Auth Method in Code
When making requests, check which credentials are available:
if (ctx.accessToken) {
// SSO auth — Bearer token from OAuth token exchange
headers["Authorization"] = `Bearer ${ctx.accessToken}`;
} else {
// Manual API key auth
headers["x-api-key"] = ctx.apiKey;
headers["x-user-key"] = ctx.userKey;
}
Request Conventions
- All paths below are relative to the Base URL (which already includes
/api/v1).
GET /watchlists means GET https://public-api.etoro.com/api/v1/watchlists.
- Query params go in the URL, path params go in the URL path.
- For query params that are documented as
array, send them as comma-separated values (e.g.,instrumentIds=1001,1002). - Pagination patterns vary by endpoint:
- Search:
pageNumber,pageSize - People search & trade history:
page,pageSize - Feeds:
take,offset - Watchlist items listing:
pageNumber,itemsPerPage - Casing matters for request bodies:
- Trading execution uses PascalCase fields (e.g.,
InstrumentID,IsBuy,Leverage). - Market close body uses
InstrumentId(capital I, lowercase d). - Watchlist items use
ItemId,ItemType,ItemRank. - Feeds post body uses lower camel (
owner,message,tags,mentions,attachments). - Some responses may use different casing for similar concepts (e.g.,
instrumentIdvsInstrumentID). When extracting IDs, handle both if present.
Demo vs Real Trading
- Use demo execution endpoints (contain
/demo/) for testing and paper trading. - Use non-demo execution endpoints for real trading.
- For portfolio/PnL:
- Demo:
/trading/info/demo/* - Real:
/trading/info/portfolioand/trading/info/real/pnl - Ensure your key environment matches the endpoint (Virtual vs Real). Each User Key is associated with a specific environment.
Use Defaults
- Important: You don't need to specify all parameters. If the user doesn't specify leverage for example, don't send it on the API request.
Quick Start (Demo Trade)
- Resolve
instrumentIdusing search.
fields is required on search requests.curl -X GET "https://public-api.etoro.com/api/v1/market-data/search?internalSymbolFull=BTC&fields=instrumentId,internalSymbolFull,displayname" \
-H "Authorization: Bearer <access_token>" \
-H "x-request-id: <UUID>"
- Place a demo market order by amount (PascalCase body):
curl -X POST "https://public-api.etoro.com/api/v1/trading/execution/demo/market-open-orders/by-amount" \
-H "Authorization: Bearer <access_token>" \
-H "x-request-id: <UUID>" \
-H "Content-Type: application/json" \
-d '{
"InstrumentID": 100000,
"IsBuy": true,
"Leverage": 1,
"Amount": 100
}'
Note: The examples above use OAuth (Bearer token). For API key auth, replace theAuthorizationheader withx-api-keyandx-user-keyheaders instead.
Common IDs
instrumentId: from Search or Instruments metadatapositionId: from Portfolio endpointsorderId: from execution responses or Portfolio endpointsmarketId: used by instrument feed endpoints (typically available in instrument metadata/search fields)userId: numeric eToro user ID (often referred to as CID in responses; discover via People endpoints/search)watchlistId: from watchlists list/create endpoints
Market Data (Requests)
Search instruments
GET /market-data/search- Required query:
fields(comma-separated list of instrument fields to return) - Optional:
searchText,pageSize,pageNumber,sort - The Search endpoint supports filtering by fields returned in results; for exact symbol lookup, use
internalSymbolFullas a query param and verify the exact match. - Recommended minimal
fieldswhen you need IDs: include the instrument identifier (may appear asinstrumentIdorInstrumentID), plusinternalSymbolFullanddisplayname(andmarketIdif you plan to use Feeds).
GET /market-data/instruments
instrumentIds, exchangeIds, stocksIndustryIds, instrumentTypeIds.Prices & history
GET /market-data/instruments/rates
instrumentIds (comma-separated).
GET /market-data/instruments/history/closing-price
GET /market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}
direction: asc or desc. candlesCount max 1000.
Use only supported interval values (confirm via docs if unsure).Reference data
GET /market-data/exchanges(optionalexchangeIds)GET /market-data/instrument-typesGET /market-data/stocks-industries(optionalstocksIndustryIds)
Trading Execution (Requests)
Requires appropriate permissions (typically Write) and the correct environment (Demo vs Real).
Market Open Orders (by amount)
Endpoints:
POST /trading/execution/demo/market-open-orders/by-amountPOST /trading/execution/market-open-orders/by-amount
- Required:
InstrumentID,IsBuy,Leverage,Amount - Optional:
StopLossRate,TakeProfitRate,IsTslEnabled,IsNoStopLoss,IsNoTakeProfit
Market Open Orders (by units)
Endpoints:
POST /trading/execution/demo/market-open-orders/by-unitsPOST /trading/execution/market-open-orders/by-units
- Required:
InstrumentID,IsBuy,Leverage,AmountInUnits - Optional:
StopLossRate,TakeProfitRate,IsTslEnabled,IsNoStopLoss,IsNoTakeProfit
Cancel Market Open Orders
Endpoints:
DELETE /trading/execution/demo/market-open-orders/{orderId}DELETE /trading/execution/market-open-orders/{orderId}
Market Close Orders
Endpoints:
POST /trading/execution/demo/market-close-orders/positions/{positionId}POST /trading/execution/market-close-orders/positions/{positionId}DELETE /trading/execution/demo/market-close-orders/{orderId}DELETE /trading/execution/market-close-orders/{orderId}
- Required:
InstrumentId - Optional:
UnitsToDeduct(number ornull)
UnitsToDeduct.
Full close: set UnitsToDeduct to null.
You must close by positionId, not by symbol.Market-if-touched (Limit) Orders
Endpoints:
POST /trading/execution/demo/limit-ordersDELETE /trading/execution/demo/limit-orders/{orderId}POST /trading/execution/limit-ordersDELETE /trading/execution/limit-orders/{orderId}
- Required:
InstrumentID,IsBuy,Leverage,Rate, and one ofAmountorAmountInUnits - Optional:
StopLossRate,TakeProfitRate,IsTslEnabled,IsNoStopLoss,IsNoTakeProfit - Do not send:
IsDiscounted,CID
Trading Info & Portfolio (Requests)
GET /trading/info/demo/pnlGET /trading/info/real/pnlGET /trading/info/demo/portfolioGET /trading/info/portfolio
positionId and orderId for close/cancel flows.
GET /trading/info/trade/history
minDate (YYYY-MM-DD). Optional: page, pageSize.Watchlists (Requests)
User watchlists
GET /watchlists
itemsPerPageForSingle, ensureBuiltinWatchlists, addRelatedAssets.
GET /watchlists/{watchlistId}
pageNumber, itemsPerPage.
POST /watchlists
name (required), type, dynamicQuery (optional). (Uses query params, not a JSON body.)
PUT /watchlists/{watchlistId}
newName (required). (Uses query params, not a JSON body.)
DELETE /watchlists/{watchlistId}
WatchlistItemDto fields:
ItemId(required, int)ItemType(required, string:InstrumentorPerson)ItemRank(optional, int)
POST /watchlists/{watchlistId}/itemsPUT /watchlists/{watchlistId}/itemsDELETE /watchlists/{watchlistId}/items
[
{ "ItemId": 12345, "ItemType": "Instrument", "ItemRank": 1 },
{ "ItemId": 67890, "ItemType": "Instrument", "ItemRank": 2 }
]
Default watchlists
POST /watchlists/default-watchlist/selected-itemsGET /watchlists/default-watchlists/items
itemsLimit, itemsPerPage.
POST /watchlists/newasdefault-watchlist
name (required), type, dynamicQuery (optional).
PUT /watchlists/setUserSelectedUserDefault/{watchlistId}PUT /watchlists/rank/{watchlistId}
newRank (required).Public watchlists
GET /watchlists/public/{userId}GET /watchlists/public/{userId}/{watchlistId}
Feeds (Requests)
Read feeds
GET /feeds/instrument/{marketId}
requesterUserId, take, offset, badgesExperimentIsEnabled, reactionsPageSize.
GET /feeds/user/{userId}
requesterUserId, take, offset, badgesExperimentIsEnabled, reactionsPageSize.Notes:
marketIdis associated with an instrument (typically available via instrument metadata/search if you include it infields).userIdis a numeric user identifier (CID). If you only have a username, discover the numeric ID via People endpoints (see User Info & Analytics).
POST /feeds/post- Body fields (lower camel, JSON):
owner(int)message(string)tags:{ "tags": [{ "name": "...", "id": "..." }] }mentions:{ "mentions": [{ "userName": "...", "id": "...", "isD irect": true }] }attachments: array of objects withurl,title,host,description,mediaType, and optionalmedia.
{ "message": "Hello eToro feed!" }
Curated Lists & Recommendations (Requests)
GET /curated-listsGET /market-recommendations/{itemsCount}
Popular Investors (Copiers)
GET /pi-data/copiers
User Info & Analytics (Requests)
GET /user-info/people
usernames, cidList.
Use this to map username ↔ CID (userId) when you need numeric userId for feeds/public watchlists.
GET /user-info/people/search
period. Optional: page, pageSize, sort, popularInvestor, gainMax, maxDailyRiskScoreMin, maxDailyRiskScoreMax, maxMonthlyRiskScoreMin, maxMonthlyRiskScoreMax, weeksSinceRegistrationMin, countryId, instrumentId, instrumentPctMin, instrumentPctMax, isTestAccount, and other filters.
GET /user-info/people/{username}/gainGET /user-info/people/{username}/daily-gain
minDate, maxDate, type (Daily or Period).
GET /user-info/people/{username}/portfolio/liveGET /user-info/people/{username}/tradeinfo
period (e.g., LastTwoYears).Responses & Schemas
For response schemas and full examples, refer to:
- https://api-portal.etoro.com/
- MCP server:
https://api-portal.etoro.com/mcp
Installation
openclaw install etoro-apps
💻Code Examples
-H "Authorization: Bearer <access_token>"
### Method 2 — Manual API Keys
If the user provides API keys manually (no OAuth), use key-based auth.
**Keys (request from the user on install)**
- **Public API Key**: application
- **User Key**: user account
- **Environment**: Real Portfolio or Virtual Portfolio (real/demo)
**Key generation (user-facing):**
1. Log in to eToro.
2. Settings > Trading.
3. Create New Key.
4. Choose **Environment** (Real or Virtual/Demo) and **Permissions** (Read or Write).
5. Verify identity and copy the generated User Key.
**Headers (every request):**
- `x-request-id`: unique UUID per request
- `x-api-key`: Public API Key (`<PUBLIC_KEY>`)
- `x-user-key`: User Key (`<USER_KEY>`)
Example:-H "x-user-key: <USER_KEY>"
### Choosing the Auth Method in Code
When making requests, check which credentials are available:}
## Request Conventions
- **All paths below are relative to the Base URL** (which already includes `/api/v1`).
Example: `GET /watchlists` means `GET https://public-api.etoro.com/api/v1/watchlists`.
- Query params go in the URL, path params go in the URL path.
- For query params that are documented as `array`, send them as **comma-separated values** (e.g., `instrumentIds=1001,1002`).
- Pagination patterns vary by endpoint:
- Search: `pageNumber`, `pageSize`
- People search & trade history: `page`, `pageSize`
- Feeds: `take`, `offset`
- Watchlist items listing: `pageNumber`, `itemsPerPage`
- **Casing matters** for request bodies:
- Trading execution uses **PascalCase** fields (e.g., `InstrumentID`, `IsBuy`, `Leverage`).
- Market close body uses `InstrumentId` (capital I, lowercase d).
- Watchlist items use `ItemId`, `ItemType`, `ItemRank`.
- Feeds post body uses lower camel (`owner`, `message`, `tags`, `mentions`, `attachments`).
- Some responses may use different casing for similar concepts (e.g., `instrumentId` vs `InstrumentID`). When extracting IDs, handle both if present.
## Demo vs Real Trading
- Use **demo execution endpoints** (contain `/demo/`) for testing and paper trading.
- Use **non-demo execution endpoints** for real trading.
- For portfolio/PnL:
- Demo: `/trading/info/demo/*`
- Real: `/trading/info/portfolio` and `/trading/info/real/pnl`
- Ensure your key environment matches the endpoint (Virtual vs Real). Each User Key is associated with a specific environment.
## Use Defaults
- Important: You don't need to specify all parameters. If the user doesn't specify leverage for example, don't send it on the API request.
## Quick Start (Demo Trade)
1. **Resolve `instrumentId`** using search.
`fields` is required on search requests.}'
> **Note:** The examples above use OAuth (Bearer token). For API key auth, replace the `Authorization` header with `x-api-key` and `x-user-key` headers instead.
## Common IDs
- `instrumentId`: from Search or Instruments metadata
- `positionId`: from Portfolio endpoints
- `orderId`: from execution responses or Portfolio endpoints
- `marketId`: used by instrument feed endpoints (typically available in instrument metadata/search fields)
- `userId`: numeric eToro user ID (often referred to as **CID** in responses; discover via People endpoints/search)
- `watchlistId`: from watchlists list/create endpoints
## Market Data (Requests)
**Search instruments**
- `GET /market-data/search`
- Required query: `fields` (comma-separated list of instrument fields to return)
- Optional: `searchText`, `pageSize`, `pageNumber`, `sort`
- The Search endpoint supports filtering by fields returned in results; for exact symbol lookup, use `internalSymbolFull` as a query param and verify the exact match.
- Recommended minimal `fields` when you need IDs: include the instrument identifier (may appear as `instrumentId` or `InstrumentID`), plus `internalSymbolFull` and `displayname` (and `marketId` if you plan to use Feeds).
**Metadata**
- `GET /market-data/instruments`
Filters: `instrumentIds`, `exchangeIds`, `stocksIndustryIds`, `instrumentTypeIds`.
**Prices & history**
- `GET /market-data/instruments/rates`
Required: `instrumentIds` (comma-separated).
- `GET /market-data/instruments/history/closing-price`
Returns historical closing prices for all instruments (bulk).
- `GET /market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}`
`direction`: `asc` or `desc`. `candlesCount` max 1000.
Use only supported `interval` values (confirm via docs if unsure).
**Reference data**
- `GET /market-data/exchanges` (optional `exchangeIds`)
- `GET /market-data/instrument-types`
- `GET /market-data/stocks-industries` (optional `stocksIndustryIds`)
## Trading Execution (Requests)
> Requires appropriate permissions (typically **Write**) and the correct environment (Demo vs Real).
### Market Open Orders (by amount)
Endpoints:
- `POST /trading/execution/demo/market-open-orders/by-amount`
- `POST /trading/execution/market-open-orders/by-amount`
Body (PascalCase, JSON):
- **Required:** `InstrumentID`, `IsBuy`, `Leverage`, `Amount`
- **Optional:** `StopLossRate`, `TakeProfitRate`, `IsTslEnabled`, `IsNoStopLoss`, `IsNoTakeProfit`
### Market Open Orders (by units)
Endpoints:
- `POST /trading/execution/demo/market-open-orders/by-units`
- `POST /trading/execution/market-open-orders/by-units`
Body (PascalCase, JSON):
- **Required:** `InstrumentID`, `IsBuy`, `Leverage`, `AmountInUnits`
- **Optional:** `StopLossRate`, `TakeProfitRate`, `IsTslEnabled`, `IsNoStopLoss`, `IsNoTakeProfit`
### Cancel Market Open Orders
Endpoints:
- `DELETE /trading/execution/demo/market-open-orders/{orderId}`
- `DELETE /trading/execution/market-open-orders/{orderId}`
### Market Close Orders
Endpoints:
- `POST /trading/execution/demo/market-close-orders/positions/{positionId}`
- `POST /trading/execution/market-close-orders/positions/{positionId}`
- `DELETE /trading/execution/demo/market-close-orders/{orderId}`
- `DELETE /trading/execution/market-close-orders/{orderId}`
Body (JSON):
- **Required:** `InstrumentId`
- **Optional:** `UnitsToDeduct` (number or `null`)
Partial close: set `UnitsToDeduct`.
Full close: set `UnitsToDeduct` to `null`.
You must close by `positionId`, not by symbol.
### Market-if-touched (Limit) Orders
Endpoints:
- `POST /trading/execution/demo/limit-orders`
- `DELETE /trading/execution/demo/limit-orders/{orderId}`
- `POST /trading/execution/limit-orders`
- `DELETE /trading/execution/limit-orders/{orderId}`
Body (PascalCase, JSON):
- **Required:** `InstrumentID`, `IsBuy`, `Leverage`, **`Rate`**, and **one of** `Amount` **or** `AmountInUnits`
- **Optional:** `StopLossRate`, `TakeProfitRate`, `IsTslEnabled`, `IsNoStopLoss`, `IsNoTakeProfit`
- **Do not send:** `IsDiscounted`, `CID`
## Trading Info & Portfolio (Requests)
- `GET /trading/info/demo/pnl`
- `GET /trading/info/real/pnl`
- `GET /trading/info/demo/portfolio`
- `GET /trading/info/portfolio`
Use these to discover `positionId` and `orderId` for close/cancel flows.
- `GET /trading/info/trade/history`
Required: `minDate` (YYYY-MM-DD). Optional: `page`, `pageSize`.
## Watchlists (Requests)
**User watchlists**
- `GET /watchlists`
Optional: `itemsPerPageForSingle`, `ensureBuiltinWatchlists`, `addRelatedAssets`.
- `GET /watchlists/{watchlistId}`
Optional: `pageNumber`, `itemsPerPage`.
- `POST /watchlists`
Query: `name` (required), `type`, `dynamicQuery` (optional). (Uses query params, not a JSON body.)
- `PUT /watchlists/{watchlistId}`
Query: `newName` (required). (Uses query params, not a JSON body.)
- `DELETE /watchlists/{watchlistId}`
**Watchlist items (body schema)**
`WatchlistItemDto` fields:
- `ItemId` (required, int)
- `ItemType` (required, string: `Instrument` or `Person`)
- `ItemRank` (optional, int)
Endpoints:
- `POST /watchlists/{watchlistId}/items`
- `PUT /watchlists/{watchlistId}/items`
- `DELETE /watchlists/{watchlistId}/items`
Example body:]
**Default watchlists**
- `POST /watchlists/default-watchlist/selected-items`
- `GET /watchlists/default-watchlists/items`
Optional: `itemsLimit`, `itemsPerPage`.
- `POST /watchlists/newasdefault-watchlist`
Query: `name` (required), `type`, `dynamicQuery` (optional).
- `PUT /watchlists/setUserSelectedUserDefault/{watchlistId}`
- `PUT /watchlists/rank/{watchlistId}`
Query: `newRank` (required).
**Public watchlists**
- `GET /watchlists/public/{userId}`
- `GET /watchlists/public/{userId}/{watchlistId}`
## Feeds (Requests)
**Read feeds**
- `GET /feeds/instrument/{marketId}`
Optional: `requesterUserId`, `take`, `offset`, `badgesExperimentIsEnabled`, `reactionsPageSize`.
- `GET /feeds/user/{userId}`
Optional: `requesterUserId`, `take`, `offset`, `badgesExperimentIsEnabled`, `reactionsPageSize`.
Notes:
- `marketId` is associated with an instrument (typically available via instrument metadata/search if you include it in `fields`).
- `userId` is a numeric user identifier (CID). If you only have a username, discover the numeric ID via People endpoints (see User Info & Analytics).
**Create post**
- `POST /feeds/post`
- Body fields (lower camel, JSON):
- `owner` (int)
- `message` (string)
- `tags`: `{ "tags": [{ "name": "...", "id": "..." }] }`
- `mentions`: `{ "mentions": [{ "userName": "...", "id": "...", "isD irect": true }] }`
- `attachments`: array of objects with `url`, `title`, `host`, `description`, `mediaType`, and optional `media`.
Minimal example:curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \
-H "x-request-id: <UUID>" \
-H "Authorization: Bearer <access_token>"curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \
-H "x-request-id: <UUID>" \
-H "x-api-key: <PUBLIC_KEY>" \
-H "x-user-key: <USER_KEY>"if (ctx.accessToken) {
// SSO auth — Bearer token from OAuth token exchange
headers["Authorization"] = `Bearer ${ctx.accessToken}`;
} else {
// Manual API key auth
headers["x-api-key"] = ctx.apiKey;
headers["x-user-key"] = ctx.userKey;
}curl -X GET "https://public-api.etoro.com/api/v1/market-data/search?internalSymbolFull=BTC&fields=instrumentId,internalSymbolFull,displayname" \
-H "Authorization: Bearer <access_token>" \
-H "x-request-id: <UUID>"curl -X POST "https://public-api.etoro.com/api/v1/trading/execution/demo/market-open-orders/by-amount" \
-H "Authorization: Bearer <access_token>" \
-H "x-request-id: <UUID>" \
-H "Content-Type: application/json" \
-d '{
"InstrumentID": 100000,
"IsBuy": true,
"Leverage": 1,
"Amount": 100
}'Tags
Quick Info
Ready to Install?
Get started with this skill in seconds
Related Skills
4claw
4claw — a moderated imageboard for AI agents.
Aap Passport
Agent Attestation Protocol - The Reverse Turing Test.
Adaptive Suite
A continuously adaptive skill suite that empowers Clawdbot.
Adversarial Prompting
Adversarial analysis to critique, fix.