Install
openclaw skills install etoro-appsClawHub Security found sensitive or high-impact capabilities. Review the scan results before using.
Enables agents to interact with the eToro API to access market data, portfolio and social features, and execute trades programmatically. Supports both OAuth SSO and manual API key authentication.
openclaw skills install etoro-appsBase URL: https://public-api.etoro.com/api/v1
This skill allows to interact with the user's eToro account programatically, including executing trades.
The eToro API supports two authentication methods. Both use the same base URL and endpoints — only the auth headers differ.
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>Where access_token comes from:
https://www.etoro.com/sso/ with PKCE challenge.code.POST https://www.etoro.com/sso/oidc/token:
grant_type=authorization_codecode=<auth_code>redirect_uri=<callback_url>code_verifier=<pkce_verifier>Authorization: Basic <base64(client_id:client_secret)> headeraccess_token — this is the Bearer token for API calls (~2130 chars, JWT)id_token — JWT with user identity (sub claim = 128-char encoded user ID)token_type: "Bearer"expires_in: (varies)Example:
curl -X GET "https://public-api.etoro.com/api/v1/watchlists" \
-H "x-request-id: <UUID>" \
-H "Authorization: Bearer <access_token>"
If the user provides API keys manually (no OAuth), use key-based auth.
Keys (request from the user on install)
Key generation (user-facing):
Headers (every request):
x-request-id: unique UUID per requestx-api-key: Public API Key (<PUBLIC_KEY>)x-user-key: User Key (<USER_KEY>)Example:
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>"
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;
}
/api/v1).GET /watchlists means GET https://public-api.etoro.com/api/v1/watchlists.array, send them as comma-separated values (e.g., instrumentIds=1001,1002).pageNumber, pageSizepage, pageSizetake, offsetpageNumber, itemsPerPageInstrumentID, IsBuy, Leverage).InstrumentId (capital I, lowercase d).ItemId, ItemType, ItemRank.owner, message, tags, mentions, attachments).instrumentId vs InstrumentID). When extracting IDs, handle both if present./demo/) for testing and paper trading./trading/info/demo/*/trading/info/portfolio and /trading/info/real/pnlinstrumentId using 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>"
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 the
Authorizationheader withx-api-keyandx-user-keyheaders instead.
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 endpointsSearch instruments
GET /market-data/searchfields (comma-separated list of instrument fields to return)searchText, pageSize, pageNumber, sortinternalSymbolFull as a query param and verify the exact match.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/instrumentsinstrumentIds, exchangeIds, stocksIndustryIds, instrumentTypeIds.Prices & history
GET /market-data/instruments/ratesinstrumentIds (comma-separated).GET /market-data/instruments/history/closing-priceGET /market-data/instruments/{instrumentId}/history/candles/{direction}/{interval}/{candlesCount}direction: asc or desc. candlesCount max 1000.interval values (confirm via docs if unsure).Reference data
GET /market-data/exchanges (optional exchangeIds)GET /market-data/instrument-typesGET /market-data/stocks-industries (optional stocksIndustryIds)Requires appropriate permissions (typically Write) and the correct environment (Demo vs Real).
Endpoints:
POST /trading/execution/demo/market-open-orders/by-amountPOST /trading/execution/market-open-orders/by-amountBody (PascalCase, JSON):
InstrumentID, IsBuy, Leverage, AmountStopLossRate, TakeProfitRate, IsTslEnabled, IsNoStopLoss, IsNoTakeProfitEndpoints:
POST /trading/execution/demo/market-open-orders/by-unitsPOST /trading/execution/market-open-orders/by-unitsBody (PascalCase, JSON):
InstrumentID, IsBuy, Leverage, AmountInUnitsStopLossRate, TakeProfitRate, IsTslEnabled, IsNoStopLoss, IsNoTakeProfitEndpoints:
DELETE /trading/execution/demo/market-open-orders/{orderId}DELETE /trading/execution/market-open-orders/{orderId}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):
InstrumentIdUnitsToDeduct (number or null)Partial close: set UnitsToDeduct.
Full close: set UnitsToDeduct to null.
You must close by positionId, not by symbol.
Endpoints:
POST /trading/execution/demo/limit-ordersDELETE /trading/execution/demo/limit-orders/{orderId}POST /trading/execution/limit-ordersDELETE /trading/execution/limit-orders/{orderId}Body (PascalCase, JSON):
InstrumentID, IsBuy, Leverage, Rate, and one of Amount or AmountInUnitsStopLossRate, TakeProfitRate, IsTslEnabled, IsNoStopLoss, IsNoTakeProfitIsDiscounted, CIDGET /trading/info/demo/pnlGET /trading/info/real/pnlGET /trading/info/demo/portfolioGET /trading/info/portfoliopositionId and orderId for close/cancel flows.GET /trading/info/trade/historyminDate (YYYY-MM-DD). Optional: page, pageSize.User watchlists
GET /watchlistsitemsPerPageForSingle, ensureBuiltinWatchlists, addRelatedAssets.GET /watchlists/{watchlistId}pageNumber, itemsPerPage.POST /watchlistsname (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}Watchlist items (body schema)
WatchlistItemDto fields:
ItemId (required, int)ItemType (required, string: Instrument or Person)ItemRank (optional, int)Endpoints:
POST /watchlists/{watchlistId}/itemsPUT /watchlists/{watchlistId}/itemsDELETE /watchlists/{watchlistId}/itemsExample body:
[
{ "ItemId": 12345, "ItemType": "Instrument", "ItemRank": 1 },
{ "ItemId": 67890, "ItemType": "Instrument", "ItemRank": 2 }
]
Default watchlists
POST /watchlists/default-watchlist/selected-itemsGET /watchlists/default-watchlists/itemsitemsLimit, itemsPerPage.POST /watchlists/newasdefault-watchlistname (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}Read feeds
GET /feeds/instrument/{marketId}requesterUserId, take, offset, badgesExperimentIsEnabled, reactionsPageSize.GET /feeds/user/{userId}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/postowner (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:
{ "message": "Hello eToro feed!" }
GET /curated-listsGET /market-recommendations/{itemsCount}GET /pi-data/copiersGET /user-info/peopleusernames, cidList.userId for feeds/public watchlists.GET /user-info/people/searchperiod. 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-gainminDate, maxDate, type (Daily or Period).GET /user-info/people/{username}/portfolio/liveGET /user-info/people/{username}/tradeinfoperiod (e.g., LastTwoYears).For response schemas and full examples, refer to:
https://api-portal.etoro.com/mcp