Requirements
- Target platform
- OpenClaw
- Install method
- Manual import
- Extraction
- Extract archive
- Prerequisites
- OpenClaw
- Primary doc
- SKILL.md
Enables agents to interact with the eToro API to access market data, portfolio and social features, and execute trades programmatically. Supports both OAuth...
Enables agents to interact with the eToro API to access market data, portfolio and social features, and execute trades programmatically. Supports both OAuth...
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
Base 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 request Authorization: Bearer <access_token> Where 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_code code=<auth_code> redirect_uri=<callback_url> code_verifier=<pkce_verifier> Plus Authorization: Basic <base64(client_id:client_secret)> header Response contains: access_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) Public API Key: application User Key: user account Environment: Real Portfolio or Virtual Portfolio (real/demo) Key generation (user-facing): 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. 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: 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; }
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.
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.
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.
Resolve instrumentId 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>" 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 the Authorization header with x-api-key and x-user-key headers instead.
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
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)
Requires appropriate permissions (typically Write) and the correct environment (Demo vs Real).
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
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
Endpoints: 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): 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.
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
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.
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: [ { "ItemId": 12345, "ItemType": "Instrument", "ItemRank": 1 }, { "ItemId": 67890, "ItemType": "Instrument", "ItemRank": 2 } ] 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}
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: { "message": "Hello eToro feed!" }
GET /curated-lists GET /market-recommendations/{itemsCount}
GET /pi-data/copiers
GET /user-info/people Optional: usernames, cidList. Use this to map username โ CID (userId) when you need numeric userId for feeds/public watchlists. GET /user-info/people/search Required: 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}/gain GET /user-info/people/{username}/daily-gain Required: minDate, maxDate, type (Daily or Period). GET /user-info/people/{username}/portfolio/live GET /user-info/people/{username}/tradeinfo Required: period (e.g., LastTwoYears).
For response schemas and full examples, refer to: https://api-portal.etoro.com/ MCP server: https://api-portal.etoro.com/mcp
Code helpers, APIs, CLIs, browser automation, testing, and developer operations.
Largest current source with strong distribution and engagement signals.